From 11c6413251762fa1d5208fad8a0a90a545526775 Mon Sep 17 00:00:00 2001 From: TrueDoctor Date: Wed, 26 Oct 2022 00:32:50 +0200 Subject: [PATCH] Implement node registry (#822) --- Cargo.lock | 3 + node-graph/borrow_stack/Cargo.toml | 1 + node-graph/borrow_stack/src/lib.rs | 24 ++-- node-graph/gcore/src/lib.rs | 6 +- node-graph/gcore/src/ops.rs | 14 ++- node-graph/gcore/src/structural.rs | 19 +++- node-graph/graph-craft/src/lib.rs | 18 +-- node-graph/graph-craft/src/node_registry.rs | 120 ++++++++++++++++++++ node-graph/gstd/src/any.rs | 44 ++++++- node-graph/gstd/src/document.rs | 9 ++ 10 files changed, 213 insertions(+), 45 deletions(-) create mode 100644 node-graph/graph-craft/src/node_registry.rs diff --git a/Cargo.lock b/Cargo.lock index fd33a2fa..9ab9e410 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "borrow_stack" version = "0.1.0" +dependencies = [ + "dyn-any", +] [[package]] name = "bumpalo" diff --git a/node-graph/borrow_stack/Cargo.toml b/node-graph/borrow_stack/Cargo.toml index 044f817b..ee86bc38 100644 --- a/node-graph/borrow_stack/Cargo.toml +++ b/node-graph/borrow_stack/Cargo.toml @@ -7,3 +7,4 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +dyn-any = {path = "../../libraries/dyn-any"} diff --git a/node-graph/borrow_stack/src/lib.rs b/node-graph/borrow_stack/src/lib.rs index 6f4328c6..d333f117 100644 --- a/node-graph/borrow_stack/src/lib.rs +++ b/node-graph/borrow_stack/src/lib.rs @@ -5,25 +5,24 @@ use std::{ sync::atomic::{AtomicUsize, Ordering}, }; -pub trait BorrowStack<'n> { +pub trait BorrowStack { type Item; /// # Safety unsafe fn push(&self, value: Self::Item); /// # Safety unsafe fn pop(&self); /// # Safety - unsafe fn get(&self) -> &'n [Self::Item]; + unsafe fn get(&self) -> &'static [Self::Item]; } #[derive(Debug)] -pub struct FixedSizeStack<'n, T> { +pub struct FixedSizeStack { data: Pin]>>, capacity: usize, len: AtomicUsize, - _phantom: PhantomData<&'n ()>, } -impl<'n, T: Unpin + 'n> FixedSizeStack<'n, T> { +impl<'n, T: Unpin + 'n + dyn_any::StaticTypeSized> FixedSizeStack { pub fn new(capacity: usize) -> Self { let layout = std::alloc::Layout::array::>(capacity).unwrap(); let array = unsafe { std::alloc::alloc(layout) }; @@ -33,7 +32,6 @@ impl<'n, T: Unpin + 'n> FixedSizeStack<'n, T> { data: array, capacity, len: AtomicUsize::new(0), - _phantom: PhantomData, } } @@ -44,19 +42,19 @@ impl<'n, T: Unpin + 'n> FixedSizeStack<'n, T> { pub fn is_empty(&self) -> bool { self.len.load(Ordering::SeqCst) == 0 } - pub fn push_fn(&self, f: impl FnOnce(&'n [T]) -> T) { - unsafe { self.push(f(self.get())) } + pub fn push_fn(&self, f: impl FnOnce(&'static [T::Static]) -> T) { + unsafe { self.push(std::mem::transmute_copy(&f(self.get()))) } } } -impl<'n, T> BorrowStack<'n> for FixedSizeStack<'n, T> { - type Item = T; +impl<'n, T: 'n + dyn_any::StaticTypeSized> BorrowStack for FixedSizeStack { + type Item = T::Static; unsafe fn push(&self, value: Self::Item) { let len = self.len.load(Ordering::SeqCst); assert!(len < self.capacity); let ptr = self.data[len].as_ptr(); - (ptr as *mut T).write(value); + (ptr as *mut T::Static).write(value); self.len.fetch_add(1, Ordering::SeqCst); } @@ -66,8 +64,8 @@ impl<'n, T> BorrowStack<'n> for FixedSizeStack<'n, T> { self.len.fetch_sub(1, Ordering::SeqCst); } - unsafe fn get(&self) -> &'n [Self::Item] { - std::slice::from_raw_parts(self.data.as_ptr() as *const T, self.len.load(Ordering::SeqCst)) + unsafe fn get(&self) -> &'static [Self::Item] { + std::slice::from_raw_parts(self.data.as_ptr() as *const T::Static, self.len.load(Ordering::SeqCst)) } } diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index 845564b6..dca1833a 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -48,7 +48,7 @@ where } } -pub trait AsBoxNode<'n, T> +pub trait AsRefNode<'n, T> where &'n Self: Node, Self: 'n, @@ -57,7 +57,7 @@ where fn eval_box(&'n self, input: T) -> ::Output; } -impl<'n, N: 'n, I> AsBoxNode<'n, I> for N +impl<'n, N: 'n, I> AsRefNode<'n, I> for N where &'n N: Node, N: Node, @@ -69,7 +69,7 @@ where } } -impl<'n, T> Node for &'n (dyn AsBoxNode<'n, T, Output = T> + 'n) { +impl<'n, T> Node for &'n (dyn AsRefNode<'n, T, Output = T> + 'n) { type Output = T; fn eval(self, input: T) -> Self::Output { self.eval_box(input) diff --git a/node-graph/gcore/src/ops.rs b/node-graph/gcore/src/ops.rs index c994c9d5..bb51a4db 100644 --- a/node-graph/gcore/src/ops.rs +++ b/node-graph/gcore/src/ops.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use core::ops::Add; -use crate::Node; +use crate::{Node, RefNode}; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AddNode; @@ -153,18 +153,24 @@ impl<'n, T: Clone + 'n> Node for DupNode { /// Return the Input Argument #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct IdNode; -impl<'n, T: 'n> Node for IdNode { +impl Node for IdNode { type Output = T; fn eval(self, input: T) -> Self::Output { input } } -impl<'n, T: 'n> Node for &'n IdNode { +impl<'n, T> Node for &'n IdNode { type Output = T; fn eval(self, input: T) -> Self::Output { input } } +impl RefNode for IdNode { + type Output = T; + fn eval_ref(&self, input: T) -> Self::Output { + input + } +} pub struct MapResultNode(pub MN, pub PhantomData<(I, E)>); @@ -177,7 +183,7 @@ impl, I, E> Node> for MapResultNode { impl<'n, MN: Node + Copy, I, E> Node> for &'n MapResultNode { type Output = Result; fn eval(self, input: Result) -> Self::Output { - input.map(|x| (&self.0).eval(x)) + input.map(|x| self.0.eval(x)) } } diff --git a/node-graph/gcore/src/structural.rs b/node-graph/gcore/src/structural.rs index 57b08e02..1676273c 100644 --- a/node-graph/gcore/src/structural.rs +++ b/node-graph/gcore/src/structural.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use crate::{Node, RefNode}; +use crate::{AsRefNode, Node, RefNode}; #[derive(Debug)] pub struct ComposeNode { @@ -26,17 +26,19 @@ where } impl<'n, Input, Inter, First, Second> Node for &'n ComposeNode where - First: RefNode + Copy, - Second: RefNode + Copy, + First: AsRefNode<'n, Input, Output = Inter>, + Second: AsRefNode<'n, Inter>, + &'n First: Node, + &'n Second: Node, { - type Output = >::Output; + type Output = >::Output; fn eval(self, input: Input) -> Self::Output { // evaluate the first node with the given input // and then pipe the result from the first computation // into the second node - let arg: Inter = (self.first).eval_ref(input); - (self.second).eval_ref(arg) + let arg: Inter = (self.first).eval_box(input); + (self.second).eval_box(arg) } } impl RefNode for ComposeNode @@ -136,3 +138,8 @@ impl<'n, Root: Node + Copy, T: From<()>, Input> Node for &'n ConsNode< (input, arg) } } +impl> ConsNode { + pub fn new(root: Root) -> Self { + ConsNode(root, PhantomData) + } +} diff --git a/node-graph/graph-craft/src/lib.rs b/node-graph/graph-craft/src/lib.rs index 8ffc072f..f14018ed 100644 --- a/node-graph/graph-craft/src/lib.rs +++ b/node-graph/graph-craft/src/lib.rs @@ -1,3 +1,5 @@ +pub mod node_registry; + #[cfg(test)] mod tests { @@ -7,7 +9,7 @@ mod tests { use graphene_core::{structural::*, RefNode}; use borrow_stack::BorrowStack; - use dyn_any::{downcast, DynAny, IntoDynAny}; + use dyn_any::{downcast, IntoDynAny}; use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode}; use graphene_std::ops::AddNode; @@ -19,7 +21,8 @@ mod tests { stack.push(dynanynode.into_box()); } stack.push_fn(|nodes| { - let downcast: DowncastNode<_, &u32> = DowncastNode::new(&nodes[0]); + let pre_node = nodes.get(0).unwrap(); + let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node); let dynanynode: DynAnyNode>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData)); dynanynode.into_box() }); @@ -39,17 +42,6 @@ mod tests { 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); - - /* - for i in 0..3 { - println!("node_id: {}", i); - let value = unsafe { &stack.get()[i] }; - input = value.eval_ref(input); - }*/ - - //assert_eq!(*dyn_any::downcast::(result).unwrap(), 4) - - //assert_eq!(4, *dyn_any::downcast::(DynamicAddNode.eval((Box::new(2_u32) as Dynamic, Box::new(2_u32) as Dynamic))).unwrap()); } #[test] diff --git a/node-graph/graph-craft/src/node_registry.rs b/node-graph/graph-craft/src/node_registry.rs new file mode 100644 index 00000000..e122b808 --- /dev/null +++ b/node-graph/graph-craft/src/node_registry.rs @@ -0,0 +1,120 @@ +use std::marker::PhantomData; + +use borrow_stack::FixedSizeStack; +use graphene_core::ops::{AddNode, IdNode}; +use graphene_core::structural::{ConsNode, Then}; +use graphene_core::{AsRefNode, Node}; +use graphene_std::{ + any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode}, + document::{ConstructionArgs, ProtoNode, ProtoNodeInput}, +}; + +struct NodeIdentifier { + name: &'static str, + types: &'static [&'static str], +} + +const fn annotate<'n, 's: 'n, F>(f: F) -> F +where + F: Fn(ProtoNode, FixedSizeStack>), +{ + f +} + +use borrow_stack::BorrowStack; +unsafe fn foo<'n>(proto_node: ProtoNode, stack: &'n FixedSizeStack>) { + let node_id = proto_node.input.unwrap_node() as usize; + let nodes = stack.get(); + let pre_node = nodes.get(node_id).unwrap(); + let downcast: DowncastNode<_, &u32> = DowncastNode::new(pre_node); + let dynanynode: DynAnyNode>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData)); + stack.push(dynanynode.into_box()); +} +fn borrow_stack() { + let stack = borrow_stack::FixedSizeStack::new(256); + unsafe { + { + let proto_node = ProtoNode::id(); + foo(proto_node, &stack); + let proto_node = ProtoNode::id(); + let stack = &stack; + let node_id = proto_node.input.unwrap_node() as usize; + let nodes = stack.get(); + let pre_node = nodes.get(node_id).unwrap(); + let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node); + let dynanynode: DynAnyNode>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData)); + stack.push(dynanynode.into_box()); + } + }; +} + +static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack>))] = &[ + ( + NodeIdentifier { + name: "graphene_core::ops::IdNode", + types: &["Any<'n>"], + }, + |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::AddNode", + types: &["u32", "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"], + }, + |proto_node, stack| { + let node_id = proto_node.input.unwrap_node() as usize; + stack.push_fn(move |nodes| { + let pre_node = nodes.get(node_id).unwrap(); + let downcast: DowncastNode<_, &u32> = DowncastNode::new(pre_node); + let dynanynode: DynAnyNode>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData)); + dynanynode.into_box() + }) + }, + ),*/ + ( + NodeIdentifier { + name: "graphene_core::any::DowncastNode", + types: &["&TypeErasedNode", "&u32"], + }, + |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() + }) + }, + ), +]; + +#[cfg(test)] +mod test { + use super::*; + + /*#[test] + fn test() { + let nodes = [TypeErasedNode(Box::new(42u32))]; + let node = NODE_REGISTRY[0].1(node, &nodes); + assert_eq!(node.eval(()), 42); + }*/ +} diff --git a/node-graph/gstd/src/any.rs b/node-graph/gstd/src/any.rs index a6916f1a..aeef23f9 100644 --- a/node-graph/gstd/src/any.rs +++ b/node-graph/gstd/src/any.rs @@ -1,4 +1,4 @@ -use dyn_any::{DynAny, StaticType}; +use dyn_any::{DynAny, StaticType, StaticTypeSized}; pub use graphene_core::{generic, ops /*, structural*/, Node, RefNode}; use std::marker::PhantomData; @@ -6,7 +6,7 @@ fn fmt_error() -> String { format!("DynAnyNode: input is not of correct type, expected {}", std::any::type_name::()) } -pub struct DynAnyNode(pub N, PhantomData<(I, O, ORef)>); +pub struct DynAnyNode(pub N, pub PhantomData<(I, O, ORef)>); /*impl<'n, I: StaticType, N: RefNode<'n, &'n I, Output = O> + 'n, O: 'n + StaticType> Node<&'n dyn DynAny<'n>> for DynAnyNode<'n, N, I> { type Output = Box + 'n>; fn eval(self, input: &'n dyn DynAny<'n>) -> Self::Output { @@ -49,13 +49,37 @@ where Box::new((&self.0).eval_ref(*input)) } } -pub struct TypeErasedNode<'n>(pub Box, Output = Any<'n>>>); +pub struct TypeErasedNode<'n>(pub Box, Output = Any<'n>> + 'n>); impl<'n> Node> for &'n TypeErasedNode<'n> { type Output = Any<'n>; fn eval(self, input: Any<'n>) -> Self::Output { self.0.eval_box(input) } } +impl<'n> Node> for &'n &'n TypeErasedNode<'n> { + type Output = Any<'n>; + fn eval(self, input: Any<'n>) -> Self::Output { + self.0.eval_box(input) + } +} + +pub trait IntoTypeErasedNode<'n> { + fn into_type_erased(self) -> TypeErasedNode<'n>; +} + +impl<'n> StaticTypeSized for TypeErasedNode<'n> { + type Static = TypeErasedNode<'static>; +} + +impl<'n, N: 'n> IntoTypeErasedNode<'n> for N +where + N: AsRefNode<'n, Any<'n>, Output = Any<'n>>, + &'n N: Node, Output = Any<'n>>, +{ + fn into_type_erased(self) -> TypeErasedNode<'n> { + TypeErasedNode(Box::new(self)) + } +} impl<'n, I: StaticType + 'n, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> DynAnyNode where @@ -81,11 +105,19 @@ where Self: 'a, N: Node, { - TypeErasedNode(Box::new(self)) + self.into_type_erased() + } +} +impl<'n, I: StaticType + 'n, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> DynAnyNode<&'n N, I, O, ORef> +where + N: Node, +{ + pub fn new_from_ref(n: &'n N) -> Self { + DynAnyNode(n, PhantomData) } } -pub struct DowncastNode(pub N, PhantomData); +pub struct DowncastNode(pub N, pub PhantomData); impl Clone for DowncastNode { fn clone(&self) -> Self { Self(self.0, self.1) @@ -127,7 +159,7 @@ where } }*/ -use graphene_core::{ops::Dynamic, AsBoxNode}; +use graphene_core::{ops::Dynamic, AsRefNode}; pub struct BoxedComposition<'a, Second> { pub first: Box>>, pub second: Second, diff --git a/node-graph/gstd/src/document.rs b/node-graph/gstd/src/document.rs index 21ba58a2..ae651964 100644 --- a/node-graph/gstd/src/document.rs +++ b/node-graph/gstd/src/document.rs @@ -198,6 +198,15 @@ impl NodeInput { } } +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 {