arora_simple_data_store/
lib.rs1mod namespaced;
11pub use namespaced::NamespacedStore;
12
13use std::collections::HashMap;
14use std::sync::mpsc::{channel, Sender};
15use std::sync::{Arc, Mutex, RwLock};
16
17use arora_types::data::{DataError, DataStore, Key, Slot, State, StateChange, Subscription};
18use arora_types::value::Value;
19
20type Cell = Arc<RwLock<Option<Value>>>;
22
23#[derive(Default)]
24struct Inner {
25 cells: RwLock<HashMap<Key, Cell>>,
26 subscribers: Mutex<Vec<Sender<StateChange>>>,
27}
28
29impl Inner {
30 fn notify(&self, change: StateChange) {
33 if change.is_empty() {
34 return;
35 }
36 let mut subs = self.subscribers.lock().unwrap();
37 subs.retain(|tx| tx.send(change.clone()).is_ok());
38 }
39}
40
41#[derive(Clone, Default)]
43pub struct SimpleDataStore {
44 inner: Arc<Inner>,
45}
46
47impl SimpleDataStore {
48 pub fn new() -> Self {
49 Self::default()
50 }
51
52 fn cell(&self, key: &Key) -> Cell {
54 if let Some(cell) = self.inner.cells.read().unwrap().get(key) {
55 return cell.clone();
56 }
57 self.inner
58 .cells
59 .write()
60 .unwrap()
61 .entry(key.clone())
62 .or_insert_with(|| Arc::new(RwLock::new(None)))
63 .clone()
64 }
65}
66
67impl DataStore for SimpleDataStore {
68 fn read(&self, keys: &[Key]) -> Vec<Option<Value>> {
69 let cells = self.inner.cells.read().unwrap();
70 keys.iter()
71 .map(|k| cells.get(k).and_then(|c| c.read().unwrap().clone()))
72 .collect()
73 }
74
75 fn write(&self, changes: StateChange) -> Result<(), DataError> {
76 let mut effective = StateChange::new();
83 for (key, value) in &changes.set {
84 let cell = self.cell(key);
85 let mut current = cell.write().unwrap();
86 if current.as_ref() != value.as_ref() {
87 *current = value.clone();
88 effective.set.insert(key.clone(), value.clone());
89 }
90 }
91 for key in &changes.unset {
92 let cell = self.cell(key);
94 let mut current = cell.write().unwrap();
95 if current.is_some() {
96 *current = None;
97 effective.unset.insert(key.clone());
98 }
99 }
100 if !effective.is_empty() {
101 self.inner.notify(effective);
102 }
103 Ok(())
104 }
105
106 fn snapshot(&self) -> State {
107 let cells = self.inner.cells.read().unwrap();
108 let storage = cells
109 .iter()
110 .map(|(k, c)| (k.clone(), c.read().unwrap().clone()))
111 .collect();
112 State { storage }
113 }
114
115 fn slot(&self, key: &Key) -> Box<dyn Slot> {
116 Box::new(SimpleSlot {
117 cell: self.cell(key),
118 key: key.clone(),
119 inner: self.inner.clone(),
120 })
121 }
122
123 fn clone_box(&self) -> Box<dyn DataStore> {
124 Box::new(self.clone())
125 }
126
127 fn subscribe(&self) -> Subscription {
128 let (tx, rx) = channel();
129 let mut subscribers = self.inner.subscribers.lock().unwrap();
135 let mut initial = StateChange::new();
136 for (key, value) in self.snapshot().storage {
137 initial.set.insert(key, value);
138 }
139 let _ = tx.send(initial);
140 subscribers.push(tx);
141 Subscription::new(rx)
142 }
143}
144
145struct SimpleSlot {
148 cell: Cell,
149 key: Key,
150 inner: Arc<Inner>,
151}
152
153impl Slot for SimpleSlot {
154 fn get(&self) -> Option<Value> {
155 self.cell.read().unwrap().clone()
156 }
157
158 fn set(&self, value: Option<Value>) -> Result<(), DataError> {
159 {
162 let mut current = self.cell.write().unwrap();
163 if *current == value {
164 return Ok(());
165 }
166 *current = value.clone();
167 }
168 self.inner.notify(StateChange {
169 set: HashMap::from([(self.key.clone(), value)]),
170 unset: Default::default(),
171 });
172 Ok(())
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn write_then_read() {
182 let store = SimpleDataStore::new();
183 store
184 .write(StateChange::set("a/b", Value::Boolean(true)))
185 .unwrap();
186 assert_eq!(
187 store.read(&[Key::from("a/b")]),
188 vec![Some(Value::Boolean(true))]
189 );
190 assert_eq!(store.read(&[Key::from("missing")]), vec![None]);
191 }
192
193 #[test]
194 fn slot_and_store_coincide() {
195 let store = SimpleDataStore::new();
196 let slot = store.slot(&Key::from("x"));
197 slot.set(Some(Value::Boolean(true))).unwrap();
199 assert_eq!(
200 store.read(&[Key::from("x")]),
201 vec![Some(Value::Boolean(true))]
202 );
203 store
205 .write(StateChange::set("x", Value::Boolean(false)))
206 .unwrap();
207 assert_eq!(slot.get(), Some(Value::Boolean(false)));
208 }
209
210 #[test]
211 fn subscribe_delivers_changes_to_all() {
212 let store = SimpleDataStore::new();
213 let s1 = store.subscribe();
214 let s2 = store.subscribe();
215 s1.try_recv().expect("s1 opening state");
216 s2.try_recv().expect("s2 opening state");
217 store
218 .write(StateChange::set("k", Value::Boolean(true)))
219 .unwrap();
220 assert!(s1.try_recv().expect("s1 change").contains(&Key::from("k")));
221 assert!(s2.try_recv().expect("s2 change").contains(&Key::from("k")));
222 }
223
224 #[test]
228 fn subscribe_opens_on_the_current_state() {
229 let store = SimpleDataStore::new();
230 store
231 .write(StateChange::set("already", Value::Boolean(true)))
232 .unwrap();
233
234 let sub = store.subscribe();
235 let opening = sub.try_recv().expect("opening state");
236 assert!(opening.contains(&Key::from("already")));
237
238 store
239 .write(StateChange::set("later", Value::Boolean(false)))
240 .unwrap();
241 assert!(sub
242 .try_recv()
243 .expect("change")
244 .contains(&Key::from("later")));
245 }
246
247 #[test]
248 fn slot_set_notifies_subscribers() {
249 let store = SimpleDataStore::new();
250 let sub = store.subscribe();
251 sub.try_recv().expect("opening state");
252 store
253 .slot(&Key::from("y"))
254 .set(Some(Value::Boolean(true)))
255 .unwrap();
256 assert!(sub.try_recv().expect("change").contains(&Key::from("y")));
257 }
258
259 #[test]
260 fn snapshot_returns_all() {
261 let store = SimpleDataStore::new();
262 store
263 .write(StateChange::set("a", Value::Boolean(true)))
264 .unwrap();
265 store
266 .write(StateChange::set("b", Value::Boolean(false)))
267 .unwrap();
268 assert_eq!(store.snapshot().storage.len(), 2);
269 }
270
271 #[test]
272 fn clones_share_storage() {
273 let store = SimpleDataStore::new();
274 let other = store.clone();
275 store
276 .write(StateChange::set("shared", Value::Boolean(true)))
277 .unwrap();
278 assert_eq!(
279 other.read(&[Key::from("shared")]),
280 vec![Some(Value::Boolean(true))]
281 );
282 }
283}