mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-07 23:08:07 +00:00
Rename NodeNetwork inputs/outputs to imports/exports
This commit is contained in:
parent
137853eb40
commit
fd54cda445
17 changed files with 166 additions and 164 deletions
|
@ -514,24 +514,26 @@ impl NodeOutput {
|
|||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
/// A network (subgraph) of nodes containing each [`DocumentNode`] and its ID, as well as a list of input nodes and [`NodeOutput`]s
|
||||
pub struct NodeNetwork {
|
||||
/// The list of nodes that are imported into this network from the parent network. Each is a reference to the node that the input is connected to.
|
||||
/// Presently, only one is supported— use an Identity node to split an input to multiple user nodes (although this could be changed in the future).
|
||||
pub inputs: Vec<NodeId>,
|
||||
/// The list of data outputs that are exported from this network to the parent network. Each is a reference to the node, and its output index, that is the source of the output data.
|
||||
pub outputs: Vec<NodeOutput>,
|
||||
/// The list of nodes that are imported into this network from the parent network.
|
||||
/// Each import is a reference to which node within this network that the input is connected to.
|
||||
/// Presently, only one is supported— use an Identity node to split an input to multiple user nodes (although this could, and should, be changed in the future).
|
||||
pub imports: Vec<NodeId>,
|
||||
/// The list of data outputs that are exported from this network to the parent network.
|
||||
/// Each export is a reference to a node within this network, paired with its output index, that is the source of the network's exported data.
|
||||
pub exports: Vec<NodeOutput>,
|
||||
/// The list of all nodes in this network.
|
||||
pub nodes: HashMap<NodeId, DocumentNode>,
|
||||
/// Nodes that the user has disabled/hidden with the visibility eye icon.
|
||||
/// These nodes get replaced with Identity nodes during the graph flattening step.
|
||||
pub disabled: Vec<NodeId>,
|
||||
/// In the case when another node is previewed (chosen by the user as a temporary output), this stores what it used to be so it can be restored later.
|
||||
/// In the case when another node is previewed (chosen by the user as a temporary output), this stores what it previously was so it can be restored later.
|
||||
pub previous_outputs: Option<Vec<NodeOutput>>,
|
||||
}
|
||||
|
||||
impl std::hash::Hash for NodeNetwork {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.inputs.hash(state);
|
||||
self.outputs.hash(state);
|
||||
self.imports.hash(state);
|
||||
self.exports.hash(state);
|
||||
let mut nodes: Vec<_> = self.nodes.iter().collect();
|
||||
nodes.sort_by_key(|(id, _)| *id);
|
||||
for (id, node) in nodes {
|
||||
|
@ -553,17 +555,17 @@ impl NodeNetwork {
|
|||
|
||||
/// Get the original output nodes of this network, ignoring any preview node
|
||||
pub fn original_outputs(&self) -> &Vec<NodeOutput> {
|
||||
self.previous_outputs.as_ref().unwrap_or(&self.outputs)
|
||||
self.previous_outputs.as_ref().unwrap_or(&self.exports)
|
||||
}
|
||||
|
||||
pub fn input_types(&self) -> impl Iterator<Item = Type> + '_ {
|
||||
self.inputs.iter().map(move |id| self.nodes[id].inputs.get(0).map(|i| i.ty()).unwrap_or(concrete!(())))
|
||||
self.imports.iter().map(move |id| self.nodes[id].inputs.get(0).map(|i| i.ty()).unwrap_or(concrete!(())))
|
||||
}
|
||||
|
||||
pub fn value_network(node: DocumentNode) -> Self {
|
||||
Self {
|
||||
inputs: node.inputs.iter().filter(|input| matches!(input, NodeInput::Network(_))).map(|_| NodeId(0)).collect(),
|
||||
outputs: vec![NodeOutput::new(NodeId(0), 0)],
|
||||
imports: node.inputs.iter().filter(|input| matches!(input, NodeInput::Network(_))).map(|_| NodeId(0)).collect(),
|
||||
exports: vec![NodeOutput::new(NodeId(0), 0)],
|
||||
nodes: [(NodeId(0), node)].into_iter().collect(),
|
||||
disabled: vec![],
|
||||
previous_outputs: None,
|
||||
|
@ -573,8 +575,8 @@ impl NodeNetwork {
|
|||
/// A graph with just an input node
|
||||
pub fn new_network() -> Self {
|
||||
Self {
|
||||
inputs: vec![NodeId(0)],
|
||||
outputs: vec![NodeOutput::new(NodeId(0), 0)],
|
||||
imports: vec![NodeId(0)],
|
||||
exports: vec![NodeOutput::new(NodeId(0), 0)],
|
||||
nodes: [(
|
||||
NodeId(0),
|
||||
DocumentNode {
|
||||
|
@ -600,8 +602,8 @@ impl NodeNetwork {
|
|||
node.metadata.position = pos + IVec2::new(8, 0);
|
||||
}
|
||||
}
|
||||
if !self.outputs.is_empty() {
|
||||
let input = NodeInput::node(self.outputs[0].node_id, self.outputs[0].node_output_index);
|
||||
if !self.exports.is_empty() {
|
||||
let input = NodeInput::node(self.exports[0].node_id, self.exports[0].node_output_index);
|
||||
if node.inputs.is_empty() {
|
||||
node.inputs.push(input);
|
||||
} else {
|
||||
|
@ -609,7 +611,7 @@ impl NodeNetwork {
|
|||
}
|
||||
}
|
||||
self.nodes.insert(id, node);
|
||||
self.outputs = vec![NodeOutput::new(id, 0)];
|
||||
self.exports = vec![NodeOutput::new(id, 0)];
|
||||
id
|
||||
}
|
||||
|
||||
|
@ -630,8 +632,8 @@ impl NodeNetwork {
|
|||
name: "Cache".into(),
|
||||
inputs: vec![],
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
inputs: vec![NodeId(0)],
|
||||
outputs: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
imports: vec![NodeId(0)],
|
||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
nodes: vec![
|
||||
(
|
||||
NodeId(0),
|
||||
|
@ -686,13 +688,13 @@ impl NodeNetwork {
|
|||
/// Check if the specified node id is connected to the output
|
||||
pub fn connected_to_output(&self, target_node_id: NodeId) -> bool {
|
||||
// If the node is the output then return true
|
||||
if self.outputs.iter().any(|&NodeOutput { node_id, .. }| node_id == target_node_id) {
|
||||
if self.exports.iter().any(|&NodeOutput { node_id, .. }| node_id == target_node_id) {
|
||||
return true;
|
||||
}
|
||||
// Get the outputs
|
||||
let mut stack = self.outputs.iter().filter_map(|&output| self.nodes.get(&output.node_id)).collect::<Vec<_>>();
|
||||
let mut stack = self.exports.iter().filter_map(|&output| self.nodes.get(&output.node_id)).collect::<Vec<_>>();
|
||||
let mut already_visited = HashSet::new();
|
||||
already_visited.extend(self.outputs.iter().map(|output| output.node_id));
|
||||
already_visited.extend(self.exports.iter().map(|output| output.node_id));
|
||||
|
||||
while let Some(node) = stack.pop() {
|
||||
for input in &node.inputs {
|
||||
|
@ -720,7 +722,7 @@ impl NodeNetwork {
|
|||
|
||||
/// Is the node being used directly as an output?
|
||||
pub fn outputs_contain(&self, node_id: NodeId) -> bool {
|
||||
self.outputs.iter().any(|output| output.node_id == node_id)
|
||||
self.exports.iter().any(|output| output.node_id == node_id)
|
||||
}
|
||||
|
||||
/// Is the node being used directly as an original output?
|
||||
|
@ -774,8 +776,8 @@ impl NodeNetwork {
|
|||
|
||||
pub fn output_as_input(&self, arg: usize) -> NodeInput {
|
||||
NodeInput::Node {
|
||||
node_id: self.outputs[arg].node_id,
|
||||
output_index: self.outputs[arg].node_output_index,
|
||||
node_id: self.exports[arg].node_id,
|
||||
output_index: self.exports[arg].node_output_index,
|
||||
lambda: false,
|
||||
}
|
||||
}
|
||||
|
@ -811,8 +813,8 @@ impl<'a> Iterator for FlowIter<'a> {
|
|||
impl NodeNetwork {
|
||||
/// Replace all references in the graph of a node ID with a new node ID defined by the function `f`.
|
||||
pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId + Copy) {
|
||||
self.inputs.iter_mut().for_each(|id| *id = f(*id));
|
||||
self.outputs.iter_mut().for_each(|output| output.node_id = f(output.node_id));
|
||||
self.imports.iter_mut().for_each(|id| *id = f(*id));
|
||||
self.exports.iter_mut().for_each(|output| output.node_id = f(output.node_id));
|
||||
self.disabled.iter_mut().for_each(|id| *id = f(*id));
|
||||
self.previous_outputs
|
||||
.iter_mut()
|
||||
|
@ -875,7 +877,7 @@ impl NodeNetwork {
|
|||
|
||||
/// Replace all references in any node of `old_output` with `new_output`
|
||||
fn replace_network_outputs(&mut self, old_output: NodeOutput, new_output: NodeOutput) {
|
||||
for output in self.outputs.iter_mut() {
|
||||
for output in self.exports.iter_mut() {
|
||||
if *output == old_output {
|
||||
*output = new_output;
|
||||
}
|
||||
|
@ -886,7 +888,7 @@ impl NodeNetwork {
|
|||
pub fn remove_dead_nodes(&mut self) -> Vec<bool> {
|
||||
// Take all the nodes out of the nodes list
|
||||
let mut old_nodes = std::mem::take(&mut self.nodes);
|
||||
let mut stack = self.outputs.iter().map(|output| output.node_id).collect::<Vec<_>>();
|
||||
let mut stack = self.exports.iter().map(|output| output.node_id).collect::<Vec<_>>();
|
||||
while let Some(node_id) = stack.pop() {
|
||||
let Some((node_id, mut document_node)) = old_nodes.remove_entry(&node_id) else {
|
||||
continue;
|
||||
|
@ -909,9 +911,9 @@ impl NodeNetwork {
|
|||
}
|
||||
|
||||
// Check if inputs are used and store for return value
|
||||
let are_inputs_used = self.inputs.iter().map(|input| self.nodes.contains_key(input)).collect();
|
||||
let are_inputs_used = self.imports.iter().map(|input| self.nodes.contains_key(input)).collect();
|
||||
// Remove unused inputs from graph
|
||||
self.inputs.retain(|input| self.nodes.contains_key(input));
|
||||
self.imports.retain(|input| self.nodes.contains_key(input));
|
||||
|
||||
are_inputs_used
|
||||
}
|
||||
|
@ -986,21 +988,21 @@ impl NodeNetwork {
|
|||
let mut network_offsets = HashMap::new();
|
||||
assert_eq!(
|
||||
node.inputs.len(),
|
||||
inner_network.inputs.len(),
|
||||
inner_network.imports.len(),
|
||||
"\n\nThe number of inputs to the node and the inner network must be the same for \"{}\". The node has {} inputs, the network has {} inputs.\n\nNode inputs:\n\n{:?}\n\nNetwork inputs:\n\n{:?}\n",
|
||||
node.name,
|
||||
node.inputs.len(),
|
||||
inner_network.inputs.len(),
|
||||
inner_network.imports.len(),
|
||||
node.inputs,
|
||||
inner_network.inputs
|
||||
inner_network.imports
|
||||
);
|
||||
assert_eq!(
|
||||
node.inputs.len(),
|
||||
inner_network.inputs.len(),
|
||||
inner_network.imports.len(),
|
||||
"Document Nodes with a Network implementation should have the same number of inner network inputs as inputs declared on the Document Node"
|
||||
);
|
||||
// Match the document node input and the inputs of the inner network
|
||||
for (input_index, (document_input, network_input)) in node.inputs.into_iter().zip(inner_network.inputs.iter()).enumerate() {
|
||||
for (input_index, (document_input, network_input)) in node.inputs.into_iter().zip(inner_network.imports.iter()).enumerate() {
|
||||
// Keep track of how many network inputs we have already connected for each node
|
||||
let offset = network_offsets.entry(network_input).or_insert(0);
|
||||
match document_input {
|
||||
|
@ -1012,8 +1014,8 @@ impl NodeNetwork {
|
|||
}
|
||||
NodeInput::Network(_) => {
|
||||
*network_offsets.get_mut(network_input).unwrap() += 1;
|
||||
if let Some(index) = self.inputs.iter().position(|i| *i == id) {
|
||||
self.inputs[index] = *network_input;
|
||||
if let Some(index) = self.imports.iter().position(|i| *i == id) {
|
||||
self.imports[index] = *network_input;
|
||||
}
|
||||
}
|
||||
NodeInput::Value { .. } => unreachable!("Value inputs should have been replaced with value nodes"),
|
||||
|
@ -1022,7 +1024,7 @@ impl NodeNetwork {
|
|||
}
|
||||
|
||||
// Connect all nodes that were previously connected to this node to the nodes of the inner network
|
||||
for (i, output) in inner_network.outputs.into_iter().enumerate() {
|
||||
for (i, output) in inner_network.exports.into_iter().enumerate() {
|
||||
let node_input = |node_id, output_index, lambda| NodeInput::Node { node_id, output_index, lambda };
|
||||
|
||||
self.replace_node_inputs(node_input(id, i, false), node_input(output.node_id, output.node_output_index, false));
|
||||
|
@ -1082,7 +1084,7 @@ impl NodeNetwork {
|
|||
for NodeOutput {
|
||||
ref mut node_id,
|
||||
ref mut node_output_index,
|
||||
} in self.outputs.iter_mut()
|
||||
} in self.exports.iter_mut()
|
||||
{
|
||||
if *node_id == id {
|
||||
*node_id = input_node_id;
|
||||
|
@ -1199,8 +1201,8 @@ impl NodeNetwork {
|
|||
nodes.sort_unstable_by_key(|(i, _)| *i);
|
||||
|
||||
// Create a network to evaluate each output
|
||||
self.outputs.into_iter().map(move |output| ProtoNetwork {
|
||||
inputs: self.inputs.clone(),
|
||||
self.exports.into_iter().map(move |output| ProtoNetwork {
|
||||
inputs: self.imports.clone(),
|
||||
output: output.node_id,
|
||||
nodes: nodes.clone(),
|
||||
})
|
||||
|
@ -1244,8 +1246,8 @@ mod test {
|
|||
|
||||
fn add_network() -> NodeNetwork {
|
||||
NodeNetwork {
|
||||
inputs: vec![NodeId(0), NodeId(0)],
|
||||
outputs: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
imports: vec![NodeId(0), NodeId(0)],
|
||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
nodes: [
|
||||
(
|
||||
NodeId(0),
|
||||
|
@ -1277,8 +1279,8 @@ mod test {
|
|||
let mut network = add_network();
|
||||
network.map_ids(|id| NodeId(id.0 + 1));
|
||||
let mapped_add = NodeNetwork {
|
||||
inputs: vec![NodeId(1), NodeId(1)],
|
||||
outputs: vec![NodeOutput::new(NodeId(2), 0)],
|
||||
imports: vec![NodeId(1), NodeId(1)],
|
||||
exports: vec![NodeOutput::new(NodeId(2), 0)],
|
||||
nodes: [
|
||||
(
|
||||
NodeId(1),
|
||||
|
@ -1316,8 +1318,8 @@ mod test {
|
|||
};
|
||||
// TODO: Extend test cases to test nested network
|
||||
let mut extraction_network = NodeNetwork {
|
||||
inputs: vec![],
|
||||
outputs: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
imports: vec![],
|
||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
nodes: [
|
||||
id_node.clone(),
|
||||
DocumentNode {
|
||||
|
@ -1343,8 +1345,8 @@ mod test {
|
|||
#[test]
|
||||
fn flatten_add() {
|
||||
let mut network = NodeNetwork {
|
||||
inputs: vec![NodeId(1)],
|
||||
outputs: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
imports: vec![NodeId(1)],
|
||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
||||
nodes: [(
|
||||
NodeId(1),
|
||||
DocumentNode {
|
||||
|
@ -1446,8 +1448,8 @@ mod test {
|
|||
|
||||
fn flat_network() -> NodeNetwork {
|
||||
NodeNetwork {
|
||||
inputs: vec![NodeId(10)],
|
||||
outputs: vec![NodeOutput::new(NodeId(11), 0)],
|
||||
imports: vec![NodeId(10)],
|
||||
exports: vec![NodeOutput::new(NodeId(11), 0)],
|
||||
nodes: [
|
||||
(
|
||||
NodeId(10),
|
||||
|
@ -1509,8 +1511,8 @@ mod test {
|
|||
|
||||
fn two_node_identity() -> NodeNetwork {
|
||||
NodeNetwork {
|
||||
inputs: vec![NodeId(1), NodeId(2)],
|
||||
outputs: vec![NodeOutput::new(NodeId(1), 0), NodeOutput::new(NodeId(2), 0)],
|
||||
imports: vec![NodeId(1), NodeId(2)],
|
||||
exports: vec![NodeOutput::new(NodeId(1), 0), NodeOutput::new(NodeId(2), 0)],
|
||||
nodes: [
|
||||
(
|
||||
NodeId(1),
|
||||
|
@ -1539,8 +1541,8 @@ mod test {
|
|||
|
||||
fn output_duplicate(network_outputs: Vec<NodeOutput>, result_node_input: NodeInput) -> NodeNetwork {
|
||||
let mut network = NodeNetwork {
|
||||
inputs: Vec::new(),
|
||||
outputs: network_outputs,
|
||||
imports: Vec::new(),
|
||||
exports: network_outputs,
|
||||
nodes: [
|
||||
(
|
||||
NodeId(1),
|
||||
|
@ -1576,8 +1578,8 @@ mod test {
|
|||
fn simple_duplicate() {
|
||||
let result = output_duplicate(vec![NodeOutput::new(NodeId(1), 0)], NodeInput::node(NodeId(1), 0));
|
||||
println!("{result:#?}");
|
||||
assert_eq!(result.outputs.len(), 1, "The number of outputs should remain as 1");
|
||||
assert_eq!(result.outputs[0], NodeOutput::new(NodeId(11), 0), "The outer network output should be from a duplicated inner network");
|
||||
assert_eq!(result.exports.len(), 1, "The number of outputs should remain as 1");
|
||||
assert_eq!(result.exports[0], NodeOutput::new(NodeId(11), 0), "The outer network output should be from a duplicated inner network");
|
||||
let mut ids = result.nodes.keys().copied().collect::<Vec<_>>();
|
||||
ids.sort();
|
||||
assert_eq!(ids, vec![NodeId(11), NodeId(10010)], "Should only contain identity and values");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue