Try and fail to make nodes object-safe in node graph
This commit is contained in:
parent
800fb4dbc1
commit
3243b80cf2
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
use graphene_core::Node;
|
||||
use crate::Node;
|
||||
pub struct FnNode<T: Fn(&In) -> O, In, O>(T, PhantomData<In>, PhantomData<O>);
|
||||
impl<T: Fn(&In) -> O, In, O> Node for FnNode<T, In, O> {
|
||||
type Output<'a> = O where Self: 'a;
|
||||
|
|
@ -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<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a>;
|
||||
}
|
||||
|
||||
pub trait SimpleNode<'n, I, O> {
|
||||
fn eval_simple(&self, input: &I) -> &O;
|
||||
}
|
||||
|
||||
impl<T: for<'n> 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<Self::Input<'a>>>(&'a self, input: In) -> Self::Output<'a> {
|
||||
self.eval_simple(input.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub trait OutputNode<'a, T>: Node<Output<'a> = T> where Self: 'a {}
|
||||
#[rustfmt::skip]
|
||||
pub trait ArgNode<'a, T>: OutputNode<'a, T> + Node<Input<'a> = ()> 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<T: Node> AnyRef for T {
|
|||
}
|
||||
}
|
||||
|
||||
trait Ref<T>: Node {}
|
||||
impl<'a, T: 'a, N: Node<Output<'a> = &'a T> + 'a> Ref<T> for N {}
|
||||
|
||||
pub trait ExecPtr<'n, T>: Node {
|
||||
fn fn_ptr(&self) -> &T;
|
||||
}
|
||||
|
||||
impl<'n, T: 'n, N: Ref<T>> ExecPtr<'n, T> for N
|
||||
where
|
||||
for<'a> &'a (): Borrow<<Self as Node>::Input<'a>>,
|
||||
for<'a> &'a T: From<N::Output<'a>>,
|
||||
{
|
||||
fn fn_ptr(&self) -> &T {
|
||||
let value: &T = self.eval(&()).into();
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Exec: Node
|
||||
where
|
||||
for<'a> &'a (): Borrow<<Self as Node>::Input<'a>>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
use graphene_core::Node;
|
||||
use crate::Node;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AddNode<T>(PhantomData<T>);
|
||||
|
|
@ -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,
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
use const_default::ConstDefault;
|
||||
|
||||
use crate::{Exec, Node};
|
||||
|
||||
pub struct IntNode<const N: u32>;
|
||||
impl<const N: u32> Node for IntNode<N> {
|
||||
type Input<'o> = ();
|
||||
type Output<'i> = u32;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&self, _input: I) -> u32 {
|
||||
N
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ValueNode<T>(T);
|
||||
impl<T> Node for ValueNode<T> {
|
||||
type Input<'i> = () where T: 'i;
|
||||
type Output<'o> = &'o T where T: 'o;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl<T> ValueNode<T> {
|
||||
pub const fn new(value: T) -> ValueNode<T> {
|
||||
ValueNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DefaultNode<T>(PhantomData<T>);
|
||||
impl<T: Default> Node for DefaultNode<T> {
|
||||
type Input<'i> = () where T: 'i;
|
||||
type Output<'o> = T where T: 'o;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> T {
|
||||
T::default()
|
||||
}
|
||||
}
|
||||
impl<T> DefaultNode<T> {
|
||||
pub const fn new() -> DefaultNode<T> {
|
||||
DefaultNode(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultRefNode<T>(ValueNode<T>);
|
||||
impl<T: 'static> Node for DefaultRefNode<T> {
|
||||
type Input<'i> = () where T: 'i;
|
||||
type Output<'o> = &'o T where T: 'o;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> &'a T {
|
||||
self.0.exec()
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "const_default")]
|
||||
impl<T: ConstDefault> DefaultRefNode<T> {
|
||||
pub const fn new() -> DefaultRefNode<T> {
|
||||
DefaultRefNode(ValueNode::new(T::DEFAULT))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "const_default"))]
|
||||
impl<T: Default> DefaultRefNode<T> {
|
||||
pub fn new() -> DefaultRefNode<T> {
|
||||
DefaultRefNode(ValueNode::new(T::default()))
|
||||
}
|
||||
}
|
||||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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<f32> = DefaultRefNode::new();
|
||||
const B: DefaultRefNode<f32> = 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) -> <Self as graphene_std::Node>::Output<'a>
|
||||
where
|
||||
I: std::borrow::Borrow<Self::Input<'a>>,
|
||||
{
|
||||
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::<u32>::default().eval((int.exec(), int.exec()));
|
||||
let fnode = generic::FnNode::new(|(a, b): &(i32, i32)| a - b);
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
use std::borrow::Borrow;
|
||||
|
||||
use graphene_core::Node;
|
||||
|
||||
pub struct IntNode<const N: u32>;
|
||||
impl<const N: u32> Node for IntNode<N> {
|
||||
type Output<'a> = u32;
|
||||
type Input<'a> = ();
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&self, _input: I) -> u32 {
|
||||
N
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ValueNode<T>(T);
|
||||
impl<T> Node for ValueNode<T> {
|
||||
type Output<'o> = &'o T where T: 'o;
|
||||
type Input<'i> = () where T: 'i;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub trait OutputNode<'a, T>: Node<Output<'a> = T> where Self: 'a {}
|
||||
impl<T: std::default::Default> DefaultNode for T {}
|
||||
|
||||
impl<T> ValueNode<T> {
|
||||
pub fn new(value: T) -> ValueNode<T> {
|
||||
ValueNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DefaultNode: Default {
|
||||
fn default_node() -> ValueNode<Self> {
|
||||
ValueNode::new(Self::default())
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Type> {
|
||||
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<FnArg, syn::token::Comma>) -> Vec<Box<Type>> {
|
||||
return fn_args.into_iter().map(extract_type).collect::<Vec<_>>();
|
||||
fn extract_arg_types(fn_args: Punctuated<FnArg, syn::token::Comma>) -> Vec<Type> {
|
||||
fn_args.into_iter().map(extract_type).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn extract_arg_idents(fn_args: Punctuated<FnArg, syn::token::Comma>) -> Vec<Box<Pat>> {
|
||||
return fn_args.into_iter().map(extract_arg_pat).collect::<Vec<_>>();
|
||||
fn extract_arg_idents(fn_args: Punctuated<FnArg, syn::token::Comma>) -> Vec<Pat> {
|
||||
fn_args.into_iter().map(extract_arg_pat).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn extract_arg_pat(a: FnArg) -> Box<Pat> {
|
||||
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<Pat> {
|
|||
#[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::<Vec<_>>();
|
||||
let const_idents = idents
|
||||
.iter()
|
||||
.map(|t| {
|
||||
let name = t.to_string().to_uppercase();
|
||||
quote! {#name}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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::<Vec<_>>()
|
||||
.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> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue