sim_kernel/catalog/
table_backend.rs1use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
2
3use crate::{
4 Cx, Error, Expr, Result, Symbol, Value,
5 id::CORE_TABLE_CLASS_ID,
6 object::{ClassRef, Object},
7 table::{Table, TableBackend},
8};
9
10use super::{
11 CatalogRow, CatalogSnapshot, CatalogStore, CatalogTableSpec, CatalogTx, CatalogWritePolicy,
12};
13
14pub struct CatalogTable {
21 store: RwLock<CatalogStore>,
22}
23
24impl CatalogTable {
25 pub fn new() -> Result<Self> {
27 Ok(Self {
28 store: RwLock::new(new_store()?),
29 })
30 }
31
32 pub fn with_entries(entries: Vec<(Symbol, Value)>) -> Result<Self> {
34 let table = Self::new()?;
35 for (key, value) in entries {
36 table.put_value(key, value)?;
37 }
38 Ok(table)
39 }
40
41 pub fn snapshot(&self) -> Result<CatalogSnapshot> {
43 self.read_store()
44 .map(|store| CatalogSnapshot::from_store(&store))
45 }
46
47 fn put_value(&self, key: Symbol, value: Value) -> Result<()> {
48 let mut tx = CatalogTx::new();
49 tx.put_row(row_for_value(key, value));
50 let mut store = self.write_store()?;
51 tx.commit(&mut store).map(|_| ())
52 }
53
54 fn read_store(&self) -> Result<RwLockReadGuard<'_, CatalogStore>> {
55 self.store
56 .read()
57 .map_err(|_| Error::PoisonedLock("catalog table"))
58 }
59
60 fn write_store(&self) -> Result<RwLockWriteGuard<'_, CatalogStore>> {
61 self.store
62 .write()
63 .map_err(|_| Error::PoisonedLock("catalog table"))
64 }
65}
66
67impl Object for CatalogTable {
68 fn display(&self, _cx: &mut Cx) -> Result<String> {
69 let len = self
70 .read_store()?
71 .rows(&entries_table())
72 .map_or(0, |rows| rows.len());
73 Ok(format!("catalog-table[{len}]"))
74 }
75
76 fn as_any(&self) -> &dyn std::any::Any {
77 self
78 }
79}
80
81impl crate::ObjectCompat for CatalogTable {
82 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
83 let symbol = Symbol::qualified("core", "Table");
84 if let Some(value) = cx.registry().class_by_symbol(&symbol) {
85 return Ok(value.clone());
86 }
87 cx.factory().class_stub(CORE_TABLE_CLASS_ID, symbol)
88 }
89
90 fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
91 self.as_table_expr(cx)
92 }
93
94 fn truth(&self, cx: &mut Cx) -> Result<bool> {
95 Ok(!self.is_empty(cx)?)
96 }
97
98 fn as_table_impl(&self) -> Option<&dyn Table> {
99 Some(self)
100 }
101}
102
103impl Table for CatalogTable {
104 fn backend_symbol(&self) -> Symbol {
105 Symbol::qualified("table", "catalog")
106 }
107
108 fn get(&self, cx: &mut Cx, key: Symbol) -> Result<Value> {
109 match self
110 .read_store()?
111 .row(&entries_table(), &key)
112 .map(|row| row_value(cx, row))
113 .transpose()?
114 {
115 Some(value) => Ok(value),
116 None => cx.factory().nil(),
117 }
118 }
119
120 fn set(&self, _cx: &mut Cx, key: Symbol, value: Value) -> Result<()> {
121 self.put_value(key, value)
122 }
123
124 fn has(&self, _cx: &mut Cx, key: Symbol) -> Result<bool> {
125 Ok(self.read_store()?.row(&entries_table(), &key).is_some())
126 }
127
128 fn del(&self, cx: &mut Cx, key: Symbol) -> Result<Value> {
129 let mut store = self.write_store()?;
130 let Some(value) = store
131 .row(&entries_table(), &key)
132 .map(|row| row_value(cx, row))
133 .transpose()?
134 else {
135 return cx.factory().nil();
136 };
137
138 let mut tx = CatalogTx::new();
139 tx.delete_row(entries_table(), key);
140 tx.commit(&mut store)?;
141 Ok(value)
142 }
143
144 fn keys(&self, _cx: &mut Cx) -> Result<Vec<Symbol>> {
145 Ok(self
146 .read_store()?
147 .rows(&entries_table())
148 .map(|rows| rows.keys().cloned().collect())
149 .unwrap_or_default())
150 }
151
152 fn entries(&self, cx: &mut Cx) -> Result<Vec<(Symbol, Value)>> {
153 self.read_store()?
154 .rows(&entries_table())
155 .into_iter()
156 .flat_map(|rows| rows.iter())
157 .map(|(key, row)| row_value(cx, row).map(|value| (key.clone(), value)))
158 .collect()
159 }
160
161 fn len(&self, _cx: &mut Cx) -> Result<usize> {
162 Ok(self
163 .read_store()?
164 .rows(&entries_table())
165 .map_or(0, |rows| rows.len()))
166 }
167
168 fn clear(&self, _cx: &mut Cx) -> Result<()> {
169 let keys = self
170 .read_store()?
171 .rows(&entries_table())
172 .map(|rows| rows.keys().cloned().collect::<Vec<_>>())
173 .unwrap_or_default();
174 if keys.is_empty() {
175 return Ok(());
176 }
177
178 let mut tx = CatalogTx::new();
179 for key in keys {
180 tx.delete_row(entries_table(), key);
181 }
182 let mut store = self.write_store()?;
183 tx.commit(&mut store).map(|_| ())
184 }
185}
186
187pub struct CatalogBackend;
190
191impl TableBackend for CatalogBackend {
192 fn name(&self) -> &str {
193 "table/catalog"
194 }
195
196 fn new_table(&self, cx: &mut Cx, entries: Vec<(Symbol, Value)>) -> Result<Value> {
197 cx.factory()
198 .opaque(Arc::new(CatalogTable::with_entries(entries)?))
199 }
200}
201
202fn new_store() -> Result<CatalogStore> {
203 let mut store = CatalogStore::new();
204 store.install_table(
205 CatalogTableSpec::new(entries_table(), CatalogWritePolicy::Mutable)
206 .with_required_fields(vec![field("key"), field("value")]),
207 )?;
208 Ok(store)
209}
210
211fn row_for_value(key: Symbol, value: Value) -> CatalogRow {
212 let mut row =
213 CatalogRow::new(entries_table(), key.clone()).with_data(field("key"), Expr::Symbol(key));
214 row.insert_live_value(field("value"), value);
215 row
216}
217
218fn row_value(cx: &mut Cx, row: &CatalogRow) -> Result<Value> {
219 if let Some(value) = row.live_value(&field("value")) {
220 Ok(value.clone())
221 } else if let Some(expr) = row.data.get(&field("value")) {
222 cx.factory().expr(expr.clone())
223 } else {
224 cx.factory().nil()
225 }
226}
227
228fn entries_table() -> Symbol {
229 Symbol::qualified("table", "entries")
230}
231
232fn field(name: &'static str) -> Symbol {
233 Symbol::new(name)
234}