Rename NodeNetwork inputs/outputs to imports/exports

This commit is contained in:
Keavon Chambers
2024-03-10 22:45:22 -07:00
parent 137853eb40
commit fd54cda445
17 changed files with 166 additions and 164 deletions

View File

@@ -37,8 +37,8 @@ fn main() {
fn add_network() -> NodeNetwork {
NodeNetwork {
inputs: vec![],
outputs: vec![NodeOutput::new(NodeId(0), 0)],
imports: vec![],
exports: vec![NodeOutput::new(NodeId(0), 0)],
disabled: vec![],
previous_outputs: None,
nodes: [DocumentNode {

View File

@@ -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");

View File

@@ -30,7 +30,7 @@ impl Compiler {
Ok(proto_networks_result.into_iter())
}
pub fn compile_single(&self, network: NodeNetwork) -> Result<ProtoNetwork, String> {
assert_eq!(network.outputs.len(), 1, "Graph with multiple outputs not yet handled");
assert_eq!(network.exports.len(), 1, "Graph with multiple outputs not yet handled");
let Some(proto_network) = self.compile(network)?.next() else {
return Err("Failed to convert graph into proto graph".to_string());
};

View File

@@ -114,7 +114,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
}
}
let len = network_inputs.len();
network.inputs = network_inputs;
network.imports = network_inputs;
// if the network has no inputs, it doesn't need to be wrapped in a scope
if len == 0 {
@@ -140,8 +140,8 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
},
];
NodeNetwork {
inputs: vec![NodeId(0)],
outputs: vec![NodeOutput::new(NodeId(2), 0)],
imports: vec![NodeId(0)],
exports: vec![NodeOutput::new(NodeId(2), 0)],
nodes: nodes.into_iter().enumerate().map(|(id, node)| (NodeId(id as u64), node)).collect(),
..Default::default()
}
@@ -151,8 +151,8 @@ fn begin_scope() -> DocumentNode {
DocumentNode {
name: "Begin Scope".to_string(),
implementation: DocumentNodeImplementation::Network(NodeNetwork {
inputs: vec![NodeId(0)],
outputs: vec![NodeOutput::new(NodeId(1), 0), NodeOutput::new(NodeId(2), 0)],
imports: vec![NodeId(0)],
exports: vec![NodeOutput::new(NodeId(1), 0), NodeOutput::new(NodeId(2), 0)],
nodes: [
DocumentNode {
name: "SetNode".to_string(),

View File

@@ -169,11 +169,11 @@ async fn create_compute_pass_descriptor<T: Clone + Pixel + StaticTypeSized>(
log::debug!("inner_network: {inner_network:?}");
let network = NodeNetwork {
inputs: vec![NodeId(2), NodeId(1)], //vec![0, 1],
imports: vec![NodeId(2), NodeId(1)], //vec![0, 1],
#[cfg(feature = "quantization")]
outputs: vec![NodeOutput::new(NodeId(5), 0)],
exports: vec![NodeOutput::new(NodeId(5), 0)],
#[cfg(not(feature = "quantization"))]
outputs: vec![NodeOutput::new(NodeId(3), 0)],
exports: vec![NodeOutput::new(NodeId(3), 0)],
nodes: [
DocumentNode {
name: "Slice".into(),
@@ -434,8 +434,8 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
let compiler = graph_craft::graphene_compiler::Compiler {};
let network = NodeNetwork {
inputs: vec![],
outputs: vec![NodeOutput::new(NodeId(0), 0)],
imports: vec![],
exports: vec![NodeOutput::new(NodeId(0), 0)],
nodes: [DocumentNode {
name: "BlendOp".into(),
inputs: vec![NodeInput::Inline(InlineRust::new(

View File

@@ -16,8 +16,8 @@ mod tests {
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),
@@ -45,8 +45,8 @@ mod tests {
}
let network = NodeNetwork {
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 {
@@ -86,8 +86,8 @@ mod tests {
use graph_craft::*;
let 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: [
// Simple identity node taking a number as input from outside the graph
(