Restructure node graph project layout

This commit is contained in:
Dennis 2022-04-02 14:50:00 +02:00 committed by Keavon Chambers
parent f8d4e10f35
commit 800fb4dbc1
19 changed files with 1958 additions and 598 deletions

512
node-graph/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,7 @@
[package]
name = "nodegraph-experiments"
version = "0.1.0"
edition = "2021"
[workspace]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
rust_analyzer = ["ide", "ide_db"]
[dependencies]
ide = { version = "*", package = "ra_ap_ide", optional = true }
ide_db = { version = "*", package = "ra_ap_ide_db" , optional = true }
graph-proc-macros = {path = "proc-macro"}
once_cell = "1.10"
dashmap = "5.2"
storage-map = "*"
lock_api = "*"
parking_lot = "*"
members = [
"proc-macro",
"gcore",
"gstd",
]

View file

@ -0,0 +1,10 @@
[package]
name = "graphene-core"
version = "0.1.0"
edition = "2021"
description = "Api definitions for graphene"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -1,12 +1,6 @@
#![feature(generic_associated_types)]
//#![deny(rust_2018_idioms)]
use std::{any::Any, borrow::Borrow};
mod iter;
pub mod nodes;
use iter::insert_after_nth;
use nodes::*;
#[rustfmt::skip]
pub trait Node {
// Self: 'a means that Self has to live at least as long as 'a (the input and output)
@ -39,20 +33,6 @@ impl<T: Node> AnyRef for T {
}
}
pub trait DefaultNode: Default {
fn default_node() -> ValueNode<Self> {
ValueNode::new(Self::default())
}
}
impl<T: std::default::Default> DefaultNode for T {}
pub trait After: Sized {
fn after<'a, First: Node>(&'a self, first: &'a First) -> ComposeNode<'a, First, Self> {
ComposeNode::new(first, self)
}
}
impl<Second: Node> After for Second {}
pub trait Exec: Node
where
for<'a> &'a (): Borrow<<Self as Node>::Input<'a>>,
@ -67,20 +47,3 @@ pub trait DynamicInput {
fn set_kwarg_by_name(&mut self, name: &str, value: &dyn Any);
fn set_arg_by_index(&mut self, index: usize, value: &dyn Any);
}
fn main() {
let int = IntNode::<32>;
let add: u32 = AddNode::<u32>::default().eval((int.exec(), int.exec()));
let fnode = FnNode::new(|(a, b): &(i32, i32)| a - b);
//let sub = fnode.any(&("a", 2));
let cache = CacheNode::new(&fnode);
let foo = cache.eval(&(2, 3));
/*
let curry: CurryNthArgNode<'_, _, _, u32, u32, 0> = CurryNthArgNode::new(&AddNode, &int);
let composition = curry.after(&curry);
let n = ValueNode::new(10_u32);
let curry: CurryNthArgNode<'_, _, _, u32, _, 0> = CurryNthArgNode::new(&composition, &n);
*/
println!("{}", foo)
}

1319
node-graph/gstd/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,25 @@
[package]
name = "graphene-std"
version = "0.1.0"
edition = "2021"
description = "Graphene standard library"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
rust_analyzer = ["ide", "ide_db"]
caching = ["storage-map", "lock_api", "parking_lot"]
derive = ["graph-proc-macros"]
memoization = ["once_cell"]
default = ["derive", "memoization"]
[dependencies]
graphene-core = {path = "../gcore"}
graph-proc-macros = {path = "../proc-macro", optional = true}
once_cell = {version= "1.10", optional = true}
ide = { version = "*", package = "ra_ap_ide", optional = true }
ide_db = { version = "*", package = "ra_ap_ide_db" , optional = true }
storage-map = { version = "*", optional = true }
lock_api = { version= "*", optional = true }
parking_lot = { version = "*", optional = true }

View file

@ -0,0 +1,48 @@
use parking_lot::RawRwLock;
use std::{
any::Any,
borrow::Borrow,
cell::RefCell,
collections::{hash_map::DefaultHasher, HashMap},
hash::{Hash, Hasher},
iter,
iter::Sum,
marker::PhantomData,
};
use storage_map::{StorageMap, StorageMapGuard};
use graphene_api::{DynamicInput, Node};
/// Caches the output of a given Node and acts as a proxy
/// Automatically resets if it receives different input
pub struct SmartCacheNode<'n, 'c, NODE: Node + 'c> {
node: &'n NODE,
map: StorageMap<RawRwLock, HashMap<u64, CacheNode<'n, 'c, NODE>>>,
}
impl<'n: 'c, 'c, NODE: Node + 'c> Node for SmartCacheNode<'n, 'c, NODE>
where
for<'a> NODE::Input<'a>: Hash,
{
type Input<'a> = NODE::Input<'a> where Self: 'a, 'c : 'a;
type Output<'a> = StorageMapGuard<'a, RawRwLock, CacheNode<'n, 'c, NODE>> where Self: 'a, 'c: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
let mut hasher = DefaultHasher::new();
input.borrow().hash(&mut hasher);
let hash = hasher.finish();
self.map
.get_or_create_with(&hash, || CacheNode::new(self.node))
}
}
impl<'n, 'c, NODE: Node> SmartCacheNode<'n, 'c, NODE> {
pub fn clear(&'n mut self) {
self.map = StorageMap::default();
}
pub fn new(node: &'n NODE) -> SmartCacheNode<'n, 'c, NODE> {
SmartCacheNode {
node,
map: StorageMap::default(),
}
}
}

View file

@ -0,0 +1,39 @@
use std::{borrow::Borrow, marker::PhantomData};
use graphene_core::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;
type Input<'a> = In where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
self.0(input.borrow())
}
}
impl<T: Fn(&In) -> O, In, O> FnNode<T, In, O> {
pub fn new(f: T) -> Self {
FnNode(f, PhantomData::default(), PhantomData::default())
}
}
pub struct FnNodeWithState<T: Fn(&In, &State) -> O, In, O, State>(
T,
State,
PhantomData<In>,
PhantomData<O>,
);
impl<T: Fn(&In, &State) -> O, In, O, State> Node for FnNodeWithState<T, In, O, State> {
type Output<'a> = O where Self: 'a;
type Input<'a> = In where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
self.0(input.borrow(), &self.1)
}
}
impl<T: Fn(&In, &State) -> O, In, O, State> FnNodeWithState<T, In, O, State> {
pub fn new(f: T, state: State) -> Self {
FnNodeWithState(f, state, PhantomData::default(), PhantomData::default())
}
}

View file

@ -0,0 +1,10 @@
#![feature(generic_associated_types)]
#[cfg(feature = "caching")]
pub mod caching;
pub mod generic;
#[cfg(feature = "memoization")]
pub mod memo;
pub mod ops;
pub mod structural;
pub mod value;

View file

@ -0,0 +1,13 @@
use graphene_core::{Exec, Node};
use graphene_std::*;
fn main() {
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);
//let sub = fnode.any(&("a", 2));
let cache = memo::CacheNode::new(&fnode);
let cached_result = cache.eval(&(2, 3));
println!("{}", cached_result)
}

View file

@ -0,0 +1,28 @@
use graphene_core::Node;
use once_cell::sync::OnceCell;
use std::borrow::Borrow;
/// Caches the output of a given Node and acts as a proxy
pub struct CacheNode<'n, 'c, CachedNode: Node + 'c> {
node: &'n CachedNode,
cache: OnceCell<CachedNode::Output<'c>>,
}
impl<'n: 'c, 'c, CashedNode: Node> Node for CacheNode<'n, 'c, CashedNode> {
type Output<'a> = &'a CashedNode::Output<'c> where 'c: 'a;
type Input<'a> = CashedNode::Input<'c> where 'c: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
self.cache.get_or_init(|| self.node.eval(input))
}
}
impl<'n, 'c, CachedNode: Node> CacheNode<'n, 'c, CachedNode> {
pub fn clear(&'n mut self) {
self.cache = OnceCell::new();
}
pub fn new(node: &'n CachedNode) -> CacheNode<'n, 'c, CachedNode> {
CacheNode {
node,
cache: OnceCell::new(),
}
}
}

View file

@ -0,0 +1,37 @@
use std::{borrow::Borrow, marker::PhantomData};
use graphene_core::Node;
#[derive(Default)]
pub struct AddNode<T>(PhantomData<T>);
impl<T: std::ops::Add + 'static + Copy> Node for AddNode<T> {
type Output<'a> = <T as std::ops::Add>::Output;
type Input<'a> = (T, T);
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> T::Output {
input.borrow().0 + input.borrow().1
}
}
#[derive(Default)]
/// Destructures a Tuple of two values and returns the first one
pub struct FstNode<T, U>(PhantomData<T>, PhantomData<U>);
impl<T: Copy, U> Node for FstNode<T, U> {
type Output<'a> = &'a T where Self: 'a;
type Input<'a> = &'a (T, U) where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
let &(ref a, _) = input.borrow();
a
}
}
#[derive(Default)]
/// Destructures a Tuple of two values and returns the first one
pub struct SndNode<T, U>(PhantomData<T>, PhantomData<U>);
impl<T, U: Copy> Node for SndNode<T, U> {
type Output<'a> = &'a U where Self: 'a;
type Input<'a> = &'a (T, U) where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
let &(_, ref b) = input.borrow();
b
}
}

View file

@ -0,0 +1,60 @@
use std::{any::Any, borrow::Borrow};
use graphene_core::{DynamicInput, Node};
pub struct ComposeNode<'n, FIRST, SECOND> {
first: &'n FIRST,
second: &'n SECOND,
}
impl<'n, FIRST, SECOND> Node for ComposeNode<'n, FIRST, SECOND>
where
FIRST: Node,
SECOND: Node,
for<'a> FIRST::Output<'a>: Borrow<SECOND::Input<'a>>,
{
type Input<'a> = FIRST::Input<'a> where Self: 'a;
type Output<'a> = SECOND::Output<'a> where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
// evaluate the first node with the given input
// and then pipe the result from the first computation
// into the second node
let arg = self.first.eval(input);
self.second.eval(arg)
}
}
impl<'n, FIRST, SECOND> ComposeNode<'n, FIRST, SECOND>
where
FIRST: Node,
{
pub fn new(first: &'n FIRST, second: &'n SECOND) -> Self {
ComposeNode::<'n, FIRST, SECOND> { first, second }
}
}
pub trait After: Sized {
fn after<'a, First: Node>(&'a self, first: &'a First) -> ComposeNode<'a, First, Self> {
ComposeNode::new(first, self)
}
}
impl<Second: Node> After for Second {}
pub struct ProxyNode<T: DynamicInput>(T);
impl<T: DynamicInput> Node for ProxyNode<T> {
type Output<'a> = &'a T where Self: 'a;
type Input<'a> = &'a () where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> Self::Output<'a> {
&self.0
}
}
impl<T: DynamicInput> DynamicInput for ProxyNode<T> {
fn set_kwarg_by_name(&mut self, name: &str, value: &dyn Any) {
self.0.set_kwarg_by_name(name, value)
}
fn set_arg_by_index(&mut self, index: usize, value: &dyn Any) {
self.0.set_arg_by_index(index, value)
}
}

View file

@ -0,0 +1,38 @@
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())
}
}

View file

