Make the node graph use a document node's default type (#1965)
* Use document node default type * Refactor getting input * Clippy * Fix missing continue * Fix CI
This commit is contained in:
parent
507210b961
commit
514582fd8d
|
|
@ -24,8 +24,10 @@ jobs:
|
||||||
override: true
|
override: true
|
||||||
components: clippy
|
components: clippy
|
||||||
|
|
||||||
- name: Install Deps
|
- name: Install deps
|
||||||
run: sudo apt-get install libgtk-3-dev libsoup2.4-dev libjavascriptcoregtk-4.0-dev libwebkit2gtk-4.0-dev
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install libgtk-3-dev libsoup2.4-dev libjavascriptcoregtk-4.0-dev libwebkit2gtk-4.0-dev
|
||||||
|
|
||||||
- name: Run Clippy
|
- name: Run Clippy
|
||||||
id: clippy
|
id: clippy
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
|
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
|
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, NodeTemplate, OutputConnector, Previewing};
|
use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, NodeTemplate, OutputConnector, Previewing, TypeSource};
|
||||||
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
|
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||||
|
|
@ -181,7 +181,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
.find(|(_, input)| input.is_exposed_to_frontend(selection_network_path.is_empty()))
|
.find(|(_, input)| input.is_exposed_to_frontend(selection_network_path.is_empty()))
|
||||||
{
|
{
|
||||||
responses.add(NodeGraphMessage::CreateWire {
|
responses.add(NodeGraphMessage::CreateWire {
|
||||||
output_connector: output_connector.clone(),
|
output_connector: *output_connector,
|
||||||
input_connector: InputConnector::node(node_id, input_index),
|
input_connector: InputConnector::node(node_id, input_index),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -481,7 +481,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
if let Some(clicked_input) = &clicked_input {
|
if let Some(clicked_input) = &clicked_input {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
self.initial_disconnecting = true;
|
self.initial_disconnecting = true;
|
||||||
self.disconnecting = Some(clicked_input.clone());
|
self.disconnecting = Some(*clicked_input);
|
||||||
|
|
||||||
let output_connector = if *clicked_input == InputConnector::Export(0) {
|
let output_connector = if *clicked_input == InputConnector::Export(0) {
|
||||||
network_interface.root_node(selection_network_path).map(|root_node| root_node.to_connector())
|
network_interface.root_node(selection_network_path).map(|root_node| root_node.to_connector())
|
||||||
|
|
@ -615,9 +615,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
if disconnect_root_node {
|
if disconnect_root_node {
|
||||||
responses.add(NodeGraphMessage::DisconnectRootNode);
|
responses.add(NodeGraphMessage::DisconnectRootNode);
|
||||||
} else {
|
} else {
|
||||||
responses.add(NodeGraphMessage::DisconnectInput {
|
responses.add(NodeGraphMessage::DisconnectInput { input_connector: *disconnecting });
|
||||||
input_connector: disconnecting.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// Update the frontend that the node is disconnected
|
// Update the frontend that the node is disconnected
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
|
|
@ -781,8 +779,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
|
|
||||||
if let (Some(output_connector), Some(input_connector)) = (&output_connector, &input_connector) {
|
if let (Some(output_connector), Some(input_connector)) = (&output_connector, &input_connector) {
|
||||||
responses.add(NodeGraphMessage::CreateWire {
|
responses.add(NodeGraphMessage::CreateWire {
|
||||||
input_connector: input_connector.clone(),
|
input_connector: *input_connector,
|
||||||
output_connector: output_connector.clone(),
|
output_connector: *output_connector,
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
|
|
@ -972,7 +970,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
{
|
{
|
||||||
responses.add(NodeGraphMessage::InsertNodeBetween {
|
responses.add(NodeGraphMessage::InsertNodeBetween {
|
||||||
node_id: selected_node_id,
|
node_id: selected_node_id,
|
||||||
input_connector: overlapping_wire.wire_end.clone(),
|
input_connector: overlapping_wire.wire_end,
|
||||||
insert_node_input_index: selected_node_input_index,
|
insert_node_input_index: selected_node_input_index,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1650,6 +1648,7 @@ impl NodeGraphMessageHandler {
|
||||||
log::error!("Could not get nested network when collecting nodes");
|
log::error!("Could not get nested network when collecting nodes");
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
for node_id in network.nodes.keys().cloned().collect::<Vec<_>>() {
|
for node_id in network.nodes.keys().cloned().collect::<Vec<_>>() {
|
||||||
if network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path) {
|
if network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path) {
|
||||||
can_be_layer_lookup.insert(node_id);
|
can_be_layer_lookup.insert(node_id);
|
||||||
|
|
@ -1660,6 +1659,7 @@ impl NodeGraphMessageHandler {
|
||||||
log::error!("Could not get position for node {node_id}");
|
log::error!("Could not get position for node {node_id}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut frontend_inputs_lookup = frontend_inputs_lookup(breadcrumb_network_path, network_interface);
|
||||||
let Some(network) = network_interface.network(breadcrumb_network_path) else {
|
let Some(network) = network_interface.network(breadcrumb_network_path) else {
|
||||||
log::error!("Could not get nested network when collecting nodes");
|
log::error!("Could not get nested network when collecting nodes");
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
|
|
@ -1671,63 +1671,24 @@ impl NodeGraphMessageHandler {
|
||||||
|
|
||||||
let mut nodes = Vec::new();
|
let mut nodes = Vec::new();
|
||||||
for (&node_id, node) in &network.nodes {
|
for (&node_id, node) in &network.nodes {
|
||||||
let node_id_path = &[breadcrumb_network_path, (&[node_id])].concat();
|
let node_id_path = [breadcrumb_network_path, (&[node_id])].concat();
|
||||||
let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(&node_id) else {
|
|
||||||
log::error!("Could not get node_metadata for {node_id_path:?}");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let frontend_graph_inputs = node.inputs.iter().enumerate().map(|(index, _)| {
|
let inputs = frontend_inputs_lookup.remove(&node_id).unwrap_or_default();
|
||||||
// Convert the index in all inputs to the index in only the exposed inputs
|
let mut inputs = inputs.into_iter().map(|input| {
|
||||||
// TODO: Only display input type if potential inputs in node_registry are all the same type
|
input.map(|input| FrontendGraphInput {
|
||||||
let node_type = network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path);
|
data_type: FrontendGraphDataType::with_type(&input.ty),
|
||||||
// TODO: Should display the color of the "most commonly relevant" (we'd need some sort of precedence) data type it allows given the current generic form that's constrained by the other present connections.
|
resolved_type: Some(format!("{:?} from {:?}", &input.ty, input.type_source)),
|
||||||
let data_type = FrontendGraphDataType::with_type(&node_type);
|
name: input.name.unwrap_or_else(|| input.ty.nested_type().to_string()),
|
||||||
|
connected_to: input.output_connector,
|
||||||
let input_name = node_metadata
|
|
||||||
.persistent_metadata
|
|
||||||
.input_names
|
|
||||||
.get(index)
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or(network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path).nested_type().to_string());
|
|
||||||
|
|
||||||
FrontendGraphInput {
|
|
||||||
data_type,
|
|
||||||
name: input_name,
|
|
||||||
resolved_type: Some(format!("{:?}", node_type)),
|
|
||||||
connected_to: None,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut inputs = node.inputs.iter().zip(frontend_graph_inputs).map(|(node_input, mut frontend_graph_input)| {
|
|
||||||
if let NodeInput::Node {
|
|
||||||
node_id: connected_node_id,
|
|
||||||
output_index,
|
|
||||||
..
|
|
||||||
} = node_input
|
|
||||||
{
|
|
||||||
frontend_graph_input.connected_to = Some(OutputConnector::node(*connected_node_id, *output_index));
|
|
||||||
} else if let NodeInput::Network { import_index, .. } = node_input {
|
|
||||||
frontend_graph_input.connected_to = Some(OutputConnector::Import(*import_index));
|
|
||||||
}
|
|
||||||
(node_input, frontend_graph_input)
|
|
||||||
});
|
|
||||||
|
|
||||||
let primary_input = inputs
|
|
||||||
.next()
|
|
||||||
.filter(|(input, _)| {
|
|
||||||
// Don't show EditorApi input to nodes like "Text" in the document network
|
|
||||||
input.is_exposed_to_frontend(breadcrumb_network_path.is_empty())
|
|
||||||
})
|
})
|
||||||
.map(|(_, input_type)| input_type);
|
});
|
||||||
let exposed_inputs = inputs
|
|
||||||
.filter(|(input, _)| input.is_exposed_to_frontend(breadcrumb_network_path.is_empty()))
|
let primary_input = inputs.next().flatten();
|
||||||
.map(|(_, input_type)| input_type)
|
let exposed_inputs = inputs.flatten().collect();
|
||||||
.collect();
|
|
||||||
|
|
||||||
let output_types = network_interface.output_types(&node_id, breadcrumb_network_path);
|
let output_types = network_interface.output_types(&node_id, breadcrumb_network_path);
|
||||||
let primary_output_type = output_types.first().expect("Primary output should always exist");
|
let primary_output_type = output_types.first().expect("Primary output should always exist");
|
||||||
let frontend_data_type = if let Some(output_type) = primary_output_type {
|
let frontend_data_type = if let Some((output_type, _)) = primary_output_type {
|
||||||
FrontendGraphDataType::with_type(output_type)
|
FrontendGraphDataType::with_type(output_type)
|
||||||
} else {
|
} else {
|
||||||
FrontendGraphDataType::General
|
FrontendGraphDataType::General
|
||||||
|
|
@ -1737,7 +1698,7 @@ impl NodeGraphMessageHandler {
|
||||||
Some(FrontendGraphOutput {
|
Some(FrontendGraphOutput {
|
||||||
data_type: frontend_data_type,
|
data_type: frontend_data_type,
|
||||||
name: "Output 1".to_string(),
|
name: "Output 1".to_string(),
|
||||||
resolved_type: primary_output_type.clone().map(|input| format!("{input:?}")),
|
resolved_type: primary_output_type.clone().map(|(input, type_source)| format!("{input:?} from {type_source:?}")),
|
||||||
connected_to,
|
connected_to,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1749,7 +1710,7 @@ impl NodeGraphMessageHandler {
|
||||||
if index == 0 && network_interface.has_primary_output(&node_id, breadcrumb_network_path) {
|
if index == 0 && network_interface.has_primary_output(&node_id, breadcrumb_network_path) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let frontend_data_type = if let Some(output_type) = &exposed_output {
|
let frontend_data_type = if let Some((output_type, _)) = &exposed_output {
|
||||||
FrontendGraphDataType::with_type(output_type)
|
FrontendGraphDataType::with_type(output_type)
|
||||||
} else {
|
} else {
|
||||||
FrontendGraphDataType::General
|
FrontendGraphDataType::General
|
||||||
|
|
@ -1769,7 +1730,7 @@ impl NodeGraphMessageHandler {
|
||||||
exposed_outputs.push(FrontendGraphOutput {
|
exposed_outputs.push(FrontendGraphOutput {
|
||||||
data_type: frontend_data_type,
|
data_type: frontend_data_type,
|
||||||
name: output_name,
|
name: output_name,
|
||||||
resolved_type: exposed_output.clone().map(|input| format!("{input:?}")),
|
resolved_type: exposed_output.clone().map(|(input, type_source)| format!("{input:?} from {type_source:?}")),
|
||||||
connected_to,
|
connected_to,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1791,10 +1752,10 @@ impl NodeGraphMessageHandler {
|
||||||
let errors = self
|
let errors = self
|
||||||
.node_graph_errors
|
.node_graph_errors
|
||||||
.iter()
|
.iter()
|
||||||
.find(|error| error.node_path == *node_id_path)
|
.find(|error| error.node_path == node_id_path)
|
||||||
.map(|error| format!("{:?}", error.error.clone()))
|
.map(|error| format!("{:?}", error.error.clone()))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if self.node_graph_errors.iter().any(|error| error.node_path.starts_with(node_id_path)) {
|
if self.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) {
|
||||||
Some("Node graph type error within this node".to_string())
|
Some("Node graph type error within this node".to_string())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -1985,6 +1946,64 @@ impl NodeGraphMessageHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct InputLookup {
|
||||||
|
name: Option<String>,
|
||||||
|
ty: Type,
|
||||||
|
type_source: TypeSource,
|
||||||
|
output_connector: Option<OutputConnector>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type FrontendInputsLookup = HashMap<NodeId, Vec<Option<InputLookup>>>;
|
||||||
|
|
||||||
|
/// Create a lookup hashmap that can be used to create the frontend inputs. This is needed because `input_type` requires a mutable `network_interface`.
|
||||||
|
fn frontend_inputs_lookup(breadcrumb_network_path: &[NodeId], network_interface: &mut NodeNetworkInterface) -> FrontendInputsLookup {
|
||||||
|
let Some(network) = network_interface.network(breadcrumb_network_path) else {
|
||||||
|
return Default::default();
|
||||||
|
};
|
||||||
|
let network_metadata = network_interface.network_metadata(breadcrumb_network_path);
|
||||||
|
let mut frontend_inputs_lookup = HashMap::new();
|
||||||
|
for (&node_id, node) in network.nodes.iter() {
|
||||||
|
let node_metadata = network_metadata.and_then(|network_metadata| network_metadata.persistent_metadata.node_metadata.get(&node_id));
|
||||||
|
let mut inputs = Vec::with_capacity(node.inputs.len());
|
||||||
|
for (index, input) in node.inputs.iter().enumerate() {
|
||||||
|
let is_exposed = input.is_exposed_to_frontend(breadcrumb_network_path.is_empty());
|
||||||
|
|
||||||
|
// Skip not exposed inputs (they still get an entry to help with finding the primary input)
|
||||||
|
if !is_exposed {
|
||||||
|
inputs.push(None);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the name from the metadata here (since it also requires a reference to the `network_interface`)
|
||||||
|
let name = node_metadata.and_then(|node_metadata| node_metadata.persistent_metadata.input_names.get(index)).cloned();
|
||||||
|
|
||||||
|
// Get the output connector that feeds into this input (done here as well for simplicity)
|
||||||
|
let connector = OutputConnector::from_input(input);
|
||||||
|
|
||||||
|
inputs.push(Some(InputLookup {
|
||||||
|
name,
|
||||||
|
output_connector: connector,
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
frontend_inputs_lookup.insert(node_id, inputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (&node_id, value) in frontend_inputs_lookup.iter_mut() {
|
||||||
|
for (index, value) in value.iter_mut().enumerate() {
|
||||||
|
// Skip not exposed inputs for efficiency
|
||||||
|
let Some(value) = value else { continue };
|
||||||
|
|
||||||
|
// Resolve the type (done in a seperate loop because it requires a mutable reference to the `network_interface`)
|
||||||
|
let (ty, type_source) = network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path);
|
||||||
|
value.ty = ty;
|
||||||
|
value.type_source = type_source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frontend_inputs_lookup
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for NodeGraphMessageHandler {
|
impl Default for NodeGraphMessageHandler {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let right_side_widgets = vec![
|
let right_side_widgets = vec![
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use super::misc::PTZ;
|
||||||
use super::nodes::SelectedNodes;
|
use super::nodes::SelectedNodes;
|
||||||
use crate::consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP};
|
use crate::consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP};
|
||||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||||
|
use crate::messages::portfolio::document::node_graph::document_node_definitions::{resolve_document_node_type, DocumentNodeDefinition};
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets, FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput};
|
use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets, FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
|
|
||||||
|
|
@ -170,7 +171,7 @@ impl NodeNetworkInterface {
|
||||||
layers
|
layers
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chain_width(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> u32 {
|
pub fn chain_width(&self, node_id: &NodeId, network_path: &[NodeId]) -> u32 {
|
||||||
if self.number_of_inputs(node_id, network_path) > 1 {
|
if self.number_of_inputs(node_id, network_path) > 1 {
|
||||||
let mut last_chain_node_distance = 0u32;
|
let mut last_chain_node_distance = 0u32;
|
||||||
// Iterate upstream from the layer, and get the number of nodes distance to the last node with Position::Chain
|
// Iterate upstream from the layer, and get the number of nodes distance to the last node with Position::Chain
|
||||||
|
|
@ -413,7 +414,7 @@ impl NodeNetworkInterface {
|
||||||
/// Converts all node id inputs to a new id based on a HashMap.
|
/// Converts all node id inputs to a new id based on a HashMap.
|
||||||
///
|
///
|
||||||
/// If the node is not in the hashmap then a default input is found based on the compiled network, using the node_id passed as a parameter
|
/// If the node is not in the hashmap then a default input is found based on the compiled network, using the node_id passed as a parameter
|
||||||
pub fn map_ids(&self, mut node_template: NodeTemplate, node_id: &NodeId, new_ids: &HashMap<NodeId, NodeId>, network_path: &[NodeId]) -> NodeTemplate {
|
pub fn map_ids(&mut self, mut node_template: NodeTemplate, node_id: &NodeId, new_ids: &HashMap<NodeId, NodeId>, network_path: &[NodeId]) -> NodeTemplate {
|
||||||
for (input_index, input) in node_template.document_node.inputs.iter_mut().enumerate() {
|
for (input_index, input) in node_template.document_node.inputs.iter_mut().enumerate() {
|
||||||
if let &mut NodeInput::Node { node_id: id, output_index, lambda } = input {
|
if let &mut NodeInput::Node { node_id: id, output_index, lambda } = input {
|
||||||
if let Some(&new_id) = new_ids.get(&id) {
|
if let Some(&new_id) = new_ids.get(&id) {
|
||||||
|
|
@ -424,12 +425,12 @@ impl NodeNetworkInterface {
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// Disconnect node input if it is not connected to another node in new_ids
|
// Disconnect node input if it is not connected to another node in new_ids
|
||||||
let tagged_value = TaggedValue::from_type(&self.input_type(&InputConnector::node(*node_id, input_index), network_path));
|
let tagged_value = TaggedValue::from_type(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0);
|
||||||
*input = NodeInput::value(tagged_value, true);
|
*input = NodeInput::value(tagged_value, true);
|
||||||
}
|
}
|
||||||
} else if let &mut NodeInput::Network { .. } = input {
|
} else if let &mut NodeInput::Network { .. } = input {
|
||||||
// Always disconnect network node input
|
// Always disconnect network node input
|
||||||
let tagged_value = TaggedValue::from_type(&self.input_type(&InputConnector::node(*node_id, input_index), network_path));
|
let tagged_value = TaggedValue::from_type(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0);
|
||||||
*input = NodeInput::value(tagged_value, true);
|
*input = NodeInput::value(tagged_value, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -453,39 +454,59 @@ impl NodeNetworkInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the [`Type`] for any InputConnector
|
/// Try and get the [`DocumentNodeDefinition`] for a node
|
||||||
pub fn input_type(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Type {
|
pub fn get_node_definition(&self, network_path: &[NodeId], node_id: NodeId) -> Option<&DocumentNodeDefinition> {
|
||||||
// TODO: If the input_connector is a NodeInput::Value, return the type of the tagged value
|
let metadata = self.node_metadata(&node_id, network_path)?;
|
||||||
let node_type_from_compiled_network = if let Some(node_id) = input_connector.node_id() {
|
resolve_document_node_type(metadata.persistent_metadata.reference.as_ref()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try and get the [`Type`] for any [`InputConnector`] based on the `self.resolved_types`.
|
||||||
|
fn node_type_from_compiled(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<(Type, TypeSource)> {
|
||||||
|
let (node_id, input_index) = match *input_connector {
|
||||||
|
InputConnector::Node { node_id, input_index } => (node_id, input_index),
|
||||||
|
InputConnector::Export(export_index) => {
|
||||||
|
let Some((encapsulating_node_id, encapsulating_node_id_path)) = network_path.split_last() else {
|
||||||
|
// The outermost network export defaults to an ArtboardGroup.
|
||||||
|
return Some((concrete!(graphene_core::ArtboardGroup), TypeSource::OuterMostExportDefault));
|
||||||
|
};
|
||||||
|
|
||||||
|
let output_type = self.output_types(encapsulating_node_id, encapsulating_node_id_path).into_iter().nth(export_index).flatten();
|
||||||
|
if output_type.is_none() {
|
||||||
|
warn!("Could not find output type for export node");
|
||||||
|
}
|
||||||
|
return output_type;
|
||||||
|
}
|
||||||
|
};
|
||||||
let Some(current_network) = self.network(network_path) else {
|
let Some(current_network) = self.network(network_path) else {
|
||||||
log::error!("Could not get current network in input_type");
|
log::error!("Could not get current network in input_type");
|
||||||
return concrete!(());
|
return None;
|
||||||
};
|
};
|
||||||
let Some(node) = current_network.nodes.get(&node_id) else {
|
let Some(node) = current_network.nodes.get(&node_id) else {
|
||||||
log::error!("Could not get node {node_id} in input_type");
|
log::error!("Could not get node {node_id} in input_type");
|
||||||
return concrete!(());
|
return None;
|
||||||
};
|
};
|
||||||
|
// If the input_connector is a NodeInput::Value, return the type of the tagged value.
|
||||||
|
if let Some(value) = node.inputs.get(input_index).and_then(|input| input.as_value()) {
|
||||||
|
return Some((value.ty(), TypeSource::TaggedValue));
|
||||||
|
}
|
||||||
let node_id_path = [network_path, &[node_id]].concat().clone();
|
let node_id_path = [network_path, &[node_id]].concat().clone();
|
||||||
match &node.implementation {
|
match &node.implementation {
|
||||||
DocumentNodeImplementation::Network(nested_network) => {
|
DocumentNodeImplementation::Network(_nested_network) => {
|
||||||
let downstream_connection = nested_network
|
// Attempt to resolve where this import is within the nested network (it may be connected to the node or directly to an export)
|
||||||
.nodes
|
let outwards_wires = self.outward_wires(network_path);
|
||||||
.iter()
|
let inputs_using_import = outwards_wires.and_then(|outwards_wires| outwards_wires.get(&OutputConnector::Import(input_index)));
|
||||||
.flat_map(|(node_id, node)| node.inputs.iter().enumerate().map(|(input_index, input)| (InputConnector::node(*node_id, input_index), input)))
|
let first_input = inputs_using_import.and_then(|input| input.first()).copied();
|
||||||
.chain(nested_network.exports.iter().enumerate().map(|(export_index, export)| (InputConnector::Export(export_index), export)))
|
|
||||||
.find(|(_, input)| {
|
if inputs_using_import.is_some_and(|inputs| inputs.len() > 1) {
|
||||||
if let NodeInput::Network { import_index, .. } = input {
|
warn!("Found multiple inputs using an import. Using the type of the first one.");
|
||||||
*import_index == input_connector.input_index()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if let Some((input_connector, _)) = downstream_connection {
|
if let Some(input_connector) = first_input {
|
||||||
Some(self.input_type(&input_connector, &node_id_path))
|
self.node_type_from_compiled(&input_connector, &node_id_path)
|
||||||
}
|
}
|
||||||
// Nothing is connected to the import
|
// Nothing is connected to the import
|
||||||
else {
|
else {
|
||||||
Some(concrete!(()))
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentNodeImplementation::ProtoNode(_) => {
|
DocumentNodeImplementation::ProtoNode(_) => {
|
||||||
|
|
@ -494,73 +515,86 @@ impl NodeNetworkInterface {
|
||||||
self.resolved_types
|
self.resolved_types
|
||||||
.types
|
.types
|
||||||
.get(node_id_path.as_slice())
|
.get(node_id_path.as_slice())
|
||||||
.map(|node_types| node_types.inputs[input_connector.input_index() + manual_composition_offset].clone())
|
.and_then(|node_types| node_types.inputs.get(input_index + manual_composition_offset).cloned())
|
||||||
|
.map(|node_types| (node_types, TypeSource::Compiled))
|
||||||
|
}
|
||||||
|
DocumentNodeImplementation::Extract => None,
|
||||||
}
|
}
|
||||||
DocumentNodeImplementation::Extract => Some(concrete!(())),
|
|
||||||
}
|
}
|
||||||
} else if let Some(encapsulating_node_id) = network_path.last() {
|
|
||||||
let mut encapsulating_node_id_path = network_path.to_vec();
|
|
||||||
encapsulating_node_id_path.pop();
|
|
||||||
let output_types: Vec<Option<Type>> = self.output_types(encapsulating_node_id, &encapsulating_node_id_path);
|
|
||||||
output_types.get(input_connector.input_index()).map_or_else(
|
|
||||||
|| {
|
|
||||||
warn!("Could not find output type for export node");
|
|
||||||
Some(concrete!(()))
|
|
||||||
},
|
|
||||||
|output_type| output_type.clone().map_or(Some(concrete!(())), Some),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Some(concrete!(graphene_core::ArtboardGroup))
|
|
||||||
};
|
|
||||||
|
|
||||||
node_type_from_compiled_network.unwrap_or_else(|| {
|
/// Guess the type from the node based on a document node default or a random protonode definition.
|
||||||
// TODO: Once there is type inference (#1621), replace this workaround approach when disconnecting node inputs with NodeInput::Node(ToDefaultNode),
|
fn guess_type_from_node(&mut self, network_path: &mut Vec<NodeId>, node_id: NodeId, input_index: usize) -> (Type, TypeSource) {
|
||||||
// TODO: which would be a new node that implements the Default trait (i.e. `Default::default()`)
|
// Try and get the default value from the document node definition
|
||||||
|
if let Some(value) = self
|
||||||
|
.get_node_definition(network_path, node_id)
|
||||||
|
.and_then(|definition| definition.node_template.document_node.inputs.get(input_index))
|
||||||
|
.and_then(|input| input.as_value())
|
||||||
|
{
|
||||||
|
return (value.ty(), TypeSource::DocumentNodeDefault);
|
||||||
|
}
|
||||||
|
|
||||||
let Some(network) = self.network(network_path) else {
|
let Some(network) = self.network(network_path) else {
|
||||||
log::error!("Could not get network in input_type");
|
log::error!("Could not get network in input_type");
|
||||||
return concrete!(());
|
return (concrete!(()), TypeSource::Error("could not get network"));
|
||||||
};
|
};
|
||||||
// Resolve types from proto nodes in node_registry
|
|
||||||
let Some(node_id) = input_connector.node_id() else {
|
let Some(node) = network.nodes.get(&node_id) else {
|
||||||
return concrete!(());
|
return (concrete!(()), TypeSource::Error("node id not in network"));
|
||||||
};
|
|
||||||
let Some(node) = network.nodes.get(&node_id) else {
|
|
||||||
return concrete!(());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn type_from_node(node: &DocumentNode, input_index: usize) -> Type {
|
|
||||||
match &node.implementation {
|
match &node.implementation {
|
||||||
DocumentNodeImplementation::ProtoNode(protonode) => {
|
DocumentNodeImplementation::ProtoNode(protonode) => {
|
||||||
let Some(node_types) = proto_node_type(protonode) else { return concrete!(()) };
|
let Some(node_types) = random_protonode_implementation(protonode) else {
|
||||||
|
return (concrete!(()), TypeSource::Error("could not resolve protonode"));
|
||||||
|
};
|
||||||
|
|
||||||
let skip_footprint = if node.manual_composition.is_some() { 1 } else { 0 };
|
let skip_footprint = if node.manual_composition.is_some() { 1 } else { 0 };
|
||||||
|
|
||||||
let Some(input_type) = std::iter::once(node_types.input.clone()).chain(node_types.parameters.clone()).nth(input_index + skip_footprint) else {
|
let Some(input_type) = std::iter::once(node_types.input.clone()).chain(node_types.parameters.clone()).nth(input_index + skip_footprint) else {
|
||||||
log::error!("Could not get type");
|
log::error!("Could not get type");
|
||||||
return concrete!(());
|
return (concrete!(()), TypeSource::Error("could not get the protonode's input"));
|
||||||
};
|
};
|
||||||
|
|
||||||
input_type
|
(input_type, TypeSource::RandomProtonodeImplementation)
|
||||||
}
|
|
||||||
DocumentNodeImplementation::Network(network) => {
|
|
||||||
for node in &network.nodes {
|
|
||||||
for (network_node_input_index, input) in node.1.inputs.iter().enumerate() {
|
|
||||||
if let NodeInput::Network { import_index, .. } = input {
|
|
||||||
if *import_index == input_index {
|
|
||||||
return type_from_node(node.1, network_node_input_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
DocumentNodeImplementation::Network(_network) => {
|
||||||
|
// Attempt to resolve where this import is within the nested network
|
||||||
|
let outwards_wires = self.outward_wires(network_path);
|
||||||
|
let inputs_using_import = outwards_wires.and_then(|outwards_wires| outwards_wires.get(&OutputConnector::Import(input_index)));
|
||||||
|
let first_input = inputs_using_import.and_then(|input| input.first()).copied();
|
||||||
|
|
||||||
|
if let Some(InputConnector::Node {
|
||||||
|
node_id: child_id,
|
||||||
|
input_index: child_input_index,
|
||||||
|
}) = first_input
|
||||||
|
{
|
||||||
|
network_path.push(node_id);
|
||||||
|
let result = self.guess_type_from_node(network_path, child_id, child_input_index);
|
||||||
|
network_path.pop();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input is disconnected
|
// Input is disconnected
|
||||||
concrete!(())
|
(concrete!(()), TypeSource::Error("disconnected network input"))
|
||||||
}
|
}
|
||||||
_ => concrete!(()),
|
_ => (concrete!(()), TypeSource::Error("implementation is not network or protonode")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type_from_node(node, input_connector.input_index())
|
/// Get the [`Type`] for any InputConnector
|
||||||
})
|
pub fn input_type(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> (Type, TypeSource) {
|
||||||
|
if let Some(result) = self.node_type_from_compiled(input_connector, network_path) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve types from proto nodes in node_registry
|
||||||
|
let Some(node_id) = input_connector.node_id() else {
|
||||||
|
return (concrete!(()), TypeSource::Error("input connector is not a node"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Once there is type inference (#1621), replace this workaround approach when disconnecting node inputs with NodeInput::Node(ToDefaultNode),
|
||||||
|
// TODO: which would be a new node that implements the Default trait (i.e. `Default::default()`)
|
||||||
|
self.guess_type_from_node(&mut network_path.to_vec(), node_id, input_connector.input_index())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the output types for a given document node and its exports.
|
/// Retrieves the output types for a given document node and its exports.
|
||||||
|
|
@ -594,7 +628,7 @@ impl NodeNetworkInterface {
|
||||||
///
|
///
|
||||||
/// This function assumes that export indices and node IDs always exist within their respective
|
/// This function assumes that export indices and node IDs always exist within their respective
|
||||||
/// collections. It will panic if these assumptions are violated.
|
/// collections. It will panic if these assumptions are violated.
|
||||||
pub fn output_types(&self, node_id: &NodeId, network_path: &[NodeId]) -> Vec<Option<Type>> {
|
pub fn output_types(&self, node_id: &NodeId, network_path: &[NodeId]) -> Vec<Option<(Type, TypeSource)>> {
|
||||||
let Some(network) = self.network(network_path) else {
|
let Some(network) = self.network(network_path) else {
|
||||||
log::error!("Could not get network in output_types");
|
log::error!("Could not get network in output_types");
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
|
|
@ -624,7 +658,7 @@ impl NodeNetworkInterface {
|
||||||
output_types.push(nested_nodes_output_types.clone());
|
output_types.push(nested_nodes_output_types.clone());
|
||||||
}
|
}
|
||||||
NodeInput::Value { tagged_value, .. } => {
|
NodeInput::Value { tagged_value, .. } => {
|
||||||
output_types.push(Some(tagged_value.ty()));
|
output_types.push(Some((tagged_value.ty(), TypeSource::TaggedValue)));
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeInput::Network { .. } => {
|
NodeInput::Network { .. } => {
|
||||||
|
|
@ -640,15 +674,15 @@ impl NodeNetworkInterface {
|
||||||
}
|
}
|
||||||
graph_craft::document::DocumentNodeImplementation::ProtoNode(protonode) => {
|
graph_craft::document::DocumentNodeImplementation::ProtoNode(protonode) => {
|
||||||
let node_id_path = &[network_path, &[*node_id]].concat();
|
let node_id_path = &[network_path, &[*node_id]].concat();
|
||||||
let primary_output_type = self.resolved_types.types.get(node_id_path).map(|ty| ty.output.clone()).or_else(|| {
|
let primary_output_type = self.resolved_types.types.get(node_id_path).map(|ty| (ty.output.clone(), TypeSource::Compiled)).or_else(|| {
|
||||||
let node_types = proto_node_type(protonode)?;
|
let node_types = random_protonode_implementation(protonode)?;
|
||||||
Some(node_types.output.clone())
|
Some((node_types.output.clone(), TypeSource::RandomProtonodeImplementation))
|
||||||
});
|
});
|
||||||
|
|
||||||
output_types.push(primary_output_type);
|
output_types.push(primary_output_type);
|
||||||
}
|
}
|
||||||
graph_craft::document::DocumentNodeImplementation::Extract => {
|
graph_craft::document::DocumentNodeImplementation::Extract => {
|
||||||
output_types.push(Some(concrete!(())));
|
output_types.push(Some((concrete!(()), TypeSource::Error("extract node"))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output_types
|
output_types
|
||||||
|
|
@ -692,7 +726,7 @@ impl NodeNetworkInterface {
|
||||||
let mut encapsulating_path = network_path.to_vec();
|
let mut encapsulating_path = network_path.to_vec();
|
||||||
let encapsulating_node_id = encapsulating_path.pop().unwrap();
|
let encapsulating_node_id = encapsulating_path.pop().unwrap();
|
||||||
|
|
||||||
let input_type = self.input_type(&InputConnector::node(encapsulating_node_id, *import_index), &encapsulating_path);
|
let (input_type, type_source) = self.input_type(&InputConnector::node(encapsulating_node_id, *import_index), &encapsulating_path);
|
||||||
let data_type = FrontendGraphDataType::with_type(&input_type);
|
let data_type = FrontendGraphDataType::with_type(&input_type);
|
||||||
|
|
||||||
let import_name = if import_name.is_empty() { input_type.clone().nested_type().to_string() } else { import_name };
|
let import_name = if import_name.is_empty() { input_type.clone().nested_type().to_string() } else { import_name };
|
||||||
|
|
@ -710,7 +744,7 @@ impl NodeNetworkInterface {
|
||||||
FrontendGraphOutput {
|
FrontendGraphOutput {
|
||||||
data_type,
|
data_type,
|
||||||
name: import_name,
|
name: import_name,
|
||||||
resolved_type: Some(format!("{input_type:?}")),
|
resolved_type: Some(format!("{input_type:?} from {type_source:?}")),
|
||||||
connected_to,
|
connected_to,
|
||||||
},
|
},
|
||||||
click_target,
|
click_target,
|
||||||
|
|
@ -742,13 +776,13 @@ impl NodeNetworkInterface {
|
||||||
let (frontend_data_type, input_type) = if let NodeInput::Node { node_id, output_index, .. } = export {
|
let (frontend_data_type, input_type) = if let NodeInput::Node { node_id, output_index, .. } = export {
|
||||||
let output_types = self.output_types(node_id, network_path);
|
let output_types = self.output_types(node_id, network_path);
|
||||||
|
|
||||||
if let Some(output_type) = output_types.get(*output_index).cloned().flatten() {
|
if let Some((output_type, type_source)) = output_types.get(*output_index).cloned().flatten() {
|
||||||
(FrontendGraphDataType::with_type(&output_type), Some(output_type.clone()))
|
(FrontendGraphDataType::with_type(&output_type), Some((output_type, type_source)))
|
||||||
} else {
|
} else {
|
||||||
(FrontendGraphDataType::General, None)
|
(FrontendGraphDataType::General, None)
|
||||||
}
|
}
|
||||||
} else if let NodeInput::Value { tagged_value, .. } = export {
|
} else if let NodeInput::Value { tagged_value, .. } = export {
|
||||||
(FrontendGraphDataType::with_type(&tagged_value.ty()), Some(tagged_value.ty()))
|
(FrontendGraphDataType::with_type(&tagged_value.ty()), Some((tagged_value.ty(), TypeSource::TaggedValue)))
|
||||||
// TODO: Get type from parent node input when <https://github.com/GraphiteEditor/Graphite/issues/1762> is possible
|
// TODO: Get type from parent node input when <https://github.com/GraphiteEditor/Graphite/issues/1762> is possible
|
||||||
// else if let NodeInput::Network { import_type, .. } = export {
|
// else if let NodeInput::Network { import_type, .. } = export {
|
||||||
// (FrontendGraphDataType::with_type(import_type), Some(import_type.clone()))
|
// (FrontendGraphDataType::with_type(import_type), Some(import_type.clone()))
|
||||||
|
|
@ -783,7 +817,7 @@ impl NodeNetworkInterface {
|
||||||
} else {
|
} else {
|
||||||
input_type
|
input_type
|
||||||
.clone()
|
.clone()
|
||||||
.map(|input_type| input_type.nested_type().to_string())
|
.map(|(input_type, _)| input_type.nested_type().to_string())
|
||||||
.unwrap_or(format!("Export {}", export_index + 1))
|
.unwrap_or(format!("Export {}", export_index + 1))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -791,7 +825,7 @@ impl NodeNetworkInterface {
|
||||||
FrontendGraphInput {
|
FrontendGraphInput {
|
||||||
data_type: frontend_data_type,
|
data_type: frontend_data_type,
|
||||||
name: export_name,
|
name: export_name,
|
||||||
resolved_type: input_type.map(|input| format!("{input:?}")),
|
resolved_type: input_type.map(|(export_type, source)| format!("{export_type:?} from {source:?}")),
|
||||||
connected_to,
|
connected_to,
|
||||||
},
|
},
|
||||||
click_target,
|
click_target,
|
||||||
|
|
@ -1407,7 +1441,8 @@ impl NodeNetworkInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proto_node_type(protonode: &graph_craft::ProtoNodeIdentifier) -> Option<&graphene_std::NodeIOTypes> {
|
/// Gets the type for a random protonode implementation (used if there is no type from the compiled network)
|
||||||
|
fn random_protonode_implementation(protonode: &graph_craft::ProtoNodeIdentifier) -> Option<&graphene_std::NodeIOTypes> {
|
||||||
let Some(node_io_hashmap) = NODE_REGISTRY.get(protonode) else {
|
let Some(node_io_hashmap) = NODE_REGISTRY.get(protonode) else {
|
||||||
log::error!("Could not get hashmap for proto node: {protonode:?}");
|
log::error!("Could not get hashmap for proto node: {protonode:?}");
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -3325,7 +3360,7 @@ impl NodeNetworkInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tagged_value = TaggedValue::from_type(&self.input_type(input_connector, network_path));
|
let tagged_value = TaggedValue::from_type(&self.input_type(input_connector, network_path).0);
|
||||||
|
|
||||||
let value_input = NodeInput::value(tagged_value, true);
|
let value_input = NodeInput::value(tagged_value, true);
|
||||||
|
|
||||||
|
|
@ -4838,8 +4873,26 @@ impl<'a> Iterator for FlowIter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the source of a resolved type (for debugging)
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub enum TypeSource {
|
||||||
|
Compiled,
|
||||||
|
RandomProtonodeImplementation,
|
||||||
|
DocumentNodeDefault,
|
||||||
|
TaggedValue,
|
||||||
|
OuterMostExportDefault,
|
||||||
|
|
||||||
|
Error(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TypeSource {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Error("no source")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents an input connector with index based on the [`DocumentNode::inputs`] index, not the visible input index
|
/// Represents an input connector with index based on the [`DocumentNode::inputs`] index, not the visible input index
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub enum InputConnector {
|
pub enum InputConnector {
|
||||||
#[serde(rename = "node")]
|
#[serde(rename = "node")]
|
||||||
Node {
|
Node {
|
||||||
|
|
@ -4879,7 +4932,7 @@ impl InputConnector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an output connector
|
/// Represents an output connector
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub enum OutputConnector {
|
pub enum OutputConnector {
|
||||||
#[serde(rename = "node")]
|
#[serde(rename = "node")]
|
||||||
Node {
|
Node {
|
||||||
|
|
@ -4916,6 +4969,14 @@ impl OutputConnector {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_input(input: &NodeInput) -> Option<Self> {
|
||||||
|
match input {
|
||||||
|
NodeInput::Network { import_index, .. } => Some(Self::Import(*import_index)),
|
||||||
|
NodeInput::Node { node_id, output_index, .. } => Some(Self::node(*node_id, *output_index)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use graph_craft::document::NodeNetwork;
|
#[cfg(any(feature = "criterion", feature = "iai"))]
|
||||||
use graph_craft::graphene_compiler::Compiler;
|
use graph_craft::{document::NodeNetwork, graphene_compiler::Compiler, proto::ProtoNetwork};
|
||||||
use graph_craft::proto::ProtoNetwork;
|
|
||||||
|
|
||||||
#[cfg(feature = "criterion")]
|
#[cfg(feature = "criterion")]
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
|
@ -8,11 +7,13 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
#[cfg(all(not(feature = "criterion"), feature = "iai"))]
|
#[cfg(all(not(feature = "criterion"), feature = "iai"))]
|
||||||
use iai_callgrind::{black_box, library_benchmark, library_benchmark_group, main};
|
use iai_callgrind::{black_box, library_benchmark, library_benchmark_group, main};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "criterion", feature = "iai"))]
|
||||||
fn load_network(document_string: &str) -> NodeNetwork {
|
fn load_network(document_string: &str) -> NodeNetwork {
|
||||||
let document: serde_json::Value = serde_json::from_str(document_string).expect("Failed to parse document");
|
let document: serde_json::Value = serde_json::from_str(document_string).expect("Failed to parse document");
|
||||||
serde_json::from_value::<NodeNetwork>(document["network_interface"]["network"].clone()).expect("Failed to parse document")
|
serde_json::from_value::<NodeNetwork>(document["network_interface"]["network"].clone()).expect("Failed to parse document")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "criterion", feature = "iai"))]
|
||||||
fn compile(network: NodeNetwork) -> ProtoNetwork {
|
fn compile(network: NodeNetwork) -> ProtoNetwork {
|
||||||
let compiler = Compiler {};
|
let compiler = Compiler {};
|
||||||
compiler.compile_single(network).unwrap()
|
compiler.compile_single(network).unwrap()
|
||||||
|
|
@ -41,6 +42,7 @@ fn compile_to_proto(c: &mut Criterion) {
|
||||||
|
|
||||||
#[cfg_attr(all(feature = "iai", not(feature = "criterion")), library_benchmark)]
|
#[cfg_attr(all(feature = "iai", not(feature = "criterion")), library_benchmark)]
|
||||||
#[cfg_attr(all(feature = "iai", not(feature="criterion")), benches::with_setup(args = ["isometric-fountain", "painted-dreams", "procedural-string-lights", "red-dress", "valley-of-spires"], setup = load_from_name))]
|
#[cfg_attr(all(feature = "iai", not(feature="criterion")), benches::with_setup(args = ["isometric-fountain", "painted-dreams", "procedural-string-lights", "red-dress", "valley-of-spires"], setup = load_from_name))]
|
||||||
|
#[cfg(all(not(feature = "criterion"), feature = "iai"))]
|
||||||
pub fn iai_compile_to_proto(input: NodeNetwork) {
|
pub fn iai_compile_to_proto(input: NodeNetwork) {
|
||||||
black_box(compile(input));
|
black_box(compile(input));
|
||||||
}
|
}
|
||||||
|
|
@ -56,3 +58,6 @@ library_benchmark_group!(name = compile_group; benchmarks = iai_compile_to_proto
|
||||||
|
|
||||||
#[cfg(all(not(feature = "criterion"), feature = "iai"))]
|
#[cfg(all(not(feature = "criterion"), feature = "iai"))]
|
||||||
main!(library_benchmark_groups = compile_group);
|
main!(library_benchmark_groups = compile_group);
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "criterion"), not(feature = "iai")))]
|
||||||
|
fn main() {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue