1use std::io;
4use std::path::Path;
5
6use yog_data::Schema;
7use yog_sync::{Arc, Mutex};
8
9use crate::Scope;
10use crate::shelf::{self, Shelf};
11
12#[derive(Clone)]
15pub struct Store {
16 shelf: Arc<Mutex<Shelf>>,
17}
18
19impl Store {
20 pub fn open(root: &Path, mod_id: &str, scope: Scope<'_>) -> Self {
22 Store {
23 shelf: shelf::file(scope.path(root, mod_id)),
24 }
25 }
26
27 pub fn session(mod_id: &str) -> Self {
29 Store {
30 shelf: shelf::session(mod_id),
31 }
32 }
33
34 pub fn get<T: Schema>(&self, key: &str) -> Option<T> {
36 yog_data::read_value(self.shelf.lock().values.get(key)?).ok()
37 }
38
39 pub fn get_or_default<T: Schema + Default>(&self, key: &str) -> T {
41 self.get(key).unwrap_or_default()
42 }
43
44 pub fn set<T: Schema>(&self, key: &str, value: &T) {
46 let mut shelf = self.shelf.lock();
47 shelf.values.insert(key, value.write());
48 shelf.dirty = true;
49 }
50
51 pub fn record(&self, key: &str) -> Option<Vec<u8>> {
54 match self.shelf.lock().values.get(key)? {
55 yog_data::Value::Bytes(bytes) => Some(bytes.clone()),
56 _ => None,
57 }
58 }
59
60 pub fn set_record(&self, key: &str, bytes: &[u8]) {
63 let mut shelf = self.shelf.lock();
64 shelf.dirty = true;
65 if let Some(yog_data::Value::Bytes(old)) = shelf.values.get_mut(key) {
68 old.clear();
69 old.extend_from_slice(bytes);
70 return;
71 }
72 shelf
73 .values
74 .insert(key, yog_data::Value::Bytes(bytes.to_vec()));
75 }
76
77 pub fn remove_under(&self, prefix: &str) -> usize {
79 let mut shelf = self.shelf.lock();
80 let before = shelf.values.len();
81 shelf.values.retain(|k, _| !k.starts_with(prefix));
83 let removed = before - shelf.values.len();
84 shelf.dirty |= removed > 0;
85 removed
86 }
87
88 pub fn update<T: Schema + Default, R>(&self, key: &str, change: impl FnOnce(&mut T) -> R) -> R {
90 let mut value = self.get_or_default(key);
91 let out = change(&mut value);
92 self.set(key, &value);
93 out
94 }
95
96 pub fn remove(&self, key: &str) -> bool {
98 let mut shelf = self.shelf.lock();
99 let removed = shelf.values.remove(key).is_some();
100 shelf.dirty |= removed;
101 removed
102 }
103
104 pub fn contains(&self, key: &str) -> bool {
105 self.shelf.lock().values.get(key).is_some()
106 }
107
108 pub fn keys(&self) -> Vec<String> {
110 self.shelf.lock().values.keys().map(str::to_owned).collect()
111 }
112
113 pub fn flush(&self) -> io::Result<()> {
115 self.shelf.lock().flush()
116 }
117}