use core_types::WasmNotSend; use core_types::graphene_hash::CacheHash; use core_types::memo::*; use std::hash::DefaultHasher; use std::hash::Hasher; use std::sync::Arc; use std::sync::Mutex; /// Helps speed up repeated renders in a computationally-heavy part of the node graph. /// /// Stores the last evaluated data that flowed through this node and immediately returns that data on subsequent renders if the context has not changed. #[node_macro::node(category("General"), path(graphene_core::memo), skip_impl)] async fn memoize(input: I, #[data] cache: Arc>>, content: impl Node) -> T { // Caches the output of a given node called with a specific input. // // A cache miss occurs when the Option is None. In this case, the node evaluates the inner node and memoizes (stores) the result. // // A cache hit occurs when the Option is Some and has a stored hash matching the hash of the call argument. In this case, the node returns the cached value without re-evaluating the inner node. // // Currently, only one input-output pair is cached. Subsequent calls with different inputs will overwrite the previous cache. let mut hasher = DefaultHasher::new(); input.cache_hash(&mut hasher); let hash = hasher.finish(); if let Some(data) = cache.lock().as_ref().unwrap().as_ref().and_then(|data| (data.0 == hash).then_some(data.1.clone())) { return data; } let value = content.eval(input).await; *cache.lock().unwrap() = Some((hash, value.clone())); value } type MonitorValue = Arc>>>>; /// The Monitor node is used by the editor to access the data flowing through it. #[node_macro::node(category(""), path(graphene_core::memo), serialize(serialize_monitor), properties("monitor_properties"), skip_impl)] async fn monitor( input: I, #[allow(clippy::type_complexity)] #[data] io: MonitorValue, content: impl Node, ) -> T { let output = content.eval(input.clone()).await; *io.lock().unwrap() = Some(Arc::new(IORecord { input, output: output.clone() })); output } fn serialize_monitor(io: &MonitorValue) -> Option> { let io = io.lock().unwrap(); io.as_ref().map(|output| output.clone() as Arc) }