From cef58b16c2eb94324bd4c91b52de73587cc4d036 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 28 Sep 2022 18:47:34 +0100 Subject: [PATCH] Some initial testing on dynamic nodes and composition * Test use of borrow stack --- Cargo.lock | 11 ++++ Cargo.toml | 1 + libraries/dyn-any/src/lib.rs | 6 ++ node-graph/gcore/src/ops.rs | 46 ++++++++++++++ node-graph/graph-craft/Cargo.toml | 14 ++++ node-graph/graph-craft/src/lib.rs | 102 ++++++++++++++++++++++++++++++ node-graph/gstd/src/any.rs | 31 +++++++++ node-graph/gstd/src/document.rs | 18 +++--- 8 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 node-graph/graph-craft/Cargo.toml create mode 100644 node-graph/graph-craft/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index d4c45d62..fd33a2fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -340,6 +340,17 @@ dependencies = [ "serde", ] +[[package]] +name = "graph-craft" +version = "0.1.0" +dependencies = [ + "borrow_stack", + "dyn-any", + "graphene-core", + "graphene-std", + "num-traits", +] + [[package]] name = "graph-proc-macros" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a7903fd5..2dec3785 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "frontend/wasm", "node-graph/gcore", "node-graph/gstd", + "node-graph/graph-craft", "node-graph/borrow_stack", "libraries/dyn-any", "libraries/bezier-rs", diff --git a/libraries/dyn-any/src/lib.rs b/libraries/dyn-any/src/lib.rs index 985e1906..122dd7c4 100644 --- a/libraries/dyn-any/src/lib.rs +++ b/libraries/dyn-any/src/lib.rs @@ -142,3 +142,9 @@ macro_rules! impl_tuple { impl_tuple! { A B C D E F G H I J K L } + +#[test] +fn simple_downcast() { + let x = Box::new(3_u32) as Box; + assert_eq!(*downcast::(x).unwrap(), 3_u32); +} diff --git a/node-graph/gcore/src/ops.rs b/node-graph/gcore/src/ops.rs index c5d58825..c7e9fb5a 100644 --- a/node-graph/gcore/src/ops.rs +++ b/node-graph/gcore/src/ops.rs @@ -30,6 +30,52 @@ 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; + +// 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 + if $(core::any::TypeId::of::<$t>() == $arg.type_id())&&* { + // Cast the arguments and then call the inner node + alloc::boxed::Box::new($node.eval(($(*dyn_any::downcast::<$t>($arg).unwrap()),*)) ) as Dynamic + } + )else* + else{ + panic!("Unhandled type"); // TODO: Exit neatly (although this should probably not happen) + } + }; +} + +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) } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct CloneNode; impl<'n, O: Clone> Node<&'n O> for CloneNode { diff --git a/node-graph/graph-craft/Cargo.toml b/node-graph/graph-craft/Cargo.toml new file mode 100644 index 00000000..7b29a687 --- /dev/null +++ b/node-graph/graph-craft/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "graph-craft" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +graphene-core = { path = "../gcore", features = ["async", "std"] } +graphene-std = { path = "../gstd" } +dyn-any = { path = "../../libraries/dyn-any" } +num-traits = "0.2" +borrow_stack = { path = "../borrow_stack" } diff --git a/node-graph/graph-craft/src/lib.rs b/node-graph/graph-craft/src/lib.rs new file mode 100644 index 00000000..a83aa5d7 --- /dev/null +++ b/node-graph/graph-craft/src/lib.rs @@ -0,0 +1,102 @@ +#[cfg(test)] +mod tests { + + use graphene_core::structural::*; + use graphene_core::value::ValueNode; + + use borrow_stack::BorrowStack; + use graphene_std::any::{Any, DynAnyNode, DynAnyNodeTrait}; + use graphene_std::ops::AddNode; + + #[test] + fn borrow_stack() { + let stack = borrow_stack::FixedSizeStack::new(256); + unsafe { + let dynanynode: DynAnyNode<'_, _, ()> = DynAnyNode::new(&ValueNode(2_u32)); + let refn = Box::new(dynanynode) as Box; + stack.push(refn); + } + unsafe { + let dynanynode: DynAnyNode<'_, _, &u32> = DynAnyNode::new(&ConsNode(ValueNode(2_u32))); + let refn = Box::new(dynanynode) as Box; + stack.push(refn); + } + unsafe { + let dynanynode: DynAnyNode<'_, _, (&u32, u32)> = DynAnyNode::new(&AddNode); + let refn = Box::new(dynanynode) as Box; + stack.push(refn); + } + + let mut input = Box::new(()) as Any; + for i in 0..3 { + let value = unsafe { &stack.get()[i] }; + input = value.eval_ref_dispatch(input); + } + + assert_eq!(*dyn_any::downcast::(input).unwrap(), 4) + + //assert_eq!(4, *dyn_any::downcast::(DynamicAddNode.eval((Box::new(2_u32) as Dynamic, Box::new(2_u32) as Dynamic))).unwrap()); + } + + #[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 { + name: "cons".into(), + 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()), + }), + }, + ), + ] + .into_iter() + .collect(), + }; + } +} diff --git a/node-graph/gstd/src/any.rs b/node-graph/gstd/src/any.rs index 1b7d907d..8195980c 100644 --- a/node-graph/gstd/src/any.rs +++ b/node-graph/gstd/src/any.rs @@ -57,6 +57,33 @@ where self } } +/// If we store a `Box` in the stack then the origional DynAnyNode is dropped (because it is not stored by reference) +/// This trait is implemented directly by `DynAnyNode` so this means the borrow stack will hold by value +pub trait DynAnyNodeTrait<'n> { + fn eval_ref_dispatch(&'n self, input: Any<'n>) -> Any<'n>; +} +impl<'n, I: StaticType, O: 'n + StaticType, Node: RefNode + Copy + 'n> DynAnyNodeTrait<'n> for DynAnyNode<'n, Node, I> { + fn eval_ref_dispatch(&'n self, input: Any<'n>) -> Any<'n> { + self.eval_ref(input) + } +} + +use graphene_core::ops::Dynamic; +pub struct BoxedComposition<'a, Second> { + pub first: Box>>, + pub second: Second, +} + +// I can't see to get this to work +// We can't use the existing thing in any as it breaks lifetimes +// impl<'a, Second: Node>> Node<()> for BoxedComposition<'a, Second> { +// type Output = >>::Output; +// fn eval(self, input: ()) -> Self::Output { +// let x = RefNode::eval_ref(self.first.as_ref(), input); +// let arg: Dynamic<'a> = x.eval_ref(input); +// (self.second).eval(arg) +// } +// } /*impl<'n: 'static, I: StaticType, N, O: 'n + StaticType> DynAnyNode<'n, N, I> where @@ -131,6 +158,9 @@ mod test { pub fn dyn_input_storage_composition() { let mut vec: Vec<&(dyn RefNode)> = vec![]; //let id: DynAnyNode<_, u32> = DynAnyNode::new(IdNode); + + // If we put this until the push in a new scope then it failes to compile due to lifetime errors which I'm struggling to fix. + let value: &DynAnyNode<&ValueNode<(u32, u32)>, ()> = &DynAnyNode(&ValueNode((3u32, 4u32)), PhantomData); let add: &DynAnyNode<&AddNode, &(u32, u32)> = &DynAnyNode(&AddNode, PhantomData); @@ -138,6 +168,7 @@ mod test { let add_ref = (&add).into_ref(); vec.push(value_ref); vec.push(add_ref); + //vec.push(add.as_owned()); //vec.push(id.as_owned()); //let vec = vec.leak(); diff --git a/node-graph/gstd/src/document.rs b/node-graph/gstd/src/document.rs index 014c331f..21ba58a2 100644 --- a/node-graph/gstd/src/document.rs +++ b/node-graph/gstd/src/document.rs @@ -37,9 +37,9 @@ fn merge_ids(a: u64, b: u64) -> u64 { #[derive(Debug, PartialEq)] pub struct DocumentNode { - name: String, - inputs: Vec, - implementation: DocumentNodeImplementation, + pub name: String, + pub inputs: Vec, + pub implementation: DocumentNodeImplementation, } impl DocumentNode { @@ -114,9 +114,9 @@ pub enum DocumentNodeImplementation { #[derive(Debug, Default, PartialEq)] pub struct NodeNetwork { - inputs: Vec, - output: NodeId, - nodes: HashMap, + pub inputs: Vec, + pub output: NodeId, + pub nodes: HashMap, } pub type Value = Box; pub trait ValueTrait: DynAny<'static> + std::fmt::Debug {} @@ -177,9 +177,9 @@ impl PartialEq for ConstructionArgs { #[derive(Debug, Default, PartialEq)] pub struct ProtoNode { - construction_args: ConstructionArgs, - input: ProtoNodeInput, - name: String, + pub construction_args: ConstructionArgs, + pub input: ProtoNodeInput, + pub name: String, } #[derive(Debug, Default, PartialEq, Eq)]