diff --git a/node-graph/Cargo.lock b/node-graph/Cargo.lock index a2293598..7b605df3 100644 --- a/node-graph/Cargo.lock +++ b/node-graph/Cargo.lock @@ -367,9 +367,12 @@ version = "0.1.0" dependencies = [ "dashmap 5.2.0", "graph-proc-macros", + "lock_api", "once_cell", + "parking_lot 0.11.1", "ra_ap_ide", "ra_ap_ide_db", + "storage-map", ] [[package]] @@ -1040,6 +1043,15 @@ dependencies = [ "serde", ] +[[package]] +name = "storage-map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418bb14643aa55a7841d5303f72cf512cfb323b8cc221d51580500a1ca75206c" +dependencies = [ + "lock_api", +] + [[package]] name = "syn" version = "1.0.73" diff --git a/node-graph/Cargo.toml b/node-graph/Cargo.toml index b42c7a02..27a8d8a4 100644 --- a/node-graph/Cargo.toml +++ b/node-graph/Cargo.toml @@ -14,3 +14,6 @@ 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 = "*" diff --git a/node-graph/src/main.rs b/node-graph/src/main.rs index f9ec98b3..444768ae 100644 --- a/node-graph/src/main.rs +++ b/node-graph/src/main.rs @@ -22,22 +22,42 @@ pub trait AnyRef: Node { where Self::Input<'a>: 'static + Copy; } + impl AnyRef for T { fn any<'a>(&'a self, input: &'a dyn Any) -> Self::Output<'a> where Self::Input<'a>: 'static + Copy, { - self.eval::<&Self::Input<'a>>(input.downcast_ref::>().unwrap()) + self.eval::<&Self::Input<'a>>(input.downcast_ref::>().unwrap_or_else( + || { + panic!( + "Node was evaluated with wrong input. The input has to be of type: {}", + std::any::type_name::>(), + ) + }, + )) } } -trait After { - fn after<'a, FIRST: Node>(&'a self, first: &'a FIRST) -> ComposeNode<'a, FIRST, SECOND>; +trait DefaultNode: Default { + fn default_node() -> ValueNode { + ValueNode::new(Self::default()) + } } +impl DefaultNode for T {} + +trait After: Sized { + fn after<'a, First: Node>(&'a self, first: &'a First) -> ComposeNode<'a, First, Self> { + ComposeNode::new(first, self) + } +} +impl After for Second {} fn main() { let int = IntNode::<32>; - let add: u32 = AddNode::::default().any(&(int.eval(&()), int.eval(&())) as &dyn Any); + let add: u32 = AddNode::::default().eval((int.eval(&()), int.eval(&()))); + let fnode = FnNode::new(|(a, b): &(i32, i32)| a - b); + let sub = fnode.any(&("a", 2)); /* let curry: CurryNthArgNode<'_, _, _, u32, u32, 0> = CurryNthArgNode::new(&AddNode, &int); @@ -45,5 +65,5 @@ fn main() { let n = ValueNode::new(10_u32); let curry: CurryNthArgNode<'_, _, _, u32, _, 0> = CurryNthArgNode::new(&composition, &n); */ - println!("{}", add) + println!("{}", sub) } diff --git a/node-graph/src/nodes.rs b/node-graph/src/nodes.rs index f2a5bc66..5cb9a65f 100644 --- a/node-graph/src/nodes.rs +++ b/node-graph/src/nodes.rs @@ -1,10 +1,18 @@ use std::{ - any::Any, borrow::Borrow, collections::hash_map::DefaultHasher, hash::Hasher, iter, iter::Sum, + 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, Node}; use once_cell::sync::OnceCell; +use parking_lot::RawRwLock; +use storage_map::{StorageMap, StorageMapGuard}; pub struct IntNode; impl Node for IntNode { @@ -41,31 +49,6 @@ impl Node for AddNode { } } -/// Caches the output of a given Node and acts as a proxy -pub struct CachingNode<'n, 'c, CachedNode: Node + 'c> { - node: &'n CachedNode, - cache: OnceCell>, -} -impl<'n: 'c, 'c, CashedNode: Node> Node for CachingNode<'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>>(&'a self, input: I) -> Self::Output<'a> { - self.cache.get_or_init(|| self.node.eval(input)) - } -} - -impl<'n, 'c, CachedNode: Node> CachingNode<'n, 'c, CachedNode> { - pub fn clear(&'n mut self) { - self.cache = OnceCell::new(); - } - pub fn new(node: &'n CachedNode) -> CachingNode<'n, 'c, CachedNode> { - CachingNode { - node, - cache: OnceCell::new(), - } - } -} - pub struct ComposeNode<'n, FIRST, SECOND> { first: &'n FIRST, second: &'n SECOND, @@ -98,11 +81,64 @@ where } } -impl<'n, SECOND: Node> After for SECOND { - fn after<'a, FIRST: Node>(&'a self, first: &'a FIRST) -> ComposeNode<'a, FIRST, SECOND> { - ComposeNode::<'a, FIRST, SECOND> { - first, - second: self, +pub struct FnNode O, In, O>(T, PhantomData, PhantomData); +impl O, In, O> Node for FnNode { + type Output<'a> = O where Self: 'a; + type Input<'a> = In where Self: 'a; + + fn eval<'a, I: Borrow>>(&'a self, input: I) -> Self::Output<'a> { + self.0(input.borrow()) + } +} + +impl O, In, O> FnNode { + pub fn new(f: T) -> Self { + FnNode(f, PhantomData::default(), PhantomData::default()) + } +} + +pub struct FnNodeWithState O, In, O, State>( + T, + State, + PhantomData, + PhantomData, +); +impl O, In, O, State> Node for FnNodeWithState { + type Output<'a> = O where Self: 'a; + type Input<'a> = In where Self: 'a; + + fn eval<'a, I: Borrow>>(&'a self, input: I) -> Self::Output<'a> { + self.0(input.borrow(), &self.1) + } +} + +impl O, In, O, State> FnNodeWithState { + 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>, +} +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>>(&'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(), } } } @@ -110,52 +146,77 @@ impl<'n, SECOND: Node> After for SECOND { /* /// Caches the output of a given Node and acts as a proxy /// Automatically resets if it receives different input -pub struct SmartCacheNode<'n, NODE: Node<'n, OUT>, OUT: Clone> { - node: &'n NODE, - map: dashmap::DashMap>, -} -impl<'n, NODE: for<'a> Node<'a, OUT>, OUT: Clone> Node<'n, &'n CacheNode<'n, NODE, OUT>> - for SmartCacheNode<'n, NODE, OUT> +struct SmartCacheNode<'n, 'c, NODE: Node + 'c> +where + for<'a> NODE::Input<'a>: Hash, { - fn eval( - &'n self, - input: impl Iterator + Clone, - ) -> &'n CacheNode<'n, NODE, OUT> { + cache: InnerSmartCacheNode<'n, 'c, NODE>, +} +impl<'n: 'c, 'c, NODE: Node> 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> = &'a NODE::Output<'a> where Self: 'a, 'c: 'a; + fn eval<'a, I: Borrow>>(&'a self, input: I) -> Self::Output<'a> { let mut hasher = DefaultHasher::new(); - input.clone().for_each(|value| unsafe { - hasher.write(std::slice::from_raw_parts( - value as *const dyn Any as *const u8, - std::mem::size_of_val(value), - )) - }); + input.borrow().hash(&mut hasher); let hash = hasher.finish(); - self.map.entry(hash).or_insert(CacheNode::new(self.node)); - fn map<'a, 'c, 'd, N, OUT: Clone>( - _key: &'a u64, - node: &'c CacheNode<'d, N, OUT>, - ) -> &'c CacheNode<'b, N, OUT> - where - N: for<'b> Node<'b, OUT>, - { - node - } - let foo: Option<&CacheNode<'n, NODE, OUT>> = self.map.view(&hash, map); - foo.unwrap() + + let node = self.cache.eval(input); + node.eval(input); + todo!() } } -impl<'n, NODE: Node<'n, OUT>, OUT: Clone> SmartCacheNode<'n, NODE, OUT> { - fn clear(&'n mut self) { - self.map.clear(); +impl<'n, 'c, NODE: Node> SmartCacheNode<'n, 'c, NODE> +where + for<'a> NODE::Input<'a>: Hash, +{ + pub fn clear(&'n mut self) { + self.cache.clear(); } - fn new(node: &'n NODE) -> SmartCacheNode<'n, NODE, OUT> { + pub fn new(node: &'n NODE) -> SmartCacheNode<'n, 'c, NODE> { SmartCacheNode { - node, - map: dashmap::DashMap::new(), + cache: InnerSmartCacheNode::new(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>>, +} +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>>(&'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<