use crate::Node; use core::future::Future; #[cfg(feature = "alloc")] use alloc::sync::Arc; use core::cell::Cell; use core::marker::PhantomData; use core::pin::Pin; // Caches the output of a given Node and acts as a proxy #[derive(Default)] pub struct MemoNode { cache: Cell>, node: CachedNode, } impl<'i, 'o: 'i, T: 'i + Clone + 'o, CachedNode: 'i> Node<'i, ()> for MemoNode where CachedNode: for<'any_input> Node<'any_input, ()>, for<'a> >::Output: core::future::Future + 'a, { // TODO: This should return a reference to the cached cached_value // but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty acurate xD type Output = Pin + 'i>>; fn eval(&'i self, input: ()) -> Pin + 'i>> { Box::pin(async move { if let Some(cached_value) = self.cache.take() { self.cache.set(Some(cached_value.clone())); cached_value } else { let value = self.node.eval(input).await; self.cache.set(Some(value.clone())); value } }) } fn reset(&self) { self.cache.set(None); } } impl MemoNode { pub const fn new(node: CachedNode) -> MemoNode { MemoNode { cache: Cell::new(None), node } } } #[derive(Clone, Debug)] pub struct IORecord { pub input: I, pub output: O, } #[cfg(feature = "alloc")] /// Caches the output of the last graph evaluation for introspection #[derive(Default)] pub struct MonitorNode { io: Cell>>>, node: N, } #[cfg(feature = "alloc")] impl<'i, 'a: 'i, T, I, N> Node<'i, I> for MonitorNode where I: Clone + 'static, >::Output: Future, T: Clone + 'static, N: Node<'i, I>, { type Output = Pin + 'i>>; fn eval(&'i self, input: I) -> Self::Output { Box::pin(async move { let output = self.node.eval(input.clone()).await; self.io.set(Some(Arc::new(IORecord { input, output: output.clone() }))); output }) } fn serialize(&self) -> Option> { let io = self.io.take(); self.io.set(io.clone()); (io).as_ref().map(|output| output.clone() as Arc) } } #[cfg(feature = "alloc")] impl MonitorNode { pub const fn new(node: N) -> MonitorNode { MonitorNode { io: Cell::new(None), node } } } // Caches the output of a given Node and acts as a proxy /// It provides two modes of operation, it can either be set /// when calling the node with a `Some` variant or the last /// value that was added is returned when calling it with `None` #[derive(Default)] pub struct LetNode { // We have to use an append only data structure to make sure the references // to the cache entries are always valid // TODO: We only ever access the last value so there is not really a reason for us // to store the previous entries. This should be reworked in the future cache: Cell>, } impl<'i, T: 'i + Clone> Node<'i, Option> for LetNode { type Output = T; fn eval(&'i self, input: Option) -> Self::Output { if let Some(input) = input { self.cache.set(Some(input.clone())); input } else { let value = self.cache.take(); self.cache.set(value.clone()); value.expect("LetNode was not initialized. This can happen if you try to evaluate a node that depends on the EditorApi in the node_registry") } } fn reset(&self) { self.cache.set(None); } } impl LetNode { pub fn new() -> LetNode { LetNode { cache: Default::default() } } } /// Caches the output of a given Node and acts as a proxy #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct EndLetNode { input: Input, paramenter: PhantomData, } impl<'i, T: 'i, Parameter: 'i + From, Input> Node<'i, T> for EndLetNode where Input: Node<'i, Parameter>, { type Output = ::Output; fn eval(&'i self, t: T) -> Self::Output { let result = self.input.eval(Parameter::from(t)); result } } impl EndLetNode { pub const fn new(input: Input) -> EndLetNode { EndLetNode { input, paramenter: PhantomData } } } pub use crate::ops::SomeNode as InitNode; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct RefNode { let_node: Let, _t: PhantomData, } impl<'i, T: 'i, Let> Node<'i, ()> for RefNode where Let: for<'a> Node<'a, Option>, { type Output = >>::Output; fn eval(&'i self, _: ()) -> Self::Output { self.let_node.eval(None) } } impl RefNode { pub const fn new(let_node: Let) -> RefNode { RefNode { let_node, _t: PhantomData } } }