@ -7,33 +7,45 @@ name = "graph-proc-macros"
version = "0.1.0"
dependencies = [
"proc-macro2",
"proc_macro_roids",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.27"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
name = "proc_macro_roids"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
checksum = "06675fa2c577f52bcf77fbb511123927547d154faa08097cc012c66ec3c9611a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "quote"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "1.0.73"
version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f"
dependencies = [
"proc-macro2",
"quote",

View file

@ -10,6 +10,8 @@ path = "src/lib.rs"
proc-macro = true
[dependencies]
proc-macro2 = "1.0.26"
syn = { version = "1.0.68", features = ["full"] }
quote = "1.0.9"
proc-macro2 = "1.0"
proc_macro_roids = "0.7"
syn = { version = "1.0", features = ["full"] }
quote = "1.0"
graphene-core = {path = "../gcore"}

View file

@ -1,4 +1,6 @@
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};
@ -55,10 +57,8 @@ fn generate_to_string(parsed: ItemFn, string: String) -> TokenStream {
.map(|t| t.to_token_stream())
.collect::<Vec<_>>();
let node_fn_name = syn::Ident::new(
&(fn_name.to_string() + "_node"),
proc_macro2::Span::call_site(),
); // function name/identifier
let node_fn_name = fn_name.append("_node");
let struct_name = fn_name.append("_node");
let return_type_string = fn_return_type
.to_token_stream()
.to_string()
@ -72,6 +72,13 @@ fn generate_to_string(parsed: ItemFn, string: String) -> TokenStream {
let x = quote! {
//#whole_function
mod #fn_name {
struct #struct_name {
}
impl
}
fn #node_fn_name #generics() -> Node<'static> {
Node { func: Box::new(move |x| {
let args = x.downcast::<(#(#types,)*)>().expect(#error);

View file

@ -1,38 +0,0 @@
#[derive(Clone)]
pub struct InsertAfterNth<A>
where
A: Iterator,
{
n: usize,
iter: A,
value: Option<A::Item>,
}
impl<A> Iterator for InsertAfterNth<A>
where
A: Iterator,
{
type Item = A::Item;
fn next(&mut self) -> Option<Self::Item> {
match self.n {
1.. => {
self.n -= 1;
self.iter.next()
}
0 if self.value.is_some() => self.value.take(),
_ => self.iter.next(),
}
}
}
pub fn insert_after_nth<A>(n: usize, iter: A, value: A::Item) -> InsertAfterNth<A>
where
A: Iterator,
{
InsertAfterNth {
n,
iter,
value: Some(value),
}
}

View file

@ -1,269 +0,0 @@
use std::{
any::Any,
borrow::Borrow,
cell::RefCell,
collections::{hash_map::DefaultHasher, HashMap},
hash::{Hash, Hasher},
iter,
iter::Sum,
marker::PhantomData,
};
use crate::{insert_after_nth, After, DynamicInput, Node};
use once_cell::sync::OnceCell;
use parking_lot::RawRwLock;
use storage_map::{StorageMap, StorageMapGuard};
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
}
}
impl<T> ValueNode<T> {
pub fn new(value: T) -> ValueNode<T> {
ValueNode(value)
}
}
#[derive(Default)]
pub struct AddNode<T>(PhantomData<T>);
impl<T: std::ops::Add + 'static + Copy> Node for AddNode<T> {
type Output<'a> = <T as std::ops::Add>::Output;
type Input<'a> = (T, T);
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> T::Output {
input.borrow().0 + input.borrow().1
}
}
#[derive(Default)]
/// Destructures a Tuple of two values and returns the first one
pub struct FstNode<T, U>(PhantomData<T>, PhantomData<U>);
impl<T: Copy, U> Node for FstNode<T, U> {
type Output<'a> = &'a T where Self: 'a;
type Input<'a> = &'a (T, U) where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
let &(ref a, _) = input.borrow();
a
}
}
#[derive(Default)]
/// Destructures a Tuple of two values and returns the first one
pub struct SndNode<T, U>(PhantomData<T>, PhantomData<U>);
impl<T, U: Copy> Node for SndNode<T, U> {
type Output<'a> = &'a U where Self: 'a;
type Input<'a> = &'a (T, U) where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
let &(_, ref b) = input.borrow();
b
}
}
pub struct ComposeNode<'n, FIRST, SECOND> {
first: &'n FIRST,
second: &'n SECOND,
}
impl<'n, FIRST, SECOND> Node for ComposeNode<'n, FIRST, SECOND>
where
FIRST: Node,
SECOND: Node,
for<'a> FIRST::Output<'a>: Borrow<SECOND::Input<'a>>,
{
type Input<'a> = FIRST::Input<'a> where Self: 'a;
type Output<'a> = SECOND::Output<'a> where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
// evaluate the first node with the given input
// and then pipe the result from the first computation
// into the second node
let arg = self.first.eval(input);
self.second.eval(arg)
}
}
impl<'n, FIRST, SECOND> ComposeNode<'n, FIRST, SECOND>
where
FIRST: Node,
{
pub fn new(first: &'n FIRST, second: &'n SECOND) -> Self {
ComposeNode::<'n, FIRST, SECOND> { first, second }
}
}
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;
type Input<'a> = In where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
self.0(input.borrow())
}
}
impl<T: Fn(&In) -> O, In, O> FnNode<T, In, O> {
pub fn new(f: T) -> Self {
FnNode(f, PhantomData::default(), PhantomData::default())
}
}
pub struct FnNodeWithState<T: Fn(&In, &State) -> O, In, O, State>(
T,
State,
PhantomData<In>,
PhantomData<O>,
);
impl<T: Fn(&In, &State) -> O, In, O, State> Node for FnNodeWithState<T, In, O, State> {
type Output<'a> = O where Self: 'a;
type Input<'a> = In where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
self.0(input.borrow(), &self.1)
}
}
impl<T: Fn(&In, &State) -> O, In, O, State> FnNodeWithState<T, In, O, State> {
pub fn new(f: T, state: State) -> Self {
FnNodeWithState(f, state, PhantomData::default(), PhantomData::default())
}
}
/// Caches the output of a given Node and acts as a proxy
pub struct CacheNode<'n, 'c, CachedNode: Node + 'c> {
node: &'n CachedNode,
cache: OnceCell<CachedNode::Output<'c>>,
}
impl<'n: 'c, 'c, CashedNode: Node> Node for CacheNode<'n, 'c, CashedNode> {
type Output<'a> = &'a CashedNode::Output<'c> where 'c: 'a;
type Input<'a> = CashedNode::Input<'c> where 'c: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
self.cache.get_or_init(|| self.node.eval(input))
}
}
impl<'n, 'c, CachedNode: Node> CacheNode<'n, 'c, CachedNode> {
pub fn clear(&'n mut self) {
self.cache = OnceCell::new();
}
pub fn new(node: &'n CachedNode) -> CacheNode<'n, 'c, CachedNode> {
CacheNode {
node,
cache: OnceCell::new(),
}
}
}
pub struct ProxyNode<T: DynamicInput>(T);
impl<T: DynamicInput> Node for ProxyNode<T> {
type Output<'a> = &'a T where Self: 'a;
type Input<'a> = &'a () where Self: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> Self::Output<'a> {
&self.0
}
}
impl<T: DynamicInput> DynamicInput for ProxyNode<T> {
fn set_kwarg_by_name(&mut self, name: &str, value: &dyn Any) {
self.0.set_kwarg_by_name(name, value)
}
fn set_arg_by_index(&mut self, index: usize, value: &dyn Any) {
self.0.set_arg_by_index(index, value)
}
}
/// Caches the output of a given Node and acts as a proxy
/// Automatically resets if it receives different input
pub struct SmartCacheNode<'n, 'c, NODE: Node + 'c> {
node: &'n NODE,
map: StorageMap<RawRwLock, HashMap<u64, CacheNode<'n, 'c, NODE>>>,
}
impl<'n: 'c, 'c, NODE: Node + 'c> Node for SmartCacheNode<'n, 'c, NODE>
where
for<'a> NODE::Input<'a>: Hash,
{
type Input<'a> = NODE::Input<'a> where Self: 'a, 'c : 'a;
type Output<'a> = StorageMapGuard<'a, RawRwLock, CacheNode<'n, 'c, NODE>> where Self: 'a, 'c: 'a;
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
let mut hasher = DefaultHasher::new();
input.borrow().hash(&mut hasher);
let hash = hasher.finish();
self.map
.get_or_create_with(&hash, || CacheNode::new(self.node))
}
}
impl<'n, 'c, NODE: Node> SmartCacheNode<'n, 'c, NODE> {
pub fn clear(&'n mut self) {
self.map = StorageMap::default();
}
pub fn new(node: &'n NODE) -> SmartCacheNode<'n, 'c, NODE> {
SmartCacheNode {
node,
map: StorageMap::default(),
}
}
}
/*
pub struct CurryNthArgNode<
'n,
CurryNode: Node<'n, OUT>,
ArgNode: Node<'n, ARG>,
ARG: Clone,
OUT,
const NTH: usize,
> {
node: &'n CurryNode,
arg: CacheNode<'n, ArgNode, ARG>,
_phantom_out: std::marker::PhantomData<OUT>,
_phantom_arg: std::marker::PhantomData<ARG>,
}
impl<
'n,
CurryNode: Node<'n, OUT>,
ArgNode: Node<'n, ARG>,
ARG: 'static + Clone,
OUT,
const NTH: usize,
> Node<'n, OUT> for CurryNthArgNode<'n, CurryNode, ArgNode, ARG, OUT, NTH>
{
fn eval(&'n self, input: impl Iterator<Item = &'n dyn Any> + Clone) -> OUT {
let arg = self.arg.eval(iter::empty());
let arg: &dyn Any = arg as &dyn Any;
self.node.eval(insert_after_nth(NTH, input, arg))
}
}
impl<'n, CurryNode: Node<'n, Out>, ArgNode: Node<'n, Arg>, Arg: Clone, Out, const Nth: usize>
CurryNthArgNode<'n, CurryNode, ArgNode, Arg, Out, Nth>
{
pub fn new(node: &'n CurryNode, arg: &'n ArgNode) -> Self {
CurryNthArgNode::<'n, CurryNode, ArgNode, Arg, Out, Nth> {
node,
arg: CacheNode::new(arg),
_phantom_out: PhantomData::default(),
_phantom_arg: PhantomData::default(),
}
}
}
*/
/*
*/