From 3243b80cf2112d51591d64dfa76e068a42642457 Mon Sep 17 00:00:00 2001 From: Dennis Date: Sat, 2 Apr 2022 20:50:53 +0200 Subject: [PATCH] Try and fail to make nodes object-safe in node graph --- node-graph/Cargo.lock | 9 +++ node-graph/gcore/Cargo.toml | 4 ++ node-graph/{gstd => gcore}/src/generic.rs | 2 +- node-graph/gcore/src/lib.rs | 47 +++++++++++++- node-graph/{gstd => gcore}/src/ops.rs | 2 +- node-graph/{gstd => gcore}/src/structural.rs | 2 +- node-graph/gcore/src/value.rs | 65 ++++++++++++++++++++ node-graph/gstd/src/lib.rs | 6 +- node-graph/gstd/src/main.rs | 50 ++++++++++++++- node-graph/gstd/src/memo.rs | 4 +- node-graph/gstd/src/value.rs | 38 ------------ node-graph/proc-macro/src/lib.rs | 35 +++++++---- 12 files changed, 200 insertions(+), 64 deletions(-) rename node-graph/{gstd => gcore}/src/generic.rs (97%) rename node-graph/{gstd => gcore}/src/ops.rs (98%) rename node-graph/{gstd => gcore}/src/structural.rs (97%) create mode 100644 node-graph/gcore/src/value.rs delete mode 100644 node-graph/gstd/src/value.rs diff --git a/node-graph/Cargo.lock b/node-graph/Cargo.lock index 0a495403..3817bd19 100644 --- a/node-graph/Cargo.lock +++ b/node-graph/Cargo.lock @@ -93,6 +93,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + [[package]] name = "countme" version = "3.0.1" @@ -235,6 +241,9 @@ dependencies = [ [[package]] name = "graphene-core" version = "0.1.0" +dependencies = [ + "const-default", +] [[package]] name = "graphene-std" diff --git a/node-graph/gcore/Cargo.toml b/node-graph/gcore/Cargo.toml index 487ae7b3..34c2f65a 100644 --- a/node-graph/gcore/Cargo.toml +++ b/node-graph/gcore/Cargo.toml @@ -6,5 +6,9 @@ description = "Api definitions for graphene" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +const_default = ["const-default"] +default = ["const_default"] [dependencies] +const-default = { version = "1.0", optional = true } diff --git a/node-graph/gstd/src/generic.rs b/node-graph/gcore/src/generic.rs similarity index 97% rename from node-graph/gstd/src/generic.rs rename to node-graph/gcore/src/generic.rs index 9ce57c5b..585d4fc9 100644 --- a/node-graph/gstd/src/generic.rs +++ b/node-graph/gcore/src/generic.rs @@ -1,6 +1,6 @@ use std::{borrow::Borrow, marker::PhantomData}; -use graphene_core::Node; +use crate::Node; pub struct FnNode O, In, O>(T, PhantomData, PhantomData); impl O, In, O> Node for FnNode { type Output<'a> = O where Self: 'a; diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index 32fffd90..f7f9e603 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -1,16 +1,39 @@ #![feature(generic_associated_types)] -use std::{any::Any, borrow::Borrow}; +pub mod generic; +pub mod ops; +pub mod structural; +pub mod value; + +use std::{any::Any, borrow::Borrow, ops::Deref}; #[rustfmt::skip] pub trait Node { // Self: 'a means that Self has to live at least as long as 'a (the input and output) // this ensures that the node does not spontaneously disappear during evaluation - type Output<'a> where Self: 'a; - type Input<'a> where Self: 'a; + type Input<'i> where Self: 'i; + type Output<'o> where Self: 'o; fn eval<'a, I: Borrow>>(&'a self, input: I) -> Self::Output<'a>; } +pub trait SimpleNode<'n, I, O> { + fn eval_simple(&self, input: &I) -> &O; +} + +impl SimpleNode<'n, I, O>, I, O> Node for T { + type Input<'i> = &'i I where Self: 'i; + type Output<'o> = &'o O where Self: 'o; + + fn eval<'a, In: Borrow>>(&'a self, input: In) -> Self::Output<'a> { + self.eval_simple(input.borrow()) + } +} + +#[rustfmt::skip] +pub trait OutputNode<'a, T>: Node = T> where Self: 'a {} +#[rustfmt::skip] +pub trait ArgNode<'a, T>: OutputNode<'a, T> + Node = ()> where Self: 'a {} + pub trait AnyRef: Node { fn any<'a>(&'a self, input: &'a dyn Any) -> Self::Output<'a> where @@ -33,6 +56,24 @@ impl AnyRef for T { } } +trait Ref: Node {} +impl<'a, T: 'a, N: Node = &'a T> + 'a> Ref for N {} + +pub trait ExecPtr<'n, T>: Node { + fn fn_ptr(&self) -> &T; +} + +impl<'n, T: 'n, N: Ref> ExecPtr<'n, T> for N +where + for<'a> &'a (): Borrow<::Input<'a>>, + for<'a> &'a T: From>, +{ + fn fn_ptr(&self) -> &T { + let value: &T = self.eval(&()).into(); + value + } +} + pub trait Exec: Node where for<'a> &'a (): Borrow<::Input<'a>>, diff --git a/node-graph/gstd/src/ops.rs b/node-graph/gcore/src/ops.rs similarity index 98% rename from node-graph/gstd/src/ops.rs rename to node-graph/gcore/src/ops.rs index 29fa1dfb..670b7eb9 100644 --- a/node-graph/gstd/src/ops.rs +++ b/node-graph/gcore/src/ops.rs @@ -1,6 +1,6 @@ use std::{borrow::Borrow, marker::PhantomData}; -use graphene_core::Node; +use crate::Node; #[derive(Default)] pub struct AddNode(PhantomData); diff --git a/node-graph/gstd/src/structural.rs b/node-graph/gcore/src/structural.rs similarity index 97% rename from node-graph/gstd/src/structural.rs rename to node-graph/gcore/src/structural.rs index 8b98ed16..d3feec5f 100644 --- a/node-graph/gstd/src/structural.rs +++ b/node-graph/gcore/src/structural.rs @@ -1,6 +1,6 @@ use std::{any::Any, borrow::Borrow}; -use graphene_core::{DynamicInput, Node}; +use crate::{DynamicInput, Node}; pub struct ComposeNode<'n, FIRST, SECOND> { first: &'n FIRST, second: &'n SECOND, diff --git a/node-graph/gcore/src/value.rs b/node-graph/gcore/src/value.rs new file mode 100644 index 00000000..edae1647 --- /dev/null +++ b/node-graph/gcore/src/value.rs @@ -0,0 +1,65 @@ +use std::{borrow::Borrow, marker::PhantomData}; + +use const_default::ConstDefault; + +use crate::{Exec, Node}; + +pub struct IntNode; +impl Node for IntNode { + type Input<'o> = (); + type Output<'i> = u32; + fn eval<'a, I: Borrow>>(&self, _input: I) -> u32 { + N + } +} + +#[derive(Default)] +pub struct ValueNode(T); +impl Node for ValueNode { + type Input<'i> = () where T: 'i; + type Output<'o> = &'o T where T: 'o; + fn eval<'a, I: Borrow>>(&'a self, _input: I) -> &T { + &self.0 + } +} +impl ValueNode { + pub const fn new(value: T) -> ValueNode { + ValueNode(value) + } +} + +#[derive(Default)] +pub struct DefaultNode(PhantomData); +impl Node for DefaultNode { + type Input<'i> = () where T: 'i; + type Output<'o> = T where T: 'o; + fn eval<'a, I: Borrow>>(&'a self, _input: I) -> T { + T::default() + } +} +impl DefaultNode { + pub const fn new() -> DefaultNode { + DefaultNode(PhantomData) + } +} + +pub struct DefaultRefNode(ValueNode); +impl Node for DefaultRefNode { + type Input<'i> = () where T: 'i; + type Output<'o> = &'o T where T: 'o; + fn eval<'a, I: Borrow>>(&'a self, _input: I) -> &'a T { + self.0.exec() + } +} +#[cfg(feature = "const_default")] +impl DefaultRefNode { + pub const fn new() -> DefaultRefNode { + DefaultRefNode(ValueNode::new(T::DEFAULT)) + } +} +#[cfg(not(feature = "const_default"))] +impl DefaultRefNode { + pub fn new() -> DefaultRefNode { + DefaultRefNode(ValueNode::new(T::default())) + } +} diff --git a/node-graph/gstd/src/lib.rs b/node-graph/gstd/src/lib.rs index 699325d6..dd9bbebb 100644 --- a/node-graph/gstd/src/lib.rs +++ b/node-graph/gstd/src/lib.rs @@ -2,9 +2,7 @@ #[cfg(feature = "caching")] pub mod caching; -pub mod generic; #[cfg(feature = "memoization")] pub mod memo; -pub mod ops; -pub mod structural; -pub mod value; + +pub use graphene_core::*; diff --git a/node-graph/gstd/src/main.rs b/node-graph/gstd/src/main.rs index a77c556a..b7d2cf6c 100644 --- a/node-graph/gstd/src/main.rs +++ b/node-graph/gstd/src/main.rs @@ -1,7 +1,55 @@ -use graphene_core::{Exec, Node}; +#![feature(generic_associated_types)] use graphene_std::*; +/*fn mul(a: f32, b: f32) -> f32 { + a * b +}*/ + +mod mul { + use graphene_std::{ + value::DefaultNode, value::DefaultRefNode, ArgNode, DynamicInput, ExecPtr, Node, + }; + use std::{any::Any, ops::Deref}; + const A: DefaultRefNode = DefaultRefNode::new(); + const B: DefaultRefNode = DefaultRefNode::new(); + type F32Node<'n> = &'n dyn ExecPtr<'n, f32, Output<'n> = &'n f32, Input<'n> = ()>; + pub struct MulNode<'n> { + a: F32Node<'n>, + b: F32Node<'n>, + } + impl<'n> Node for MulNode<'n> { + type Input<'i> = () where Self: 'i; + type Output<'o> = f32 where Self: 'o; + fn eval<'a, I>(&'a self, input: I) -> ::Output<'a> + where + I: std::borrow::Borrow>, + { + let a = self.a.fn_ptr(); + let b = self.b.fn_ptr(); + a * b + } + } + impl<'n> MulNode<'n> { + pub const fn new() -> Self { + Self { a: &A, b: &B } + } + } + impl DynamicInput for MulNode<'_> { + fn set_kwarg_by_name(&mut self, _: &str, _: &(dyn std::any::Any + 'static)) { + todo!() + } + fn set_arg_by_index(&mut self, index: usize, input: &(dyn std::any::Any + 'static)) { + match index { + 0 => self.a = input.downcast_ref::<&dyn ExecPtr<'_, f32>>().unwrap(), + _ => todo!(), + } + } + } +} + fn main() { + let mut mul = mul::MulNode::new(); + let int = value::IntNode::<32>; let _add: u32 = ops::AddNode::::default().eval((int.exec(), int.exec())); let fnode = generic::FnNode::new(|(a, b): &(i32, i32)| a - b); diff --git a/node-graph/gstd/src/memo.rs b/node-graph/gstd/src/memo.rs index 254b04a6..c89abc21 100644 --- a/node-graph/gstd/src/memo.rs +++ b/node-graph/gstd/src/memo.rs @@ -1,6 +1,6 @@ -use graphene_core::Node; +use graphene_core::{ExecPtr, Node}; use once_cell::sync::OnceCell; -use std::borrow::Borrow; +use std::{any::Any, borrow::Borrow, ops::Deref}; /// Caches the output of a given Node and acts as a proxy pub struct CacheNode<'n, 'c, CachedNode: Node + 'c> { diff --git a/node-graph/gstd/src/value.rs b/node-graph/gstd/src/value.rs deleted file mode 100644 index 9dde76d6..00000000 --- a/node-graph/gstd/src/value.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::borrow::Borrow; - -use graphene_core::Node; - -pub struct IntNode; -impl Node for IntNode { - type Output<'a> = u32; - type Input<'a> = (); - fn eval<'a, I: Borrow>>(&self, _input: I) -> u32 { - N - } -} - -#[derive(Default)] -pub struct ValueNode(T); -impl Node for ValueNode { - type Output<'o> = &'o T where T: 'o; - type Input<'i> = () where T: 'i; - fn eval<'a, I: Borrow>>(&'a self, _input: I) -> &T { - &self.0 - } -} - -#[rustfmt::skip] -pub trait OutputNode<'a, T>: Node = T> where Self: 'a {} -impl DefaultNode for T {} - -impl ValueNode { - pub fn new(value: T) -> ValueNode { - ValueNode(value) - } -} - -pub trait DefaultNode: Default { - fn default_node() -> ValueNode { - ValueNode::new(Self::default()) - } -} diff --git a/node-graph/proc-macro/src/lib.rs b/node-graph/proc-macro/src/lib.rs index ee17890c..e398e919 100644 --- a/node-graph/proc-macro/src/lib.rs +++ b/node-graph/proc-macro/src/lib.rs @@ -1,28 +1,27 @@ -use graphene_core; use proc_macro::TokenStream; use proc_macro_roids::*; use quote::{quote, ToTokens}; use syn::punctuated::Punctuated; use syn::{parse_macro_input, FnArg, ItemFn, Pat, Type}; -fn extract_type(a: FnArg) -> Box { +fn extract_type(a: FnArg) -> Type { match a { - FnArg::Typed(p) => p.ty, // notice `ty` instead of `pat` + FnArg::Typed(p) => *p.ty, // notice `ty` instead of `pat` _ => panic!("Not supported on types with `self`!"), } } -fn extract_arg_types(fn_args: Punctuated) -> Vec> { - return fn_args.into_iter().map(extract_type).collect::>(); +fn extract_arg_types(fn_args: Punctuated) -> Vec { + fn_args.into_iter().map(extract_type).collect::>() } -fn extract_arg_idents(fn_args: Punctuated) -> Vec> { - return fn_args.into_iter().map(extract_arg_pat).collect::>(); +fn extract_arg_idents(fn_args: Punctuated) -> Vec { + fn_args.into_iter().map(extract_arg_pat).collect::>() } -fn extract_arg_pat(a: FnArg) -> Box { +fn extract_arg_pat(a: FnArg) -> Pat { match a { - FnArg::Typed(p) => p.pat, + FnArg::Typed(p) => *p.pat, _ => panic!("Not supported on types with `self`!"), } } @@ -30,7 +29,7 @@ fn extract_arg_pat(a: FnArg) -> Box { #[proc_macro_attribute] // 2 pub fn to_node(_attr: TokenStream, item: TokenStream) -> TokenStream { let string = item.to_string(); - let item2 = item.clone(); + let item2 = item; let parsed = parse_macro_input!(item2 as ItemFn); // 3 //item.extend(generate_to_string(parsed, string)); // 4 //item @@ -56,9 +55,16 @@ fn generate_to_string(parsed: ItemFn, string: String) -> TokenStream { .iter() .map(|t| t.to_token_stream()) .collect::>(); + let const_idents = idents + .iter() + .map(|t| { + let name = t.to_string().to_uppercase(); + quote! {#name} + }) + .collect::>(); let node_fn_name = fn_name.append("_node"); - let struct_name = fn_name.append("_node"); + let struct_name = fn_name.append("_input"); let return_type_string = fn_return_type .to_token_stream() .to_string() @@ -68,15 +74,18 @@ fn generate_to_string(parsed: ItemFn, string: String) -> TokenStream { .map(|t| t.to_string()) .collect::>() .join(", "); - let error = format!("called {} with the wrong type", fn_name.to_string()); + let error = format!("called {} with the wrong type", fn_name); let x = quote! { //#whole_function mod #fn_name { + #(const #const_idents: DefaultNode<#types> = DefaultNode::new();)* struct #struct_name { + #(#idents: #types,)* + } + impl Node for #struct_name { } - impl } fn #node_fn_name #generics() -> Node<'static> {