1use anyhow::{Result, anyhow};
20use ast::Arena;
21use mangle_ast as ast;
22
23mod tablestore;
24pub use tablestore::{TableConfig, TableStoreImpl, TableStoreSchema};
25
26#[cfg(feature = "edge")]
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
33pub enum CompoundKind {
34 List,
35 Pair,
36 Map,
37 Struct,
38}
39
40#[cfg(feature = "edge")]
41#[derive(Debug, Clone)]
42pub enum Value {
43 Number(i64),
44 Float(f64),
45 String(String),
46 Name(String),
49 Time(i64),
51 Duration(i64),
53 Compound(CompoundKind, Vec<Value>),
58 Null, }
60
61#[cfg(feature = "edge")]
62impl PartialEq for Value {
63 fn eq(&self, other: &Self) -> bool {
64 match (self, other) {
65 (Value::Number(a), Value::Number(b)) => a == b,
66 (Value::Float(a), Value::Float(b)) => a.to_bits() == b.to_bits(),
67 (Value::String(a), Value::String(b)) => a == b,
68 (Value::Name(a), Value::Name(b)) => a == b,
69 (Value::Time(a), Value::Time(b)) => a == b,
70 (Value::Duration(a), Value::Duration(b)) => a == b,
71 (Value::Compound(ka, a), Value::Compound(kb, b)) => ka == kb && a == b,
72 (Value::Null, Value::Null) => true,
73 _ => false,
74 }
75 }
76}
77
78#[cfg(feature = "edge")]
79impl Eq for Value {}
80
81#[cfg(feature = "edge")]
82impl std::hash::Hash for Value {
83 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
84 std::mem::discriminant(self).hash(state);
85 match self {
86 Value::Number(n) => n.hash(state),
87 Value::Float(f) => f.to_bits().hash(state),
88 Value::String(s) => s.hash(state),
89 Value::Name(s) => s.hash(state),
90 Value::Time(t) => t.hash(state),
91 Value::Duration(d) => d.hash(state),
92 Value::Compound(k, v) => {
93 k.hash(state);
94 v.hash(state);
95 }
96 Value::Null => {}
97 }
98 }
99}
100
101#[cfg(feature = "edge")]
102impl PartialOrd for Value {
103 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
104 Some(self.cmp(other))
105 }
106}
107
108#[cfg(feature = "edge")]
109impl Ord for Value {
110 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
111 match (self, other) {
112 (Value::Number(a), Value::Number(b)) => a.cmp(b),
113 (Value::Float(a), Value::Float(b)) => a.total_cmp(b),
114 (Value::Number(a), Value::Float(b)) => (*a as f64).total_cmp(b),
116 (Value::Float(a), Value::Number(b)) => a.total_cmp(&(*b as f64)),
117 (Value::String(a), Value::String(b)) => a.cmp(b),
118 (Value::Name(a), Value::Name(b)) => a.cmp(b),
119 (Value::Time(a), Value::Time(b)) => a.cmp(b),
120 (Value::Duration(a), Value::Duration(b)) => a.cmp(b),
121 (Value::Duration(a), Value::Number(b)) => a.cmp(b),
123 (Value::Number(a), Value::Duration(b)) => a.cmp(b),
124 (Value::Time(a), Value::Number(b)) => a.cmp(b),
126 (Value::Number(a), Value::Time(b)) => a.cmp(b),
127 (Value::Compound(ka, a), Value::Compound(kb, b)) => ka.cmp(kb).then_with(|| a.cmp(b)),
128 (Value::Null, Value::Null) => std::cmp::Ordering::Equal,
129 (Value::Number(_) | Value::Float(_), _) => std::cmp::Ordering::Less,
131 (_, Value::Number(_) | Value::Float(_)) => std::cmp::Ordering::Greater,
132 (Value::String(_), _) => std::cmp::Ordering::Less,
133 (_, Value::String(_)) => std::cmp::Ordering::Greater,
134 (Value::Name(_), _) => std::cmp::Ordering::Less,
135 (_, Value::Name(_)) => std::cmp::Ordering::Greater,
136 (Value::Time(_), _) => std::cmp::Ordering::Less,
137 (_, Value::Time(_)) => std::cmp::Ordering::Greater,
138 (Value::Duration(_), _) => std::cmp::Ordering::Less,
139 (_, Value::Duration(_)) => std::cmp::Ordering::Greater,
140 (Value::Compound(..), _) => std::cmp::Ordering::Less,
141 (_, Value::Compound(..)) => std::cmp::Ordering::Greater,
142 }
143 }
144}
145
146#[cfg(feature = "edge")]
147impl std::fmt::Display for Value {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 match self {
150 Value::Number(n) => write!(f, "{n}"),
151 Value::Float(v) => write!(f, "{v}"),
152 Value::String(s) => write!(f, "{s:?}"),
153 Value::Name(s) => write!(f, "{s}"),
154 Value::Time(nanos) => write!(f, "{}", format_time_nanos(*nanos)),
155 Value::Duration(nanos) => write!(f, "{}", format_duration_nanos(*nanos)),
156 Value::Compound(kind, elems) => match kind {
157 CompoundKind::List | CompoundKind::Pair => {
158 write!(f, "[")?;
159 for (i, e) in elems.iter().enumerate() {
160 if i > 0 {
161 write!(f, ", ")?;
162 }
163 write!(f, "{e}")?;
164 }
165 write!(f, "]")
166 }
167 CompoundKind::Map => {
168 write!(f, "[")?;
169 for (i, pair) in elems.chunks_exact(2).enumerate() {
170 if i > 0 {
171 write!(f, ", ")?;
172 }
173 write!(f, "{}: {}", pair[0], pair[1])?;
174 }
175 write!(f, "]")
176 }
177 CompoundKind::Struct => {
178 write!(f, "{{")?;
179 for (i, pair) in elems.chunks_exact(2).enumerate() {
180 if i > 0 {
181 write!(f, ", ")?;
182 }
183 write!(f, "{}: {}", pair[0], pair[1])?;
184 }
185 write!(f, "}}")
186 }
187 },
188 Value::Null => write!(f, "null"),
189 }
190 }
191}
192
193#[cfg(feature = "edge")]
194fn format_time_nanos(nanos: i64) -> String {
195 let secs = nanos.div_euclid(1_000_000_000);
196 let ns = nanos.rem_euclid(1_000_000_000) as u32;
197
198 let days = secs.div_euclid(86400);
201 let time_of_day = secs.rem_euclid(86400);
202 let hour = time_of_day / 3600;
203 let minute = (time_of_day % 3600) / 60;
204 let second = time_of_day % 60;
205
206 let z = days + 719468;
208 let era = (if z >= 0 { z } else { z - 146096 }) / 146097;
209 let doe = (z - era * 146097) as u32;
210 let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
211 let y = yoe as i64 + era * 400;
212 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
213 let mp = (5 * doy + 2) / 153;
214 let d = doy - (153 * mp + 2) / 5 + 1;
215 let m = if mp < 10 { mp + 3 } else { mp - 9 };
216 let y = if m <= 2 { y + 1 } else { y };
217
218 if ns == 0 {
219 format!("{y:04}-{m:02}-{d:02}T{hour:02}:{minute:02}:{second:02}Z")
220 } else {
221 let mut frac = format!("{ns:09}");
223 frac = frac.trim_end_matches('0').to_string();
224 format!("{y:04}-{m:02}-{d:02}T{hour:02}:{minute:02}:{second:02}.{frac}Z")
225 }
226}
227
228#[cfg(feature = "edge")]
231fn format_duration_nanos(nanos: i64) -> String {
232 if nanos == 0 {
233 return "0s".to_string();
234 }
235
236 let mut result = String::new();
237 let mut remaining = if nanos < 0 {
238 result.push('-');
239 nanos.unsigned_abs()
240 } else {
241 nanos as u64
242 };
243
244 const NANOS_PER_US: u64 = 1_000;
245 const NANOS_PER_MS: u64 = 1_000_000;
246 const NANOS_PER_S: u64 = 1_000_000_000;
247 const NANOS_PER_M: u64 = 60 * NANOS_PER_S;
248 const NANOS_PER_H: u64 = 60 * NANOS_PER_M;
249
250 if remaining >= NANOS_PER_S {
252 let hours = remaining / NANOS_PER_H;
253 remaining %= NANOS_PER_H;
254 let minutes = remaining / NANOS_PER_M;
255 remaining %= NANOS_PER_M;
256 let seconds = remaining / NANOS_PER_S;
257 let sub_second_nanos = remaining % NANOS_PER_S;
258
259 if hours > 0 {
260 result.push_str(&format!("{hours}h"));
261 }
262 if minutes > 0 || hours > 0 {
263 result.push_str(&format!("{minutes}m"));
264 }
265 if sub_second_nanos == 0 {
266 result.push_str(&format!("{seconds}s"));
267 } else {
268 let frac = format!("{sub_second_nanos:09}");
270 let frac = frac.trim_end_matches('0');
271 result.push_str(&format!("{seconds}.{frac}s"));
272 }
273 } else if remaining >= NANOS_PER_MS {
274 let ms = remaining / NANOS_PER_MS;
276 let sub = remaining % NANOS_PER_MS;
277 if sub == 0 {
278 result.push_str(&format!("{ms}ms"));
279 } else {
280 let frac = format!("{sub:06}");
281 let frac = frac.trim_end_matches('0');
282 result.push_str(&format!("{ms}.{frac}ms"));
283 }
284 } else if remaining >= NANOS_PER_US {
285 let us = remaining / NANOS_PER_US;
287 let sub = remaining % NANOS_PER_US;
288 if sub == 0 {
289 result.push_str(&format!("{us}µs"));
290 } else {
291 let frac = format!("{sub:03}");
292 let frac = frac.trim_end_matches('0');
293 result.push_str(&format!("{us}.{frac}µs"));
294 }
295 } else {
296 result.push_str(&format!("{}ns", remaining));
298 }
299
300 result
301}
302
303#[cfg(feature = "edge")]
315pub trait Store {
316 fn scan(&self, relation: &str) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
319
320 fn scan_delta(&self, relation: &str) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
322
323 fn scan_next_delta(&self, relation: &str) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
325
326 fn scan_index(
328 &self,
329 relation: &str,
330 col_idx: usize,
331 key: &Value,
332 ) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
333
334 fn scan_delta_index(
336 &self,
337 relation: &str,
338 col_idx: usize,
339 key: &Value,
340 ) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
341
342 fn insert(&mut self, relation: &str, tuple: Vec<Value>) -> Result<bool>;
345
346 fn merge_deltas(&mut self);
348
349 fn create_relation(&mut self, relation: &str);
351
352 fn retract(&mut self, relation: &str, tuple: &[Value]) -> Result<bool>;
355
356 fn clear(&mut self, relation: &str);
358
359 fn relation_names(&self) -> Vec<String>;
361
362 fn coalesce_temporal(&mut self, _relation: &str) {}
367}
368
369#[cfg(feature = "server")]
372#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
373pub struct HostVal(pub u32);
374
375#[cfg(feature = "server")]
381pub trait Host {
382 fn scan_start(&mut self, rel_id: i32) -> i32;
384 fn scan_delta_start(&mut self, rel_id: i32) -> i32;
385 fn scan_next(&mut self, iter_id: i32) -> i32;
386 fn merge_deltas(&mut self) -> i32;
388 fn scan_aggregate_start(&mut self, rel_id: i32, description: Vec<i32>) -> i32;
389 fn scan_index_start(&mut self, rel_id: i32, col_idx: i32, val: HostVal) -> i32;
390
391 fn get_col(&mut self, tuple_ptr: i32, col_idx: i32) -> HostVal;
393
394 fn insert_begin(&mut self, rel_id: i32);
396 fn insert_push(&mut self, val: HostVal);
397 fn insert_end(&mut self);
398
399 fn const_number(&mut self, n: i64) -> HostVal;
401 fn const_float(&mut self, bits: i64) -> HostVal;
402 fn const_string(&mut self, id: i32) -> HostVal;
403 fn const_name(&mut self, id: i32) -> HostVal;
404 fn const_time(&mut self, nanos: i64) -> HostVal;
405 fn const_duration(&mut self, nanos: i64) -> HostVal;
406
407 fn val_add(&mut self, a: HostVal, b: HostVal) -> HostVal;
409 fn val_sub(&mut self, a: HostVal, b: HostVal) -> HostVal;
410 fn val_mul(&mut self, a: HostVal, b: HostVal) -> HostVal;
411 fn val_div(&mut self, a: HostVal, b: HostVal) -> HostVal;
412 fn val_sqrt(&mut self, a: HostVal) -> HostVal;
413
414 fn val_eq(&mut self, a: HostVal, b: HostVal) -> i32;
416 fn val_neq(&mut self, a: HostVal, b: HostVal) -> i32;
417 fn val_lt(&mut self, a: HostVal, b: HostVal) -> i32;
418 fn val_le(&mut self, a: HostVal, b: HostVal) -> i32;
419 fn val_gt(&mut self, a: HostVal, b: HostVal) -> i32;
420 fn val_ge(&mut self, a: HostVal, b: HostVal) -> i32;
421
422 fn str_concat(&mut self, a: HostVal, b: HostVal) -> HostVal;
424 fn str_replace(&mut self, s: HostVal, old: HostVal, new: HostVal, count: HostVal) -> HostVal;
425 fn val_to_string(&mut self, val: HostVal) -> HostVal;
426
427 fn compound_begin(&mut self, kind: i32);
430 fn compound_push(&mut self, val: HostVal);
431 fn compound_end(&mut self) -> HostVal;
432 fn compound_get(&mut self, compound: HostVal, key: HostVal) -> HostVal;
434 fn compound_len(&mut self, compound: HostVal) -> HostVal;
436 fn pair_first(&mut self, compound: HostVal) -> HostVal;
437 fn pair_second(&mut self, compound: HostVal) -> HostVal;
438
439 fn debuglog(&mut self, val: HostVal);
441
442 fn hash_join_begin(&mut self, _join_id: i32) {
457 unimplemented!("hash_join_begin");
458 }
459 fn hash_join_push(&mut self, _val: HostVal) {
460 unimplemented!("hash_join_push");
461 }
462 fn hash_join_commit_build(&mut self, _join_id: i32, _n_keys: i32) {
463 unimplemented!("hash_join_commit_build");
464 }
465 fn hash_join_probe(&mut self, _join_id: i32) -> i32 {
466 unimplemented!("hash_join_probe");
467 }
468 fn hash_join_end(&mut self, _join_id: i32) {
469 unimplemented!("hash_join_end");
470 }
471}
472
473pub trait Receiver<'a> {
476 fn next(&self, item: &'a ast::Atom<'a>) -> Result<()>;
477}
478
479impl<'a, Closure: Fn(&'a ast::Atom<'a>) -> Result<()>> Receiver<'a> for Closure {
480 fn next(&self, item: &'a ast::Atom<'a>) -> Result<()> {
481 (*self)(item)
482 }
483}
484
485pub trait ReadOnlyFactStore<'a> {
487 fn arena(&'a self) -> &'a Arena;
488
489 fn contains<'src>(&'a self, src: &'src Arena, fact: &'src ast::Atom<'src>) -> Result<bool>;
490
491 fn get<'query, R: Receiver<'a>>(
494 &'a self,
495 query_sym: ast::PredicateIndex,
496 query_args: &'query [&'query ast::BaseTerm<'query>],
497 cb: &R,
498 ) -> Result<()>;
499
500 fn predicates(&'a self) -> Vec<ast::PredicateIndex>;
503
504 fn estimate_fact_count(&self) -> u32;
506}
507
508pub trait FactStore<'a>: ReadOnlyFactStore<'a> {
511 fn add<'src>(&'a self, src: &'src Arena, fact: &'src ast::Atom<'src>) -> Result<bool>;
514
515 fn merge<'src, S>(&'a self, src: &'src Arena, store: &'src S)
517 where
518 S: ReadOnlyFactStore<'src>;
519}
520
521pub fn get_all_facts<'a, S, R: Receiver<'a>>(store: &'a S, cb: &R) -> Result<()>
523where
524 S: ReadOnlyFactStore<'a> + 'a,
525{
526 let arena = Arena::new_with_global_interner();
527 let preds = store.predicates();
528
529 for pred in preds {
530 arena.copy_predicate_sym(store.arena(), pred);
531 store.get(pred, arena.new_query(pred).args, cb)?;
532 }
533 Ok(())
534}