From 4ec600957c5e0964bf02fbbdfb34a59bf3c5cf28 Mon Sep 17 00:00:00 2001 From: TrueDoctor Date: Wed, 26 Oct 2022 00:45:42 +0200 Subject: [PATCH] Node graph dynamic execution (#824) Restructure document node implementation * Implement topological sort * Enforce the usage of type annotations * Add complete test case --- Cargo.lock | 2 +- node-graph/gcore/src/ops.rs | 59 ++-- node-graph/gcore/src/raster/color.rs | 4 +- node-graph/graph-craft/Cargo.toml | 1 + .../{gstd => graph-craft}/src/document.rs | 331 +++++------------- node-graph/graph-craft/src/document/value.rs | 74 ++++ node-graph/graph-craft/src/lib.rs | 122 ++++--- node-graph/graph-craft/src/node_registry.rs | 217 +++++++++--- node-graph/graph-craft/src/proto.rs | 231 ++++++++++++ node-graph/gstd/Cargo.toml | 1 - node-graph/gstd/src/any.rs | 2 +- node-graph/gstd/src/lib.rs | 2 - 12 files changed, 662 insertions(+), 384 deletions(-) rename node-graph/{gstd => graph-craft}/src/document.rs (50%) create mode 100644 node-graph/graph-craft/src/document/value.rs create mode 100644 node-graph/graph-craft/src/proto.rs diff --git a/Cargo.lock b/Cargo.lock index 78c7a618..7232e604 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -359,6 +359,7 @@ dependencies = [ "graphene-core", "graphene-std", "num-traits", + "rand_chacha", ] [[package]] @@ -395,7 +396,6 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "rand_chacha", "syn", ] diff --git a/node-graph/gcore/src/ops.rs b/node-graph/gcore/src/ops.rs index bb51a4db..a8f82a06 100644 --- a/node-graph/gcore/src/ops.rs +++ b/node-graph/gcore/src/ops.rs @@ -30,17 +30,21 @@ impl<'n, L: Add + 'n + Copy, R: Copy, O: 'n> Node<&'n (L, R)> for } } -// Unfortunatly we can't impl the AddNode as we get -// `upstream crates may add a new impl of trait `core::ops::Add` for type `alloc::boxed::Box<(dyn dyn_any::DynAny<'_> + 'static)>` in future versions` -pub struct DynamicAddNode; +#[cfg(feature = "std")] +pub mod dynamic { + use super::*; -// Alias for a dynamic type -pub type Dynamic<'a> = alloc::boxed::Box + 'a>; + // Unfortunatly we can't impl the AddNode as we get + // `upstream crates may add a new impl of trait `core::ops::Add` for type `alloc::boxed::Box<(dyn dyn_any::DynAny<'_> + 'static)>` in future versions` + pub struct DynamicAddNode; -/// Resolves the dynamic types for a dynamic node. -/// -/// Macro uses format `BaseNode => (arg1: u32) (arg1: i32)` -macro_rules! resolve_dynamic_types { + // Alias for a dynamic type + pub type Dynamic<'a> = alloc::boxed::Box + 'a>; + + /// Resolves the dynamic types for a dynamic node. + /// + /// Macro uses format `BaseNode => (arg1: u32) (arg1: i32)` + macro_rules! resolve_dynamic_types { ($node:ident => $(($($arg:ident : $t:ty),*))*) => { $( // Check for each possible set of arguments if their types match the arguments given @@ -55,24 +59,25 @@ macro_rules! resolve_dynamic_types { }; } -impl<'n> Node<(Dynamic<'n>, Dynamic<'n>)> for DynamicAddNode { - type Output = Dynamic<'n>; - fn eval(self, (left, right): (Dynamic, Dynamic)) -> Self::Output { - resolve_dynamic_types! { AddNode => - (left: usize, right: usize) - (left: u8, right: u8) - (left: u16, right: u16) - (left: u32, right: u32) - (left: u64, right: u64) - (left: u128, right: u128) - (left: isize, right: isize) - (left: i8, right: i8) - (left: i16, right: i16) - (left: i32, right: i32) - (left: i64, right: i64) - (left: i128, right: i128) - (left: f32, right: f32) - (left: f64, right: f64) } + impl<'n> Node<(Dynamic<'n>, Dynamic<'n>)> for DynamicAddNode { + type Output = Dynamic<'n>; + fn eval(self, (left, right): (Dynamic, Dynamic)) -> Self::Output { + resolve_dynamic_types! { AddNode => + (left: usize, right: usize) + (left: u8, right: u8) + (left: u16, right: u16) + (left: u32, right: u32) + (left: u64, right: u64) + (left: u128, right: u128) + (left: isize, right: isize) + (left: i8, right: i8) + (left: i16, right: i16) + (left: i32, right: i32) + (left: i64, right: i64) + (left: i128, right: i128) + (left: f32, right: f32) + (left: f64, right: f64) } + } } } diff --git a/node-graph/gcore/src/raster/color.rs b/node-graph/gcore/src/raster/color.rs index 2eb011cd..64e7ae94 100644 --- a/node-graph/gcore/src/raster/color.rs +++ b/node-graph/gcore/src/raster/color.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "std")] use dyn_any::{DynAny, StaticType}; use serde::{Deserialize, Serialize}; @@ -6,7 +7,8 @@ use serde::{Deserialize, Serialize}; /// The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`, /// the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color. #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize, DynAny)] +#[cfg_attr(feature = "std", derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize, DynAny))] +#[cfg_attr(not(feature = "std"), derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize))] pub struct Color { red: f32, green: f32, diff --git a/node-graph/graph-craft/Cargo.toml b/node-graph/graph-craft/Cargo.toml index 03bb6145..0c3eeb6b 100644 --- a/node-graph/graph-craft/Cargo.toml +++ b/node-graph/graph-craft/Cargo.toml @@ -13,3 +13,4 @@ dyn-any = { path = "../../libraries/dyn-any" } num-traits = "0.2" borrow_stack = { path = "../borrow_stack" } dyn-clone = "1.0" +rand_chacha = "0.3.1" diff --git a/node-graph/gstd/src/document.rs b/node-graph/graph-craft/src/document.rs similarity index 50% rename from node-graph/gstd/src/document.rs rename to node-graph/graph-craft/src/document.rs index 50f22c3d..07caa2e0 100644 --- a/node-graph/gstd/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -1,15 +1,15 @@ +use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNetwork, ProtoNode, ProtoNodeInput, Type}; use std::collections::HashMap; -use std::fmt::Display; use std::sync::Mutex; -use dyn_any::{DynAny, StaticType}; -use dyn_clone::DynClone; +pub mod value; + use rand_chacha::{ rand_core::{RngCore, SeedableRng}, ChaCha20Rng, }; -type NodeId = u64; +pub type NodeId = u64; static RNG: Mutex> = Mutex::new(None); pub fn generate_uuid() -> u64 { @@ -20,14 +20,6 @@ pub fn generate_uuid() -> u64 { lock.as_mut().map(ChaCha20Rng::next_u64).unwrap() } -fn gen_node_id() -> NodeId { - static mut NODE_ID: NodeId = 3; - unsafe { - NODE_ID += 1; - NODE_ID - } -} - fn merge_ids(a: u64, b: u64) -> u64 { use std::hash::{Hash, Hasher}; let mut hasher = std::collections::hash_map::DefaultHasher::new(); @@ -36,6 +28,8 @@ fn merge_ids(a: u64, b: u64) -> u64 { hasher.finish() } +type Fqn = NodeIdentifier<'static>; + #[derive(Debug, PartialEq)] pub struct DocumentNode { pub name: String, @@ -57,35 +51,33 @@ impl DocumentNode { self.inputs[index] = NodeInput::Node(node); } - fn resolve_proto_nodes(&mut self) { + fn resolve_proto_node(mut self) -> ProtoNode { let first = self.inputs.remove(0); - if let DocumentNodeImplementation::ProtoNode(proto) = &mut self.implementation { - match first { + if let DocumentNodeImplementation::Unresolved(fqn) = self.implementation { + let (input, mut args) = match first { NodeInput::Value(value) => { - proto.input = ProtoNodeInput::None; - proto.construction_args = ConstructionArgs::Value(value); assert_eq!(self.inputs.len(), 0); - return; + (ProtoNodeInput::None, ConstructionArgs::Value(value)) } - NodeInput::Node(id) => proto.input = ProtoNodeInput::Node(id), - NodeInput::Network => proto.input = ProtoNodeInput::Network, - } - assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network)), "recived non resolved parameter"); + NodeInput::Node(id) => (ProtoNodeInput::Node(id), ConstructionArgs::Nodes(vec![])), + NodeInput::Network => (ProtoNodeInput::Network, ConstructionArgs::Nodes(vec![])), + }; + assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network)), "recieved non resolved parameter"); assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Value(_))), "recieved value as parameter"); - let nodes: Vec<_> = self - .inputs - .iter() - .filter_map(|input| match input { - NodeInput::Node(id) => Some(*id), - _ => None, - }) - .collect(); - match nodes { - vec if vec.is_empty() => proto.construction_args = ConstructionArgs::None, - vec => proto.construction_args = ConstructionArgs::Nodes(vec), + if let ConstructionArgs::Nodes(nodes) = &mut args { + nodes.extend(self.inputs.iter().map(|input| match input { + NodeInput::Node(id) => *id, + _ => unreachable!(), + })); } - self.inputs = vec![]; + ProtoNode { + identifier: fqn, + input, + construction_args: args, + } + } else { + unreachable!("tried to resolve not flattened node on resolved node"); } } } @@ -93,10 +85,18 @@ impl DocumentNode { #[derive(Debug)] pub enum NodeInput { Node(NodeId), - Value(Value), + Value(value::Value), Network, } +impl NodeInput { + fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId) { + if let NodeInput::Node(id) = self { + *self = NodeInput::Node(f(*id)) + } + } +} + impl PartialEq for NodeInput { fn eq(&self, other: &Self) -> bool { match (&self, &other) { @@ -110,7 +110,7 @@ impl PartialEq for NodeInput { #[derive(Debug, PartialEq)] pub enum DocumentNodeImplementation { Network(NodeNetwork), - ProtoNode(ProtoNode), + Unresolved(Fqn), } #[derive(Debug, Default, PartialEq)] @@ -119,127 +119,6 @@ pub struct NodeNetwork { pub output: NodeId, pub nodes: HashMap, } -pub type Value = Box; -pub trait ValueTrait: DynAny<'static> + std::fmt::Debug + DynClone {} - -pub trait IntoValue: Sized + ValueTrait + 'static { - fn into_any(self) -> Value { - Box::new(self) - } -} -impl ValueTrait for T {} -impl IntoValue for T {} - -#[repr(C)] -struct Vtable { - destructor: unsafe fn(*mut ()), - size: usize, - align: usize, -} - -#[repr(C)] -struct TraitObject { - self_ptr: *mut u8, - vtable: &'static Vtable, -} - -impl PartialEq for Box { - fn eq(&self, other: &Self) -> bool { - if self.type_id() != other.type_id() { - return false; - } - let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) }; - let other_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(other.as_ref()) }; - let size = self_trait_object.vtable.size; - let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }; - let other_mem = unsafe { std::slice::from_raw_parts(other_trait_object.self_ptr, size) }; - self_mem == other_mem - } -} - -impl Clone for Value { - fn clone(&self) -> Self { - let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) }; - let size = self_trait_object.vtable.size; - let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }.to_owned(); - let ptr = Vec::leak(self_mem); - unsafe { - std::mem::transmute(TraitObject { - self_ptr: ptr as *mut [u8] as *mut u8, - vtable: self_trait_object.vtable, - }) - } - } -} -#[derive(Debug, Default)] -pub enum ConstructionArgs { - None, - #[default] - Unresolved, - Value(Value), - Nodes(Vec), -} - -impl PartialEq for ConstructionArgs { - fn eq(&self, other: &Self) -> bool { - match (&self, &other) { - (Self::Nodes(n1), Self::Nodes(n2)) => n1 == n2, - (Self::Value(v1), Self::Value(v2)) => v1 == v2, - _ => core::mem::discriminant(self) == core::mem::discriminant(other), - } - } -} - -#[derive(Debug, Default, PartialEq)] -pub struct ProtoNode { - pub construction_args: ConstructionArgs, - pub input: ProtoNodeInput, - pub name: String, -} - -#[derive(Debug, Default, PartialEq, Eq)] -pub enum ProtoNodeInput { - None, - #[default] - Network, - Node(NodeId), -} - -impl NodeInput { - fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId) { - if let NodeInput::Node(id) = self { - *self = NodeInput::Node(f(*id)) - } - } -} - -impl ProtoNodeInput { - pub fn unwrap_node(self) -> NodeId { - match self { - ProtoNodeInput::Node(id) => id, - _ => panic!("tried to unwrap id from non node input"), - } - } -} - -impl ProtoNode { - pub fn id() -> Self { - Self { - name: "id".into(), - ..Default::default() - } - } - pub fn unresolved(name: String) -> Self { - Self { name, ..Default::default() } - } - pub fn value(name: String, value: ConstructionArgs) -> Self { - Self { - name, - construction_args: value, - ..Default::default() - } - } -} impl NodeNetwork { pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId + Copy) { @@ -286,7 +165,7 @@ impl NodeNetwork { let value_node = DocumentNode { name: name.clone(), inputs: vec![NodeInput::Value(value)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("value".into())), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic])), }; assert!(!self.nodes.contains_key(&new_id)); self.nodes.insert(new_id, value_node); @@ -301,50 +180,41 @@ impl NodeNetwork { } } } - node.implementation = DocumentNodeImplementation::ProtoNode(ProtoNode::id()); + node.implementation = DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic])); node.inputs = vec![NodeInput::Node(inner_network.output)]; for node_id in new_nodes { self.flatten_with_fns(node_id, map_ids, gen_id); } } - DocumentNodeImplementation::ProtoNode(proto_node) => { - node.implementation = DocumentNodeImplementation::ProtoNode(proto_node); - } + DocumentNodeImplementation::Unresolved(_) => (), } assert!(!self.nodes.contains_key(&id), "Trying to insert a node into the network caused an id conflict"); self.nodes.insert(id, node); } - pub fn resolve_proto_nodes(&mut self) { - for node in self.nodes.values_mut() { - node.resolve_proto_nodes(); + pub fn into_proto_network(self) -> ProtoNetwork { + let mut nodes: Vec<_> = self.nodes.into_iter().map(|(id, node)| (id, node.resolve_proto_node())).collect(); + nodes.sort_unstable_by_key(|(i, _)| *i); + ProtoNetwork { + inputs: self.inputs, + output: self.output, + nodes, } } } -struct Map(core::marker::PhantomData<(I, O)>); - -impl Display for Map<(), O> { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!(f, "Map") - } -} - -impl Display for Map { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!(f, "Map") - } -} - #[cfg(test)] mod test { use super::*; + use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNetwork, ProtoNode, ProtoNodeInput}; + use value::IntoValue; - #[test] - fn test_any_src() { - assert!(2_u32.into_any() == 2_u32.into_any()); - assert!(2_u32.into_any() != 3_u32.into_any()); - assert!(2_u32.into_any() != 3_i32.into_any()); + fn gen_node_id() -> NodeId { + static mut NODE_ID: NodeId = 3; + unsafe { + NODE_ID += 1; + NODE_ID + } } fn add_network() -> NodeNetwork { @@ -357,7 +227,7 @@ mod test { DocumentNode { name: "cons".into(), inputs: vec![NodeInput::Network, NodeInput::Network], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("cons".into())), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])), }, ), ( @@ -365,7 +235,7 @@ mod test { DocumentNode { name: "add".into(), inputs: vec![NodeInput::Node(0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("add".into())), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])), }, ), ] @@ -387,7 +257,7 @@ mod test { DocumentNode { name: "cons".into(), inputs: vec![NodeInput::Network, NodeInput::Network], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::value("cons".into(), ConstructionArgs::Unresolved)), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])), }, ), ( @@ -395,7 +265,7 @@ mod test { DocumentNode { name: "add".into(), inputs: vec![NodeInput::Node(1)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::value("add".into(), ConstructionArgs::Unresolved)), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])), }, ), ] @@ -431,85 +301,58 @@ mod test { #[test] fn resolve_proto_node_add() { - let mut d_node = DocumentNode { + let document_node = DocumentNode { name: "cons".into(), inputs: vec![NodeInput::Network, NodeInput::Node(0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::value("cons".into(), ConstructionArgs::Unresolved)), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])), }; - d_node.resolve_proto_nodes(); - let reference = DocumentNode { - name: "cons".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { - name: "cons".into(), - input: ProtoNodeInput::Network, - construction_args: ConstructionArgs::Nodes(vec![0]), - }), + let proto_node = document_node.resolve_proto_node(); + let reference = ProtoNode { + identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic]), + input: ProtoNodeInput::Network, + construction_args: ConstructionArgs::Nodes(vec![0]), }; - assert_eq!(d_node, reference); + assert_eq!(proto_node, reference); } #[test] - fn resolve_flatten_add() { - let construction_network = NodeNetwork { + fn resolve_flatten_add_as_proto_network() { + let construction_network = ProtoNetwork { inputs: vec![10], output: 1, nodes: [ ( 1, - DocumentNode { - name: "Inc".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { - name: "id".into(), - input: ProtoNodeInput::Node(11), - construction_args: ConstructionArgs::None, - }), + ProtoNode { + identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic]), + input: ProtoNodeInput::Node(11), + construction_args: ConstructionArgs::Nodes(vec![]), }, ), ( 10, - DocumentNode { - name: "cons".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { - name: "cons".into(), - input: ProtoNodeInput::Network, - construction_args: ConstructionArgs::Nodes(vec![14]), - }), + ProtoNode { + identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic]), + input: ProtoNodeInput::Network, + construction_args: ConstructionArgs::Nodes(vec![14]), }, ), ( 11, - DocumentNode { - name: "add".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { - name: "add".into(), - input: ProtoNodeInput::Node(10), - construction_args: ConstructionArgs::None, - }), - }, - ), - ( - 14, - DocumentNode { - name: "Value: 2".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { - name: "value".into(), - input: ProtoNodeInput::None, - construction_args: ConstructionArgs::Value(2_u32.into_any()), - }), + ProtoNode { + identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic]), + input: ProtoNodeInput::Node(10), + construction_args: ConstructionArgs::Nodes(vec![]), }, ), + (14, ProtoNode::value(ConstructionArgs::Value(2_u32.into_any()))), ] .into_iter() .collect(), }; - let mut resolved_network = flat_network(); - resolved_network.resolve_proto_nodes(); + let network = flat_network(); + let resolved_network = network.into_proto_network(); println!("{:#?}", resolved_network); println!("{:#?}", construction_network); @@ -526,7 +369,7 @@ mod test { DocumentNode { name: "Inc".into(), inputs: vec![NodeInput::Node(11)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::id()), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic])), }, ), ( @@ -534,7 +377,7 @@ mod test { DocumentNode { name: "cons".into(), inputs: vec![NodeInput::Network, NodeInput::Node(14)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("cons".into())), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])), }, ), ( @@ -542,7 +385,7 @@ mod test { DocumentNode { name: "Value: 2".into(), inputs: vec![NodeInput::Value(2_u32.into_any())], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("value".into())), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic])), }, ), ( @@ -550,7 +393,7 @@ mod test { DocumentNode { name: "add".into(), inputs: vec![NodeInput::Node(10)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("add".into())), + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])), }, ), ] diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs new file mode 100644 index 00000000..5dfb03ee --- /dev/null +++ b/node-graph/graph-craft/src/document/value.rs @@ -0,0 +1,74 @@ +use dyn_any::StaticType; + +use dyn_clone::DynClone; + +use dyn_any::DynAny; + +pub type Value = Box; + +pub trait ValueTrait: DynAny<'static> + std::fmt::Debug + DynClone {} + +pub trait IntoValue: Sized + ValueTrait + 'static { + fn into_any(self) -> Value { + Box::new(self) + } +} + +impl ValueTrait for T {} + +impl IntoValue for T {} + +#[repr(C)] +pub(crate) struct Vtable { + pub(crate) destructor: unsafe fn(*mut ()), + pub(crate) size: usize, + pub(crate) align: usize, +} + +#[repr(C)] +pub(crate) struct TraitObject { + pub(crate) self_ptr: *mut u8, + pub(crate) vtable: &'static Vtable, +} + +impl PartialEq for Box { + #[cfg_attr(miri, ignore)] + fn eq(&self, other: &Self) -> bool { + if self.type_id() != other.type_id() { + return false; + } + let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) }; + let other_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(other.as_ref()) }; + let size = self_trait_object.vtable.size; + let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }; + let other_mem = unsafe { std::slice::from_raw_parts(other_trait_object.self_ptr, size) }; + self_mem == other_mem + } +} + +impl Clone for Value { + fn clone(&self) -> Self { + let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) }; + let size = self_trait_object.vtable.size; + let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }.to_owned(); + let ptr = Vec::leak(self_mem); + unsafe { + std::mem::transmute(TraitObject { + self_ptr: ptr as *mut [u8] as *mut u8, + vtable: self_trait_object.vtable, + }) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_any_src() { + assert!(2_u32.into_any() == 2_u32.into_any()); + assert!(2_u32.into_any() != 3_u32.into_any()); + assert!(2_u32.into_any() != 3_i32.into_any()); + } +} diff --git a/node-graph/graph-craft/src/lib.rs b/node-graph/graph-craft/src/lib.rs index 9bc2021f..718c6326 100644 --- a/node-graph/graph-craft/src/lib.rs +++ b/node-graph/graph-craft/src/lib.rs @@ -1,6 +1,9 @@ #![feature(trait_upcasting)] pub mod node_registry; +pub mod document; +pub mod proto; + #[cfg(test)] mod tests { @@ -9,7 +12,9 @@ mod tests { use graphene_core::value::ValueNode; use graphene_core::{structural::*, RefNode}; + use crate::document::value::IntoValue; use borrow_stack::BorrowStack; + use borrow_stack::FixedSizeStack; use dyn_any::{downcast, IntoDynAny}; use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode}; use graphene_std::ops::AddNode; @@ -27,7 +32,6 @@ mod tests { let dynanynode: DynAnyNode>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData)); dynanynode.into_box() }); - /* stack.push_fn(|_| { let dynanynode: DynAnyNode<_, (u32, &u32), _, _> = DynAnyNode::new(AddNode); dynanynode.into_box() @@ -35,79 +39,81 @@ mod tests { stack.push_fn(|nodes| { let compose_node = nodes[1].after(&nodes[2]); TypeErasedNode(Box::new(compose_node)) - });}*/ + }); let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn()); assert_eq!(*downcast::<&u32>(result).unwrap(), &2_u32); let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn()); assert_eq!(*downcast::<(u32, &u32)>(result).unwrap(), (4_u32, &2_u32)); - /* let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn()); let add = unsafe { &stack.get()[2] }.eval_ref(result); assert_eq!(*downcast::(add).unwrap(), 6_u32); let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn()); - assert_eq!(*downcast::(add).unwrap(), 6_u32);*/ + assert_eq!(*downcast::(add).unwrap(), 6_u32); } #[test] - fn craft_from_flattened() { - use graphene_std::document::*; - // This is input and evaluated - let construction_network = NodeNetwork { - inputs: vec![10], - output: 1, - nodes: [ - ( - 1, - DocumentNode { - name: "Inc".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { - name: "id".into(), - input: ProtoNodeInput::Node(11), - construction_args: ConstructionArgs::None, - }), - }, - ), - ( - 10, - DocumentNode { - name: "cons".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { + fn execute_add() { + use crate::document::*; + use crate::node_registry::push_node; + use crate::proto::*; + use graphene_core::Node; + + fn add_network() -> NodeNetwork { + NodeNetwork { + inputs: vec![0, 0], + output: 1, + nodes: [ + ( + 0, + DocumentNode { name: "cons".into(), - input: ProtoNodeInput::Network, - construction_args: ConstructionArgs::Nodes(vec![14]), - }), - }, - ), - ( - 11, - DocumentNode { - name: "add".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { + inputs: vec![NodeInput::Network, NodeInput::Network], + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Concrete("u32"), Type::Concrete("u32")])), + }, + ), + ( + 1, + DocumentNode { name: "add".into(), - input: ProtoNodeInput::Node(10), - construction_args: ConstructionArgs::None, - }), - }, - ), - ( - 14, - DocumentNode { - name: "Value: 2".into(), - inputs: vec![], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNode { - name: "value".into(), - input: ProtoNodeInput::None, - construction_args: ConstructionArgs::Value(2_u32.into_any()), - }), - }, - ), - ] + inputs: vec![NodeInput::Node(0)], + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Concrete("u32"), Type::Concrete("u32")])), + }, + ), + ] + .into_iter() + .collect(), + } + } + + let mut network = NodeNetwork { + inputs: vec![0], + output: 0, + nodes: [( + 0, + DocumentNode { + name: "Inc".into(), + inputs: vec![NodeInput::Network, NodeInput::Value(1_u32.into_any())], + implementation: DocumentNodeImplementation::Network(add_network()), + }, + )] .into_iter() .collect(), }; + + let stack = FixedSizeStack::new(256); + println!("flattening"); + network.flatten(0); + //println!("flat_network: {:#?}", network); + let mut proto_network = network.into_proto_network(); + proto_network.reorder_ids(); + //println!("reordered_ides: {:#?}", proto_network); + for (_id, node) in proto_network.nodes { + push_node(node, &stack); + } + + let result = unsafe { stack.get().last().unwrap().eval(32_u32.into_dyn()) }; + let val = *dyn_any::downcast::(result).unwrap(); + assert_eq!(val, 33_u32); } } diff --git a/node-graph/graph-craft/src/node_registry.rs b/node-graph/graph-craft/src/node_registry.rs index 0d82aa56..03c372c5 100644 --- a/node-graph/graph-craft/src/node_registry.rs +++ b/node-graph/graph-craft/src/node_registry.rs @@ -1,29 +1,39 @@ use std::marker::PhantomData; use borrow_stack::FixedSizeStack; -use dyn_clone::DynClone; use graphene_core::generic::FnNode; use graphene_core::ops::{AddNode, IdNode}; use graphene_core::raster::color::Color; use graphene_core::structural::{ConsNode, Then}; use graphene_core::{AsRefNode, Node}; use graphene_std::any::DowncastBothNode; +use graphene_std::any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode}; use graphene_std::raster::Image; -use graphene_std::{ - any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode}, - document::{ConstructionArgs, ProtoNode, ProtoNodeInput}, -}; -struct NodeIdentifier { - name: &'static str, - types: &'static [&'static str], -} +use crate::proto::Type; +use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNode, ProtoNodeInput, Type::Concrete}; -static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack>))] = &[ +type NodeConstructor = fn(ProtoNode, &FixedSizeStack>); + +//TODO: turn into hasmap +static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[ ( NodeIdentifier { name: "graphene_core::ops::IdNode", - types: &["Any<'n>"], + types: &[Concrete("Any<'_>")], + }, + |proto_node, stack| { + stack.push_fn(|nodes| { + let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap(); + let node = pre_node.then(graphene_core::ops::IdNode); + node.into_type_erased() + }) + }, + ), + ( + NodeIdentifier { + name: "graphene_core::ops::IdNode", + types: &[Type::Generic], }, |proto_node, stack| { stack.push_fn(|nodes| { @@ -36,7 +46,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack = DynAnyNode::new(graphene_core::ops::AddNode); + let node = (pre_node).then(node); + + node.into_type_erased() + }) + }, + ), + ( + NodeIdentifier { + name: "graphene_core::ops::AddNode", + types: &[Concrete("&u32"), Concrete("u32")], + }, + |proto_node, stack| { + stack.push_fn(|nodes| { + let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap(); + let node: DynAnyNode = DynAnyNode::new(graphene_core::ops::AddNode); + let node = (pre_node).then(node); + + node.into_type_erased() + }) + }, + ), ( NodeIdentifier { name: "graphene_core::structural::ConsNode", - types: &["&TypeErasedNode", "&u32", "u32"], + types: &[Concrete("&u32"), Concrete("u32")], + }, + |proto_node, stack| { + if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args { + stack.push_fn(move |nodes| { + let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap(); + + let cons_node = ConsNode::new(DowncastNode::<_, &u32>::new(cons_node_arg)); + let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node); + let node = match proto_node.input { + ProtoNodeInput::Network => node.into_type_erased(), + ProtoNodeInput::Node(node_id) => { + let pre_node = nodes.get(node_id as usize).unwrap(); + (pre_node).then(node).into_type_erased() + } + ProtoNodeInput::None => unreachable!(), + }; + node + }) + } else { + unimplemented!() + } + }, + ), + ( + NodeIdentifier { + name: "graphene_core::structural::ConsNode", + types: &[Concrete("u32"), Concrete("u32")], + }, + |proto_node, stack| { + if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args { + stack.push_fn(move |nodes| { + let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap(); + + let cons_node = ConsNode::new(DowncastNode::<_, u32>::new(cons_node_arg)); + let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node); + let node = match proto_node.input { + ProtoNodeInput::Network => node.into_type_erased(), + ProtoNodeInput::Node(node_id) => { + let pre_node = nodes.get(node_id as usize).unwrap(); + (pre_node).then(node).into_type_erased() + } + ProtoNodeInput::None => unreachable!(), + }; + node + }) + } else { + unimplemented!() + } + }, + ), + // TODO: create macro to impl for all types + ( + NodeIdentifier { + name: "graphene_core::structural::ConsNode", + types: &[Concrete("&u32"), Concrete("&u32")], }, |proto_node, stack| { let node_id = proto_node.input.unwrap_node() as usize; @@ -60,8 +155,8 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack::new(cons_node_arg)); - let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node); + let cons_node = ConsNode::new(DowncastNode::<_, &u32>::new(cons_node_arg)); + let node: DynAnyNode<_, &u32, _, _> = DynAnyNode::new(cons_node); let node = (pre_node).then(node); node.into_type_erased() }) @@ -73,7 +168,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack"], + types: &[Concrete("Any<'_>")], + }, + |proto_node, stack| { + stack.push_fn(|_nodes| { + if let ConstructionArgs::Value(value) = proto_node.construction_args { + let node = FnNode::new(move |_| value.clone() as Any<'static>); + node.into_type_erased() + } else { + unreachable!() + } + }) + }, + ), + ( + NodeIdentifier { + name: "graphene_core::value::ValueNode", + types: &[Type::Generic], }, |proto_node, stack| { stack.push_fn(|_nodes| { @@ -102,7 +213,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack>) { + if let Some((_id, f)) = NODE_REGISTRY.iter().find(|(id, _)| *id == proto_node.identifier) { + f(proto_node, stack); + } else { + panic!("NodeImplementation: {:?} not found in Registry", proto_node.identifier); + } +} + #[cfg(test)] mod protograph_testing { use borrow_stack::BorrowStack; @@ -208,25 +327,25 @@ mod protograph_testing { #[test] fn add_values() { let stack = FixedSizeStack::new(256); - let val_1_protonode = ProtoNode::value("name".to_string(), ConstructionArgs::Value(Box::new(2u32))); - simple_lookup("ValueNode").1(val_1_protonode, &stack); + let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(2u32))); + push_node(val_1_protonode, &stack); - let val_2_protonode = ProtoNode::value("name".to_string(), ConstructionArgs::Value(Box::new(40u32))); - simple_lookup("ValueNode").1(val_2_protonode, &stack); + let val_2_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(40u32))); + push_node(val_2_protonode, &stack); let cons_protonode = ProtoNode { construction_args: ConstructionArgs::Nodes(vec![1]), input: ProtoNodeInput::Node(0), - name: "todo!()".to_string(), + identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[Concrete("u32"), Concrete("u32")]), }; - simple_lookup("ConsNode").1(cons_protonode, &stack); + push_node(cons_protonode, &stack); let add_protonode = ProtoNode { - construction_args: ConstructionArgs::None, + construction_args: ConstructionArgs::Nodes(vec![]), input: ProtoNodeInput::Node(2), - name: "todo!()".to_string(), + identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Concrete("u32"), Concrete("u32")]), }; - simple_lookup("AddNode").1(add_protonode, &stack); + push_node(add_protonode, &stack); let result = unsafe { stack.get()[3].eval(Box::new(())) }; let val = *dyn_any::downcast::(result).unwrap(); @@ -236,15 +355,15 @@ mod protograph_testing { #[test] fn greyscale_colour() { let stack = FixedSizeStack::new(256); - let val_protonode = ProtoNode::value("name".to_string(), ConstructionArgs::Value(Box::new(Color::from_rgb8(10, 20, 30)))); - simple_lookup("ValueNode").1(val_protonode, &stack); + let val_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(Color::from_rgb8(10, 20, 30)))); + push_node(val_protonode, &stack); let greyscale_protonode = ProtoNode { - construction_args: ConstructionArgs::None, + construction_args: ConstructionArgs::Nodes(vec![]), input: ProtoNodeInput::Node(0), - name: "todo!()".to_string(), + identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]), }; - simple_lookup("GrayscaleNode").1(greyscale_protonode, &stack); + push_node(greyscale_protonode, &stack); let result = unsafe { stack.get()[1].eval(Box::new(())) }; let val = *dyn_any::downcast::(result).unwrap(); @@ -255,11 +374,11 @@ mod protograph_testing { fn load_image() { let stack = FixedSizeStack::new(256); let image_protonode = ProtoNode { - construction_args: ConstructionArgs::None, + construction_args: ConstructionArgs::Nodes(vec![]), input: ProtoNodeInput::None, - name: "todo!()".to_string(), + identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete("&str")]), }; - simple_lookup("image_node").1(image_protonode, &stack); + push_node(image_protonode, &stack); let result = unsafe { stack.get()[0].eval(Box::new("../gstd/test-image-1.png")) }; let image = *dyn_any::downcast::(result).unwrap(); @@ -270,25 +389,25 @@ mod protograph_testing { fn greyscale_map_image() { let stack = FixedSizeStack::new(256); let image_protonode = ProtoNode { - construction_args: ConstructionArgs::None, + construction_args: ConstructionArgs::Nodes(vec![]), input: ProtoNodeInput::None, - name: "todo!()".to_string(), + identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete("&str")]), }; - simple_lookup("image_node").1(image_protonode, &stack); + push_node(image_protonode, &stack); let greyscale_protonode = ProtoNode { - construction_args: ConstructionArgs::None, + construction_args: ConstructionArgs::Nodes(vec![]), input: ProtoNodeInput::None, - name: "todo!()".to_string(), + identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]), }; - simple_lookup("GrayscaleNode").1(greyscale_protonode, &stack); + push_node(greyscale_protonode, &stack); let image_map_protonode = ProtoNode { construction_args: ConstructionArgs::Nodes(vec![1]), input: ProtoNodeInput::Node(0), - name: "todo!()".to_string(), + identifier: NodeIdentifier::new("graphene_std::raster::MapImageNode", &[]), }; - simple_lookup("MapImageNode").1(image_map_protonode, &stack); + push_node(image_map_protonode, &stack); let result = unsafe { stack.get()[2].eval(Box::new("../gstd/test-image-1.png")) }; let image = *dyn_any::downcast::(result).unwrap(); diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs new file mode 100644 index 00000000..4ec92e24 --- /dev/null +++ b/node-graph/graph-craft/src/proto.rs @@ -0,0 +1,231 @@ +use std::collections::HashMap; +use std::collections::HashSet; + +use crate::document::value; +use crate::document::NodeId; + +#[derive(Debug, PartialEq)] +pub struct NodeIdentifier<'a> { + pub name: &'a str, + pub types: &'a [Type<'a>], +} + +#[derive(Debug, PartialEq)] +pub enum Type<'a> { + Generic, + Concrete(&'a str), +} + +impl<'a> From<&'a str> for Type<'a> { + fn from(s: &'a str) -> Self { + Type::Concrete(s) + } +} +impl<'a> From<&'a str> for NodeIdentifier<'a> { + fn from(s: &'a str) -> Self { + NodeIdentifier { name: s, types: &[] } + } +} + +impl<'a> NodeIdentifier<'a> { + pub fn new(name: &'a str, types: &'a [Type<'a>]) -> Self { + NodeIdentifier { name, types } + } +} + +#[derive(Debug, Default, PartialEq)] +pub struct ProtoNetwork { + pub inputs: Vec, + pub output: NodeId, + pub nodes: Vec<(NodeId, ProtoNode)>, +} + +#[derive(Debug)] +pub enum ConstructionArgs { + Value(value::Value), + Nodes(Vec), +} + +impl PartialEq for ConstructionArgs { + fn eq(&self, other: &Self) -> bool { + match (&self, &other) { + (Self::Nodes(n1), Self::Nodes(n2)) => n1 == n2, + (Self::Value(v1), Self::Value(v2)) => v1 == v2, + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } +} + +#[derive(Debug, PartialEq)] +pub struct ProtoNode { + pub construction_args: ConstructionArgs, + pub input: ProtoNodeInput, + pub identifier: NodeIdentifier<'static>, +} + +#[derive(Debug, Default, PartialEq, Eq)] +pub enum ProtoNodeInput { + None, + #[default] + Network, + Node(NodeId), +} + +impl ProtoNodeInput { + pub fn unwrap_node(self) -> NodeId { + match self { + ProtoNodeInput::Node(id) => id, + _ => panic!("tried to unwrap id from non node input \n node: {:#?}", self), + } + } +} + +impl ProtoNode { + pub fn value(value: ConstructionArgs) -> Self { + Self { + identifier: NodeIdentifier { + name: "graphene_core::value::ValueNode", + types: &[Type::Generic], + }, + construction_args: value, + input: ProtoNodeInput::None, + } + } + + pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId) { + if let ProtoNodeInput::Node(id) = self.input { + self.input = ProtoNodeInput::Node(f(id)) + } + if let ConstructionArgs::Nodes(ids) = &mut self.construction_args { + ids.iter_mut().for_each(|id| *id = f(*id)); + } + } + + pub fn unwrap_construction_nodes(&self) -> Vec { + match &self.construction_args { + ConstructionArgs::Nodes(nodes) => nodes.clone(), + _ => panic!("tried to unwrap nodes from non node construction args \n node: {:#?}", self), + } + } +} + +impl ProtoNetwork { + fn reverse_edges(&self) -> HashMap> { + let mut edges: HashMap> = HashMap::new(); + for (id, node) in &self.nodes { + if let ProtoNodeInput::Node(ref_id) = &node.input { + edges.entry(*id).or_default().push(*ref_id) + } + if let ConstructionArgs::Nodes(ref_nodes) = &node.construction_args { + for ref_id in ref_nodes { + edges.entry(*id).or_default().push(*ref_id) + } + } + } + edges + } + + pub fn topological_sort(&self) -> Vec { + let mut visited = HashSet::new(); + let mut stack = Vec::new(); + let mut sorted = Vec::new(); + let graph = self.reverse_edges(); + // TODO: remove + println!("{:#?}", graph); + + for (id, _) in &self.nodes { + if !visited.contains(id) { + stack.push(*id); + + while let Some(id) = stack.pop() { + //TODO remove + println!("{:?}", stack); + if !visited.contains(&id) { + visited.insert(id); + if let Some(refs) = graph.get(&id) { + for ref_id in refs { + if !visited.contains(ref_id) { + stack.push(id); + stack.push(*ref_id); + break; + } + } + } + sorted.push(id); + } + } + } + } + sorted.reverse(); + sorted + } + + pub fn reorder_ids(&mut self) { + let order = self.topological_sort(); + let lookup = self + .nodes + .iter() + .map(|(id, _)| (*id, order.iter().position(|x| x == id).unwrap() as u64)) + .collect::>(); + self.nodes.sort_by_key(|(id, _)| lookup.get(id).unwrap()); + self.nodes.iter_mut().for_each(|(id, node)| { + node.map_ids(|id| *lookup.get(&id).unwrap()); + *id = *lookup.get(id).unwrap() + }); + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput}; + use value::IntoValue; + + #[test] + fn topological_sort() { + let construction_network = ProtoNetwork { + inputs: vec![10], + output: 1, + nodes: [ + ( + 1, + ProtoNode { + identifier: "id".into(), + input: ProtoNodeInput::Node(11), + construction_args: ConstructionArgs::Nodes(vec![]), + }, + ), + ( + 10, + ProtoNode { + identifier: "cons".into(), + input: ProtoNodeInput::Network, + construction_args: ConstructionArgs::Nodes(vec![14]), + }, + ), + ( + 11, + ProtoNode { + identifier: "add".into(), + input: ProtoNodeInput::Node(10), + construction_args: ConstructionArgs::Nodes(vec![]), + }, + ), + ( + 14, + ProtoNode { + identifier: "value".into(), + input: ProtoNodeInput::None, + construction_args: ConstructionArgs::Value(2_u32.into_any()), + }, + ), + ] + .into_iter() + .collect(), + }; + let sorted = construction_network.topological_sort(); + + println!("{:#?}", sorted); + assert_eq!(sorted, vec![14, 10, 11, 1]); + } +} diff --git a/node-graph/gstd/Cargo.toml b/node-graph/gstd/Cargo.toml index 2d5064dd..0b0812db 100644 --- a/node-graph/gstd/Cargo.toml +++ b/node-graph/gstd/Cargo.toml @@ -25,5 +25,4 @@ syn = {version = "1.0", default-features = false, features = ["parsing", "printi proc-macro2 = {version = "1.0", default-features = false, features = ["proc-macro"]} quote = {version = "1.0", default-features = false } image = "*" -rand_chacha = "0.3.1" dyn-clone = "1.0" diff --git a/node-graph/gstd/src/any.rs b/node-graph/gstd/src/any.rs index 4fc14f91..01b0a4ff 100644 --- a/node-graph/gstd/src/any.rs +++ b/node-graph/gstd/src/any.rs @@ -189,7 +189,7 @@ where } }*/ -use graphene_core::{ops::Dynamic, AsRefNode}; +use graphene_core::{ops::dynamic::Dynamic, AsRefNode}; pub struct BoxedComposition<'a, Second> { pub first: Box>>, pub second: Second, diff --git a/node-graph/gstd/src/lib.rs b/node-graph/gstd/src/lib.rs index ae9447b1..48fe597e 100644 --- a/node-graph/gstd/src/lib.rs +++ b/node-graph/gstd/src/lib.rs @@ -8,8 +8,6 @@ pub mod raster; pub mod any; -pub mod document; - pub use graphene_core::*; use quote::quote;