daedalus_runtime/
state.rs

1use std::collections::{BTreeMap, HashMap};
2use std::sync::{Arc, RwLock};
3
4/// Shared runtime state store keyed by node id.
5#[derive(Default, Clone)]
6pub struct StateStore {
7    inner: Arc<RwLock<HashMap<String, serde_json::Value>>>,
8}
9
10impl StateStore {
11    pub fn get(&self, key: &str) -> Option<serde_json::Value> {
12        self.inner.read().ok().and_then(|m| m.get(key).cloned())
13    }
14
15    /// Fallible getter for raw values.
16    pub fn get_result(&self, key: &str) -> Result<Option<serde_json::Value>, String> {
17        let guard = self
18            .inner
19            .read()
20            .map_err(|_| "state lock poisoned".to_string())?;
21        Ok(guard.get(key).cloned())
22    }
23
24    /// Fallible getter with error context.
25    pub fn get_checked<T: serde::de::DeserializeOwned>(
26        &self,
27        key: &str,
28    ) -> Result<Option<T>, String> {
29        let guard = self
30            .inner
31            .read()
32            .map_err(|_| "state lock poisoned".to_string())?;
33        if let Some(val) = guard.get(key) {
34            serde_json::from_value(val.clone())
35                .map(Some)
36                .map_err(|e| format!("serde error: {e}"))
37        } else {
38            Ok(None)
39        }
40    }
41
42    pub fn get_typed<T: serde::de::DeserializeOwned>(&self, key: &str) -> Option<T> {
43        self.get(key).and_then(|v| serde_json::from_value(v).ok())
44    }
45
46    pub fn set(&self, key: &str, value: serde_json::Value) -> Result<(), String> {
47        let mut m = self
48            .inner
49            .write()
50            .map_err(|_| "state lock poisoned".to_string())?;
51        m.insert(key.to_string(), value);
52        Ok(())
53    }
54
55    pub fn set_typed<T: serde::Serialize>(&self, key: &str, value: &T) -> Result<(), String> {
56        let json = serde_json::to_value(value).map_err(|e| format!("serde error: {e}"))?;
57        self.set(key, json)
58    }
59
60    pub fn dump_json(&self) -> Result<String, String> {
61        let m = self
62            .inner
63            .read()
64            .map_err(|_| "state lock poisoned".to_string())?;
65        serde_json::to_string(&*m).map_err(|e| format!("serde error: {e}"))
66    }
67
68    pub fn load_json(&self, json: &str) -> Result<(), String> {
69        let map = serde_json::from_str::<HashMap<String, serde_json::Value>>(json)
70            .map_err(|e| format!("serde error: {e}"))?;
71        let mut guard = self
72            .inner
73            .write()
74            .map_err(|_| "state lock poisoned".to_string())?;
75        *guard = map;
76        Ok(())
77    }
78}
79
80/// Execution context passed to nodes.
81pub struct ExecutionContext {
82    pub state: StateStore,
83    pub metadata: BTreeMap<String, daedalus_data::model::Value>,
84    /// Graph-level metadata (typed values) shared by all nodes in the graph.
85    pub graph_metadata: Arc<BTreeMap<String, daedalus_data::model::Value>>,
86    #[cfg(feature = "gpu")]
87    pub gpu: Option<GpuContextHandle>,
88}
89
90#[cfg(feature = "gpu")]
91pub type GpuContextHandle = daedalus_gpu::GpuContextHandle;