Repository: GraphiteEditor/Graphite
File: node-graph/graph-craft/src/document.rs (Rust)

Code before:
				}

				for input in input_node.inputs.iter_mut() {
					if let NodeInput::Node { .. } = input {
						*input = NodeInput::Network(generic!(T))
					}
				}
				node.inputs = vec![NodeInput::value(TaggedValue::DocumentNode(input_node), false)];
			}
		}
		self.nodes.extend(extraction_nodes);
	}

	/// Due to the adaptive resolution system, nodes that take a `GraphicGroup` as input must call the upstream node with the `Footprint` parameter.
	///
	/// However, in the case of the default input, we must insert a node that takes an input of `Footprint` and returns `GraphicGroup::Empty`, in order to satisfy the type system.
	/// This is because the standard value node takes in `()`.
	pub fn resolve_empty_stacks(&mut self) {
		let new_id = generate_uuid();
		let mut used = false;

		for node in self.nodes.values_mut() {
			// Do not do this to the newly inserted empty stack (in case `resolve_empty_stacks` runs multiple times).
			if node.name == "Empty Stack" {
				continue;
			}
			for input in &mut node.inputs {
				if !matches!(
					input,
					NodeInput::Value {
						tagged_value: TaggedValue::GraphicGroup(GraphicGroup::EMPTY),
						..
					}
				) {
					continue;
				}

				*input = NodeInput::node(new_id, 0);
				used = true;
			}
		}

		// Only insert the node if necessary.
		if used {
			let new_node = DocumentNode {
				name: "Empty Stack".to_string(),
				implementation: DocumentNodeImplementation::proto("graphene_core::transform::CullNode<_>"),
				manual_composition: Some(concrete!(graphene_core::transform::Footprint)),
				inputs: vec![NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroup::EMPTY), false)],
				..Default::default()
			};

Review comment (suggestion):
Stylistic suggestion: use `.filter(|node| node.name != "Empty Stack")` to make this all a one-liner.

Code after:
		if let DocumentNodeImplementation::Unresolved(ident) = &node.implementation {
			if ident.name == "graphene_core::ops::IdNode" {
				assert_eq!(node.inputs.len(), 1, "Id node has more than one input");
				if let NodeInput::Node { node_id, output_index, .. } = node.inputs[0] {
					let input_node_id = node_id;
					for output in self.nodes.values_mut() {
						for input in &mut output.inputs {
							if let NodeInput::Node {
								node_id: output_node_id,
								output_index: output_output_index,
								..
							} = input
							{
								if *output_node_id == id {
									*output_node_id = input_node_id;
									*output_output_index = output_index;
								}
							}
						}
						for NodeOutput {
							ref mut node_id,
							ref mut node_output_index,
						} in self.outputs.iter_mut()
						{
							if *node_id == id {
								*node_id = input_node_id;
								*node_output_index = output_index;
							}
						}
					}
				}
				self.nodes.remove(&id);
			}
		}
		Ok(())
	}

	/// Strips out any [`graphene_core::ops::IdNode`]s that are unnecessary.
	pub fn remove_redundant_id_nodes(&mut self) {
		let id_nodes = self
			.nodes
			.iter()
			.filter(|(_, node)| {
				matches!(&node.implementation, DocumentNodeImplementation::Unresolved(ident) if ident == &NodeIdentifier::new("graphene_core::ops::IdNode"))
					&& node.inputs.len() == 1
					&& matches!(node.inputs[0], NodeInput::Node { .. })
			})
			.map(|(id, _)| *id)
			.collect::<Vec<_>>();
		for id in id_nodes {
			if let Err(e) = self.remove_id_node(id) {