Some initial testing on dynamic nodes and composition

* Test use of borrow stack
This commit is contained in:
0hypercube 2022-09-28 18:47:34 +01:00 committed by Keavon Chambers
parent 2ced9a57c4
commit cef58b16c2
8 changed files with 220 additions and 9 deletions

11
Cargo.lock generated
View File

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

View File

@ -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",

View File

@ -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<dyn DynAny>;
assert_eq!(*downcast::<u32>(x).unwrap(), 3_u32);
}

View File

@ -30,6 +30,52 @@ impl<'n, L: Add<R, Output = O> + '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<dyn dyn_any::DynAny<'a> + '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 {

View File

@ -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" }

View File

@ -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<dyn DynAnyNodeTrait>;
stack.push(refn);
}
unsafe {
let dynanynode: DynAnyNode<'_, _, &u32> = DynAnyNode::new(&ConsNode(ValueNode(2_u32)));
let refn = Box::new(dynanynode) as Box<dyn DynAnyNodeTrait>;
stack.push(refn);
}
unsafe {
let dynanynode: DynAnyNode<'_, _, (&u32, u32)> = DynAnyNode::new(&AddNode);
let refn = Box::new(dynanynode) as Box<dyn DynAnyNodeTrait>;
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::<u32>(input).unwrap(), 4)
//assert_eq!(4, *dyn_any::downcast::<u32>(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(),
};
}
}

View File

@ -57,6 +57,33 @@ where
self
}
}
/// If we store a `Box<dyn RefNode>` 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<I, Output = O> + 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<dyn Node<(), Output = Dynamic<'a>>>,
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<Dynamic<'a>>> Node<()> for BoxedComposition<'a, Second> {
// type Output = <Second as Node<Dynamic<'a>>>::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<Any, Output = Any>)> = 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();

View File

@ -37,9 +37,9 @@ fn merge_ids(a: u64, b: u64) -> u64 {
#[derive(Debug, PartialEq)]
pub struct DocumentNode {
name: String,
inputs: Vec<NodeInput>,
implementation: DocumentNodeImplementation,
pub name: String,
pub inputs: Vec<NodeInput>,
pub implementation: DocumentNodeImplementation,
}
impl DocumentNode {
@ -114,9 +114,9 @@ pub enum DocumentNodeImplementation {
#[derive(Debug, Default, PartialEq)]
pub struct NodeNetwork {
inputs: Vec<NodeId>,
output: NodeId,
nodes: HashMap<NodeId, DocumentNode>,
pub inputs: Vec<NodeId>,
pub output: NodeId,
pub nodes: HashMap<NodeId, DocumentNode>,
}
pub type Value = Box<dyn ValueTrait>;
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)]