diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 5357c7cc..ed0c1cc2 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -117,19 +117,19 @@ fn static_nodes() -> Vec { name: "Downres".to_string(), inputs: vec![NodeInput::Network(concrete!(ImageFrame))], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::raster::DownresNode<_>")), - metadata: Default::default(), + ..Default::default() }, DocumentNode { name: "Cache".to_string(), inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")), - metadata: Default::default(), + ..Default::default() }, DocumentNode { name: "Clone".to_string(), inputs: vec![NodeInput::node(1, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")), - metadata: Default::default(), + ..Default::default() }, ] .into_iter() @@ -164,7 +164,7 @@ fn static_nodes() -> Vec { name: "Identity".to_string(), inputs: vec![NodeInput::Network(concrete!(EditorApi))], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ExtractImageFrame")), - metadata: Default::default(), + ..Default::default() }] .into_iter() .enumerate() @@ -197,25 +197,25 @@ fn static_nodes() -> Vec { name: "SetNode".to_string(), inputs: vec![NodeInput::Network(concrete!(EditorApi))], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::SomeNode")), - metadata: Default::default(), + ..Default::default() }, DocumentNode { name: "LetNode".to_string(), inputs: vec![NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::LetNode<_>")), - metadata: Default::default(), + ..Default::default() }, DocumentNode { name: "RefNode".to_string(), inputs: vec![NodeInput::Network(concrete!(())), NodeInput::lambda(1, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::RefNode<_, _>")), - metadata: Default::default(), + ..Default::default() }, DocumentNode { name: "CloneNode".to_string(), inputs: vec![NodeInput::node(2, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")), - metadata: Default::default(), + ..Default::default() }, ] .into_iter() @@ -423,7 +423,7 @@ fn static_nodes() -> Vec { name: "CacheNode".to_string(), inputs: vec![NodeInput::Network(concrete!(Image))], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")), - metadata: Default::default(), + ..Default::default() }, ), ( @@ -432,7 +432,7 @@ fn static_nodes() -> Vec { name: "BlurNode".to_string(), inputs: vec![NodeInput::node(0, 0), NodeInput::Network(concrete!(u32)), NodeInput::Network(concrete!(f64)), NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::BlurNode")), - metadata: Default::default(), + ..Default::default() }, ), ] @@ -493,7 +493,7 @@ fn static_nodes() -> Vec { name: "CacheNode".to_string(), inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::Network(concrete!(ImageFrame))], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")), - metadata: Default::default(), + ..Default::default() }, ), ( @@ -502,7 +502,7 @@ fn static_nodes() -> Vec { name: "CloneNode".to_string(), inputs: vec![NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")), - metadata: Default::default(), + ..Default::default() }, ), ] @@ -987,7 +987,7 @@ impl DocumentNodeType { // TODO: Allow inserting nodes that contain other nodes. implementation: DocumentNodeImplementation::Unresolved(ident.clone()), inputs: self.inputs.iter().map(|i| NodeInput::Network(i.default.ty())).collect(), - metadata: DocumentNodeMetadata::default(), + ..Default::default() }, )] .into_iter() @@ -1010,6 +1010,7 @@ impl DocumentNodeType { inputs, implementation: self.generate_implementation(), metadata, + ..Default::default() } } @@ -1040,7 +1041,7 @@ pub fn wrap_network_in_scope(network: NodeNetwork) -> NodeNetwork { name: "Scope".to_string(), implementation: DocumentNodeImplementation::Network(network), inputs: vec![NodeInput::node(0, 1)], - metadata: DocumentNodeMetadata::default(), + ..Default::default() }; // wrap the inner network in a scope diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index d7d7b68a..9411f321 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -311,6 +311,7 @@ fn add_brush_render(data: &BrushToolData, tool_data: &DocumentToolData, response ], implementation: DocumentNodeImplementation::Unresolved("graphene_std::brush::BrushNode".into()), metadata: graph_craft::document::DocumentNodeMetadata { position: (8, 4).into() }, + ..Default::default() }; let mut network = NodeNetwork::value_network(brush_node); network.push_output_node(); diff --git a/node-graph/compilation-client/src/main.rs b/node-graph/compilation-client/src/main.rs index 3fce504d..723581cc 100644 --- a/node-graph/compilation-client/src/main.rs +++ b/node-graph/compilation-client/src/main.rs @@ -58,8 +58,8 @@ fn add_network() -> NodeNetwork { DocumentNode { name: "Dup".into(), inputs: vec![NodeInput::value(value::TaggedValue::U32(5u32), false)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")), + ..Default::default() }, ), // ( diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index b7157feb..f5662724 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -33,13 +33,14 @@ impl DocumentNodeMetadata { } } -#[derive(Clone, Debug, PartialEq, Hash, DynAny)] +#[derive(Clone, Debug, PartialEq, Hash, DynAny, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DocumentNode { pub name: String, pub inputs: Vec, pub implementation: DocumentNodeImplementation, pub metadata: DocumentNodeMetadata, + pub path: Option>, } impl DocumentNode { @@ -91,6 +92,7 @@ impl DocumentNode { identifier: fqn, input, construction_args: args, + document_node_path: self.path.unwrap_or(Vec::new()), } } else { unreachable!("tried to resolve not flattened node on resolved node"); @@ -315,6 +317,7 @@ impl NodeNetwork { inputs: vec![NodeInput::ShortCircut(concrete!(u32))], implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()), metadata: DocumentNodeMetadata { position: (8, 4).into() }, + ..Default::default() }, )] .into_iter() @@ -349,7 +352,7 @@ impl NodeNetwork { name: "Output".into(), inputs: vec![], implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()), - metadata: DocumentNodeMetadata { position: (0, 0).into() }, + ..Default::default() }; self.push_node(node, true) } @@ -369,7 +372,7 @@ impl NodeNetwork { name: "CacheNode".to_string(), inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::Network(ty)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")), - metadata: Default::default(), + ..Default::default() }, ), ( @@ -378,7 +381,7 @@ impl NodeNetwork { name: "CloneNode".to_string(), inputs: vec![NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")), - metadata: Default::default(), + ..Default::default() }, ), ] @@ -387,6 +390,7 @@ impl NodeNetwork { ..Default::default() }), metadata: DocumentNodeMetadata { position: (0, 0).into() }, + ..Default::default() }; self.push_node(node, true) } @@ -534,6 +538,20 @@ impl NodeNetwork { outwards_links } + pub fn generate_node_paths(&mut self, prefix: &[NodeId]) { + for (node_id, node) in &mut self.nodes { + let mut new_path = prefix.to_vec(); + new_path.push(*node_id); + if let DocumentNodeImplementation::Network(network) = &mut node.implementation { + network.generate_node_paths(new_path.as_slice()); + } + if node.path.is_some() { + log::warn!("Overwriting node path"); + } + node.path = Some(new_path); + } + } + /// When a node has multiple outputs, we actually just duplicate the node and evaluate each output separately pub fn duplicate_outputs(&mut self, mut gen_id: &mut impl FnMut() -> NodeId) { let mut duplicating_nodes = HashMap::new(); @@ -653,18 +671,26 @@ impl NodeNetwork { std::mem::swap(&mut dummy_input, input); if let NodeInput::Value { tagged_value, exposed } = dummy_input { let value_node_id = gen_id(); - let value_node_id = map_ids(id, value_node_id); + let merged_node_id = map_ids(id, value_node_id); + let path = if let Some(mut new_path) = node.path.clone() { + new_path.push(value_node_id); + Some(new_path) + } else { + None + }; + self.nodes.insert( - value_node_id, + merged_node_id, DocumentNode { name: "Value".into(), inputs: vec![NodeInput::Value { tagged_value, exposed }], implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::ValueNode".into()), - metadata: DocumentNodeMetadata::default(), + path, + ..Default::default() }, ); *input = NodeInput::Node { - node_id: value_node_id, + node_id: merged_node_id, output_index: 0, lambda: false, }; @@ -789,8 +815,8 @@ mod test { DocumentNode { name: "Cons".into(), inputs: vec![NodeInput::Network(concrete!(u32)), NodeInput::Network(concrete!(u32))], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::structural::ConsNode".into()), + ..Default::default() }, ), ( @@ -798,8 +824,8 @@ mod test { DocumentNode { name: "Add".into(), inputs: vec![NodeInput::node(0, 0)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::AddNode".into()), + ..Default::default() }, ), ] @@ -822,8 +848,8 @@ mod test { DocumentNode { name: "Cons".into(), inputs: vec![NodeInput::Network(concrete!(u32)), NodeInput::Network(concrete!(u32))], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::structural::ConsNode".into()), + ..Default::default() }, ), ( @@ -831,8 +857,8 @@ mod test { DocumentNode { name: "Add".into(), inputs: vec![NodeInput::node(1, 0)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::AddNode".into()), + ..Default::default() }, ), ] @@ -848,8 +874,8 @@ mod test { let id_node = DocumentNode { name: "Id".into(), inputs: vec![], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()), + ..Default::default() }; let mut extraction_network = NodeNetwork { inputs: vec![], @@ -859,8 +885,8 @@ mod test { DocumentNode { name: "Extract".into(), inputs: vec![NodeInput::lambda(0, 0)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Extract, + ..Default::default() }, ] .into_iter() @@ -893,15 +919,18 @@ mod test { }, ], implementation: DocumentNodeImplementation::Network(add_network()), - metadata: DocumentNodeMetadata::default(), + ..Default::default() }, )] .into_iter() .collect(), ..Default::default() }; + network.generate_node_paths(&[]); network.flatten_with_fns(1, |self_id, inner_id| self_id * 10 + inner_id, gen_node_id); let flat_network = flat_network(); + println!("{:#?}", flat_network); + println!("{:#?}", network); assert_eq!(flat_network, network); } @@ -911,8 +940,8 @@ mod test { let document_node = DocumentNode { name: "Cons".into(), inputs: vec![NodeInput::Network(concrete!(u32)), NodeInput::node(0, 0)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::structural::ConsNode".into()), + ..Default::default() }; let proto_node = document_node.resolve_proto_node(); @@ -920,6 +949,7 @@ mod test { identifier: "graphene_core::structural::ConsNode".into(), input: ProtoNodeInput::Network(concrete!(u32)), construction_args: ConstructionArgs::Nodes(vec![(0, false)]), + document_node_path: vec![], }; assert_eq!(proto_node, reference); } @@ -936,6 +966,7 @@ mod test { identifier: "graphene_core::ops::IdNode".into(), input: ProtoNodeInput::Node(11, false), construction_args: ConstructionArgs::Nodes(vec![]), + document_node_path: vec![1], }, ), ( @@ -944,6 +975,7 @@ mod test { identifier: "graphene_core::structural::ConsNode".into(), input: ProtoNodeInput::Network(concrete!(u32)), construction_args: ConstructionArgs::Nodes(vec![(14, false)]), + document_node_path: vec![1, 0], }, ), ( @@ -952,9 +984,10 @@ mod test { identifier: "graphene_core::ops::AddNode".into(), input: ProtoNodeInput::Node(10, false), construction_args: ConstructionArgs::Nodes(vec![]), + document_node_path: vec![1, 1], }, ), - (14, ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2)))), + (14, ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2)), vec![1, 4])), ] .into_iter() .collect(), @@ -977,8 +1010,9 @@ mod test { DocumentNode { name: "Inc".into(), inputs: vec![NodeInput::node(11, 0)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()), + path: Some(vec![1]), + ..Default::default() }, ), ( @@ -986,8 +1020,9 @@ mod test { DocumentNode { name: "Cons".into(), inputs: vec![NodeInput::Network(concrete!(u32)), NodeInput::node(14, 0)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::structural::ConsNode".into()), + path: Some(vec![1, 0]), + ..Default::default() }, ), ( @@ -998,8 +1033,9 @@ mod test { tagged_value: TaggedValue::U32(2), exposed: false, }], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::ValueNode".into()), + path: Some(vec![1, 4]), + ..Default::default() }, ), ( @@ -1007,8 +1043,9 @@ mod test { DocumentNode { name: "Add".into(), inputs: vec![NodeInput::node(10, 0)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::AddNode".into()), + path: Some(vec![1, 1]), + ..Default::default() }, ), ] @@ -1028,8 +1065,8 @@ mod test { DocumentNode { name: "Identity 1".into(), inputs: vec![NodeInput::Network(concrete!(u32))], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")), + ..Default::default() }, ), ( @@ -1037,8 +1074,8 @@ mod test { DocumentNode { name: "Identity 2".into(), inputs: vec![NodeInput::Network(concrete!(u32))], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")), + ..Default::default() }, ), ] @@ -1058,8 +1095,8 @@ mod test { DocumentNode { name: "Nested network".into(), inputs: vec![NodeInput::value(TaggedValue::F32(1.), false), NodeInput::value(TaggedValue::F32(2.), false)], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Network(two_node_identity()), + ..Default::default() }, ), ( @@ -1067,8 +1104,8 @@ mod test { DocumentNode { name: "Result".into(), inputs: vec![result_node_input], - metadata: DocumentNodeMetadata::default(), implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")), + ..Default::default() }, ), ] diff --git a/node-graph/graph-craft/src/executor.rs b/node-graph/graph-craft/src/executor.rs index dbc1dd2e..314cc64a 100644 --- a/node-graph/graph-craft/src/executor.rs +++ b/node-graph/graph-craft/src/executor.rs @@ -10,6 +10,7 @@ pub struct Compiler {} impl Compiler { pub fn compile(&self, mut network: NodeNetwork, resolve_inputs: bool) -> impl Iterator { let node_ids = network.nodes.keys().copied().collect::>(); + network.generate_node_paths(&[]); network.resolve_extract_nodes(); println!("flattening"); for id in node_ids { diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs index 3bb66b11..ad69849c 100644 --- a/node-graph/graph-craft/src/proto.rs +++ b/node-graph/graph-craft/src/proto.rs @@ -120,6 +120,7 @@ pub struct ProtoNode { pub construction_args: ConstructionArgs, pub input: ProtoNodeInput, pub identifier: NodeIdentifier, + pub document_node_path: Vec, } /// A ProtoNodeInput represents the input of a node in a ProtoNetwork. @@ -170,11 +171,12 @@ impl ProtoNode { Some(hasher.finish() as NodeId) } - pub fn value(value: ConstructionArgs) -> Self { + pub fn value(value: ConstructionArgs, path: Vec) -> Self { Self { identifier: NodeIdentifier::new("graphene_core::value::ValueNode"), construction_args: value, input: ProtoNodeInput::None, + document_node_path: path, } } @@ -270,13 +272,15 @@ impl ProtoNetwork { let mut lookup = self.nodes.iter().map(|(id, _)| (*id, *id)).collect::>(); let compose_node_id = self.nodes.len() as NodeId; let inputs = self.nodes.iter().map(|(_, node)| node.input.clone()).collect::>(); + let paths = self.nodes.iter().map(|(_, node)| node.document_node_path.clone()).collect::>(); let resolved_lookup = resolved.clone(); - if let Some((input_node, id, input)) = self.nodes.iter_mut().filter(|(id, _)| !resolved_lookup.contains(id)).find_map(|(id, node)| { + if let Some((input_node, id, input, path)) = self.nodes.iter_mut().filter(|(id, _)| !resolved_lookup.contains(id)).find_map(|(id, node)| { if let ProtoNodeInput::Node(input_node, false) = node.input { resolved.insert(*id); let pre_node_input = inputs.get(input_node as usize).expect("input node should exist"); - Some((input_node, *id, pre_node_input.clone())) + let pre_path = paths.get(input_node as usize).expect("input node should exist"); + Some((input_node, *id, pre_node_input.clone(), pre_path.clone())) } else { resolved.insert(*id); None @@ -290,6 +294,7 @@ impl ProtoNetwork { identifier: NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"), construction_args: ConstructionArgs::Nodes(vec![(input_node, false), (id, true)]), input, + document_node_path: path, }, )); return false; @@ -644,6 +649,7 @@ mod test { identifier: "id".into(), input: ProtoNodeInput::Node(11, false), construction_args: ConstructionArgs::Nodes(vec![]), + document_node_path: vec![], }, ), ( @@ -652,6 +658,7 @@ mod test { identifier: "id".into(), input: ProtoNodeInput::Node(11, false), construction_args: ConstructionArgs::Nodes(vec![]), + document_node_path: vec![], }, ), ( @@ -660,6 +667,7 @@ mod test { identifier: "cons".into(), input: ProtoNodeInput::Network(concrete!(u32)), construction_args: ConstructionArgs::Nodes(vec![(14, false)]), + document_node_path: vec![], }, ), ( @@ -668,6 +676,7 @@ mod test { identifier: "add".into(), input: ProtoNodeInput::Node(10, false), construction_args: ConstructionArgs::Nodes(vec![]), + document_node_path: vec![], }, ), ( @@ -676,6 +685,7 @@ mod test { identifier: "value".into(), input: ProtoNodeInput::None, construction_args: ConstructionArgs::Value(value::TaggedValue::U32(2)), + document_node_path: vec![], }, ), ] diff --git a/node-graph/interpreted-executor/src/executor.rs b/node-graph/interpreted-executor/src/executor.rs index c83e22d2..7db5da40 100644 --- a/node-graph/interpreted-executor/src/executor.rs +++ b/node-graph/interpreted-executor/src/executor.rs @@ -198,7 +198,7 @@ mod test { #[test] fn push_node() { let mut tree = BorrowTree::default(); - let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32))); + let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]); tree.push_node(0, val_1_protonode, &TypingContext::default()).unwrap(); let _node = tree.get(0).unwrap(); assert_eq!(tree.eval(0, ()), Some(2u32)); diff --git a/node-graph/interpreted-executor/src/lib.rs b/node-graph/interpreted-executor/src/lib.rs index 6217a376..0a777281 100644 --- a/node-graph/interpreted-executor/src/lib.rs +++ b/node-graph/interpreted-executor/src/lib.rs @@ -61,7 +61,7 @@ mod tests { name: "Cons".into(), inputs: vec![NodeInput::Network(concrete!(u32)), NodeInput::Network(concrete!(&u32))], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode<_, _>")), - metadata: DocumentNodeMetadata::default(), + ..Default::default() }, ), ( @@ -70,7 +70,7 @@ mod tests { name: "Add".into(), inputs: vec![NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode")), - metadata: DocumentNodeMetadata::default(), + ..Default::default() }, ), ] @@ -95,7 +95,7 @@ mod tests { }, ], implementation: DocumentNodeImplementation::Network(add_network()), - metadata: DocumentNodeMetadata::default(), + ..Default::default() }, )] .into_iter() @@ -133,7 +133,7 @@ mod tests { name: "id".into(), inputs: vec![NodeInput::Network(concrete!(u32))], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")), - metadata: DocumentNodeMetadata::default(), + ..Default::default() }, ), // An add node adding the result of the id node to its self @@ -143,7 +143,7 @@ mod tests { name: "Add".into(), inputs: vec![NodeInput::node(0, 0), NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddParameterNode<_>")), - metadata: DocumentNodeMetadata::default(), + ..Default::default() }, ), ]