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, Node}; use once_cell::sync::OnceCell; use parking_lot::RawRwLock; use storage_map::{StorageMap, StorageMapGuard}; 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 } } impl ValueNode { pub fn new(value: T) -> ValueNode { ValueNode(value) } } #[derive(Default)] pub struct AddNode(PhantomData); impl Node for AddNode { type Output<'a> = ::Output; type Input<'a> = (T, T); fn eval<'a, I: Borrow>>(&'a self, input: I) -> T::Output { input.borrow().0 + input.borrow().1 } } 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>, { type Input<'a> = FIRST::Input<'a> where Self: 'a; type Output<'a> = SECOND::Output<'a> where Self: 'a; fn eval<'a, I: Borrow>>(&'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 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(), } } } /* /// Caches the output of a given Node and acts as a proxy /// Automatically resets if it receives different input struct SmartCacheNode<'n, 'c, NODE: Node + 'c> where for<'a> NODE::Input<'a>: Hash, { 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.borrow().hash(&mut hasher); let hash = hasher.finish(); let node = self.cache.eval(input); node.eval(input); todo!() } } 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(); } pub fn new(node: &'n NODE) -> SmartCacheNode<'n, 'c, NODE> { SmartCacheNode { 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< '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, _phantom_arg: std::marker::PhantomData, } 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 + 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(), } } } */ /* */