Download node-graph/gcore/src/memo.rs from openfree/graphite2: direct link, hf CLI and curl.
- Browser
- Download file 6.26 kB
-
https://huggingface.co/spaces/openfree/graphite2/resolve/main/node-graph/gcore/src/memo.rs
- Command line
-
hf download hf://spaces/openfree/graphite2/node-graph/gcore/src/memo.rs
-
curl -L -o memo.rs https://huggingface.co/spaces/openfree/graphite2/resolve/main/node-graph/gcore/src/memo.rs
6.26 kB
| use crate::{Node, WasmNotSend}; | |
| use dyn_any::DynFuture; | |
| use std::future::Future; | |
| use std::hash::DefaultHasher; | |
| use std::ops::Deref; | |
| use std::sync::Arc; | |
| use std::sync::Mutex; | |
| /// Caches the output of a given Node and acts as a proxy | |
| pub struct MemoNode<T, CachedNode> { | |
| cache: Arc<Mutex<Option<(u64, T)>>>, | |
| node: CachedNode, | |
| } | |
| impl<'i, I: Hash + 'i, T: 'i + Clone + WasmNotSend, CachedNode: 'i> Node<'i, I> for MemoNode<T, CachedNode> | |
| where | |
| CachedNode: for<'any_input> Node<'any_input, I>, | |
| for<'a> <CachedNode as Node<'a, I>>::Output: Future<Output = T> + WasmNotSend, | |
| { | |
| // 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 accurate xD | |
| type Output = DynFuture<'i, T>; | |
| fn eval(&'i self, input: I) -> Self::Output { | |
| let mut hasher = DefaultHasher::new(); | |
| input.hash(&mut hasher); | |
| let hash = hasher.finish(); | |
| if let Some(data) = self.cache.lock().as_ref().unwrap().as_ref().and_then(|data| (data.0 == hash).then_some(data.1.clone())) { | |
| Box::pin(async move { data }) | |
| } else { | |
| let fut = self.node.eval(input); | |
| let cache = self.cache.clone(); | |
| Box::pin(async move { | |
| let value = fut.await; | |
| *cache.lock().unwrap() = Some((hash, value.clone())); | |
| value | |
| }) | |
| } | |
| } | |
| fn reset(&self) { | |
| self.cache.lock().unwrap().take(); | |
| } | |
| } | |
| impl<T, CachedNode> MemoNode<T, CachedNode> { | |
| pub fn new(node: CachedNode) -> MemoNode<T, CachedNode> { | |
| MemoNode { cache: Default::default(), node } | |
| } | |
| } | |
| /// Caches the output of a given Node and acts as a proxy. | |
| /// In contrast to the regular `MemoNode`. This node ignores all input. | |
| /// Using this node might result in the document not updating properly, | |
| /// use with caution. | |
| pub struct ImpureMemoNode<I, T, CachedNode> { | |
| cache: Arc<Mutex<Option<T>>>, | |
| node: CachedNode, | |
| _phantom: std::marker::PhantomData<I>, | |
| } | |
| impl<'i, I: 'i, T: 'i + Clone + WasmNotSend, CachedNode: 'i> Node<'i, I> for ImpureMemoNode<I, T, CachedNode> | |
| where | |
| CachedNode: for<'any_input> Node<'any_input, I>, | |
| for<'a> <CachedNode as Node<'a, I>>::Output: Future<Output = T> + WasmNotSend, | |
| { | |
| // 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 accurate xD | |
| type Output = DynFuture<'i, T>; | |
| fn eval(&'i self, input: I) -> Self::Output { | |
| if let Some(cached_value) = self.cache.lock().as_ref().unwrap().deref() { | |
| let data = cached_value.clone(); | |
| Box::pin(async move { data }) | |
| } else { | |
| let fut = self.node.eval(input); | |
| let cache = self.cache.clone(); | |
| Box::pin(async move { | |
| let value = fut.await; | |
| *cache.lock().unwrap() = Some(value.clone()); | |
| value | |
| }) | |
| } | |
| } | |
| fn reset(&self) { | |
| self.cache.lock().unwrap().take(); | |
| } | |
| } | |
| impl<T, I, CachedNode> ImpureMemoNode<I, T, CachedNode> { | |
| pub fn new(node: CachedNode) -> ImpureMemoNode<I, T, CachedNode> { | |
| ImpureMemoNode { | |
| cache: Default::default(), | |
| node, | |
| _phantom: std::marker::PhantomData, | |
| } | |
| } | |
| } | |
| /// Stores both what a node was called with and what it returned. | |
| pub struct IORecord<I, O> { | |
| pub input: I, | |
| pub output: O, | |
| } | |
| /// Caches the output of the last graph evaluation for introspection | |
| pub struct MonitorNode<I, T, N> { | |
| io: Arc<Mutex<Option<Arc<IORecord<I, T>>>>>, | |
| node: N, | |
| } | |
| impl<'i, T, I, N> Node<'i, I> for MonitorNode<I, T, N> | |
| where | |
| I: Clone + 'static + Send + Sync, | |
| T: Clone + 'static + Send + Sync, | |
| for<'a> N: Node<'a, I, Output: Future<Output = T> + WasmNotSend> + 'i, | |
| { | |
| type Output = DynFuture<'i, T>; | |
| fn eval(&'i self, input: I) -> Self::Output { | |
| let io = self.io.clone(); | |
| let output_fut = self.node.eval(input.clone()); | |
| Box::pin(async move { | |
| let output = output_fut.await; | |
| *io.lock().unwrap() = Some(Arc::new(IORecord { input, output: output.clone() })); | |
| output | |
| }) | |
| } | |
| fn serialize(&self) -> Option<Arc<dyn std::any::Any + Send + Sync>> { | |
| let io = self.io.lock().unwrap(); | |
| (io).as_ref().map(|output| output.clone() as Arc<dyn std::any::Any + Send + Sync>) | |
| } | |
| } | |
| impl<I, T, N> MonitorNode<I, T, N> { | |
| pub fn new(node: N) -> MonitorNode<I, T, N> { | |
| MonitorNode { io: Arc::new(Mutex::new(None)), node } | |
| } | |
| } | |
| use std::hash::{Hash, Hasher}; | |
| pub struct MemoHash<T: Hash> { | |
| hash: u64, | |
| value: T, | |
| } | |
| impl<'de, T: serde::Deserialize<'de> + Hash> serde::Deserialize<'de> for MemoHash<T> { | |
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | |
| where | |
| D: serde::Deserializer<'de>, | |
| { | |
| T::deserialize(deserializer).map(|value| Self::new(value)) | |
| } | |
| } | |
| impl<T: Hash + serde::Serialize> serde::Serialize for MemoHash<T> { | |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
| where | |
| S: serde::Serializer, | |
| { | |
| self.value.serialize(serializer) | |
| } | |
| } | |
| impl<T: Hash> MemoHash<T> { | |
| pub fn new(value: T) -> Self { | |
| let hash = Self::calc_hash(&value); | |
| Self { hash, value } | |
| } | |
| pub fn new_with_hash(value: T, hash: u64) -> Self { | |
| Self { hash, value } | |
| } | |
| fn calc_hash(data: &T) -> u64 { | |
| let mut hasher = DefaultHasher::new(); | |
| data.hash(&mut hasher); | |
| hasher.finish() | |
| } | |
| pub fn inner_mut(&mut self) -> MemoHashGuard<'_, T> { | |
| MemoHashGuard { inner: self } | |
| } | |
| pub fn into_inner(self) -> T { | |
| self.value | |
| } | |
| pub fn hash_code(&self) -> u64 { | |
| self.hash | |
| } | |
| } | |
| impl<T: Hash> From<T> for MemoHash<T> { | |
| fn from(value: T) -> Self { | |
| Self::new(value) | |
| } | |
| } | |
| impl<T: Hash> Hash for MemoHash<T> { | |
| fn hash<H: Hasher>(&self, state: &mut H) { | |
| self.hash.hash(state) | |
| } | |
| } | |
| impl<T: Hash> Deref for MemoHash<T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| &self.value | |
| } | |
| } | |
| pub struct MemoHashGuard<'a, T: Hash> { | |
| inner: &'a mut MemoHash<T>, | |
| } | |
| impl<T: Hash> Drop for MemoHashGuard<'_, T> { | |
| fn drop(&mut self) { | |
| let hash = MemoHash::<T>::calc_hash(&self.inner.value); | |
| self.inner.hash = hash; | |
| } | |
| } | |
| impl<T: Hash> Deref for MemoHashGuard<'_, T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| &self.inner.value | |
| } | |
| } | |
| impl<T: Hash> std::ops::DerefMut for MemoHashGuard<'_, T> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| &mut self.inner.value | |
| } | |
| } | |