tirea_state/lattice/
registry.rs1use crate::{Lattice, Path, TireaError, TireaResult};
7use serde::de::DeserializeOwned;
8use serde::Serialize;
9use serde_json::Value;
10use std::collections::HashMap;
11use std::marker::PhantomData;
12use std::sync::Arc;
13
14pub trait LatticeMerger: Send + Sync {
16 fn merge(&self, current: Option<&Value>, delta: &Value) -> TireaResult<Value>;
21}
22
23struct LatticeAdapter<T>(PhantomData<T>);
25
26impl<T> LatticeMerger for LatticeAdapter<T>
27where
28 T: Lattice + Serialize + DeserializeOwned + Send + Sync,
29{
30 fn merge(&self, current: Option<&Value>, delta: &Value) -> TireaResult<Value> {
31 let d: T = serde_json::from_value(delta.clone()).map_err(TireaError::from)?;
32 let merged = match current {
33 None => d,
34 Some(v) => {
35 let c: T = serde_json::from_value(v.clone()).map_err(TireaError::from)?;
36 Lattice::merge(&c, &d)
37 }
38 };
39 serde_json::to_value(&merged).map_err(TireaError::from)
40 }
41}
42
43pub struct LatticeRegistry {
45 entries: HashMap<Path, Arc<dyn LatticeMerger>>,
46}
47
48impl LatticeRegistry {
49 pub fn new() -> Self {
51 Self {
52 entries: HashMap::new(),
53 }
54 }
55
56 pub fn register<T>(&mut self, path: impl Into<Path>)
58 where
59 T: Lattice + Serialize + DeserializeOwned + Send + Sync + 'static,
60 {
61 self.entries
62 .insert(path.into(), Arc::new(LatticeAdapter::<T>(PhantomData)));
63 }
64
65 pub fn get(&self, path: &Path) -> Option<&dyn LatticeMerger> {
67 self.entries.get(path).map(|arc| arc.as_ref())
68 }
69}
70
71impl Default for LatticeRegistry {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::{path, GCounter};
81
82 #[test]
83 fn test_register_and_merge() {
84 let mut registry = LatticeRegistry::new();
85 registry.register::<GCounter>(path!("counter"));
86
87 let merger = registry.get(&path!("counter")).unwrap();
88
89 let delta = serde_json::to_value(GCounter::new()).unwrap();
91 let result = merger.merge(None, &delta).unwrap();
92 assert_eq!(result, delta);
93 }
94
95 #[test]
96 fn test_merge_two_counters() {
97 let mut registry = LatticeRegistry::new();
98 registry.register::<GCounter>(path!("counter"));
99
100 let mut c1 = GCounter::new();
101 c1.increment("n1", 5);
102 let mut c2 = GCounter::new();
103 c2.increment("n2", 3);
104
105 let v1 = serde_json::to_value(&c1).unwrap();
106 let v2 = serde_json::to_value(&c2).unwrap();
107
108 let merger = registry.get(&path!("counter")).unwrap();
109 let merged = merger.merge(Some(&v1), &v2).unwrap();
110
111 let result: GCounter = serde_json::from_value(merged).unwrap();
112 assert_eq!(result.value(), 8);
113 }
114
115 #[test]
116 fn test_unregistered_path_returns_none() {
117 let registry = LatticeRegistry::new();
118 assert!(registry.get(&path!("missing")).is_none());
119 }
120}