Skip to main content

mangle_common/
lib.rs

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! # Mangle FactStore
16//!
17//! Defines core storage interfaces (`Store`, `Host`) and a legacy in-memory storage implementation.
18
19use anyhow::{Result, anyhow};
20use ast::Arena;
21use mangle_ast as ast;
22
23mod tablestore;
24pub use tablestore::{TableConfig, TableStoreImpl, TableStoreSchema};
25
26// --- New Interfaces (Moved from interpreter/vm to break cycles) ---
27
28#[cfg(feature = "edge")]
29#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
30pub enum Value {
31    Number(i64),
32    String(String),
33    Null, // Used for iteration end or missing
34}
35
36#[cfg(feature = "edge")]
37impl std::fmt::Display for Value {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        match self {
40            Value::Number(n) => write!(f, "{n}"),
41            Value::String(s) => write!(f, "{s:?}"),
42            Value::Null => write!(f, "null"),
43        }
44    }
45}
46
47/// Abstract interface for relation storage (Edge Mode).
48#[cfg(feature = "edge")]
49pub trait Store {
50    /// Returns an iterator over all tuples in the relation.
51    /// Returns an error if the relation does not exist.
52    fn scan(&self, relation: &str) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
53
54    /// Returns an iterator over only the new tuples added in the last iteration.
55    fn scan_delta(&self, relation: &str) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
56
57    /// Returns an iterator over tuples being collected for the next iteration.
58    fn scan_next_delta(&self, relation: &str) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
59
60    /// Returns an iterator over tuples in the relation matching a key in a column.
61    fn scan_index(
62        &self,
63        relation: &str,
64        col_idx: usize,
65        key: &Value,
66    ) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
67
68    /// Returns an iterator over delta tuples matching a key in a column.
69    fn scan_delta_index(
70        &self,
71        relation: &str,
72        col_idx: usize,
73        key: &Value,
74    ) -> Result<Box<dyn Iterator<Item = Vec<Value>> + '_>>;
75
76    /// Inserts a tuple into the relation (specifically into the delta/new set).
77    /// Returns true if it was new.
78    fn insert(&mut self, relation: &str, tuple: Vec<Value>) -> Result<bool>;
79
80    /// Merges current deltas into the stable set of facts.
81    fn merge_deltas(&mut self);
82
83    /// Ensures a relation exists in the store.
84    fn create_relation(&mut self, relation: &str);
85
86    /// Removes a specific tuple from the relation's stable set.
87    /// Returns true if the tuple was found and removed.
88    fn retract(&mut self, relation: &str, tuple: &[Value]) -> Result<bool>;
89
90    /// Removes all tuples from a relation (stable, delta, and next_delta).
91    fn clear(&mut self, relation: &str);
92
93    /// Returns the names of all relations in the store.
94    fn relation_names(&self) -> Vec<String>;
95}
96
97/// Trait for the host environment that provides storage and data access (Server Mode).
98#[cfg(feature = "server")]
99pub trait Host {
100    fn scan_start(&mut self, rel_id: i32) -> i32;
101    fn scan_delta_start(&mut self, rel_id: i32) -> i32;
102    fn scan_index_start(&mut self, rel_id: i32, col_idx: i32, val: i64) -> i32;
103    fn scan_aggregate_start(&mut self, rel_id: i32, description: Vec<i32>) -> i32;
104    fn scan_next(&mut self, iter_id: i32) -> i32;
105    fn get_col(&mut self, tuple_ptr: i32, col_idx: i32) -> i64;
106    fn insert(&mut self, rel_id: i32, val: i64);
107    /// Merges deltas and returns 1 if changes occurred, 0 otherwise.
108    fn merge_deltas(&mut self) -> i32;
109    fn debuglog(&mut self, val: i64);
110}
111
112// --- Legacy Interfaces ---
113
114pub trait Receiver<'a> {
115    fn next(&self, item: &'a ast::Atom<'a>) -> Result<()>;
116}
117
118impl<'a, Closure: Fn(&'a ast::Atom<'a>) -> Result<()>> Receiver<'a> for Closure {
119    fn next(&self, item: &'a ast::Atom<'a>) -> Result<()> {
120        (*self)(item)
121    }
122}
123
124/// Lifetime 'a is used for data held by this store.
125pub trait ReadOnlyFactStore<'a> {
126    fn arena(&'a self) -> &'a Arena;
127
128    fn contains<'src>(&'a self, src: &'src Arena, fact: &'src ast::Atom<'src>) -> Result<bool>;
129
130    // Sends atoms that matches query `Atom{ sym: query_sym, args: query_args}`.
131    // pub sym: PredicateIndex,
132    fn get<'query, R: Receiver<'a>>(
133        &'a self,
134        query_sym: ast::PredicateIndex,
135        query_args: &'query [&'query ast::BaseTerm<'query>],
136        cb: &R,
137    ) -> Result<()>;
138
139    // Invokes cb for every predicate available in this store.
140    // It would be nice to use `impl Iterator` here.
141    fn predicates(&'a self) -> Vec<ast::PredicateIndex>;
142
143    // Returns approximae number of facts.
144    fn estimate_fact_count(&self) -> u32;
145}
146
147/// A fact store that can be mutated.
148/// Implementations must make use of interior mutability.
149pub trait FactStore<'a>: ReadOnlyFactStore<'a> {
150    /// Returns true if fact did not exist before.
151    /// The fact is copied.
152    fn add<'src>(&'a self, src: &'src Arena, fact: &'src ast::Atom<'src>) -> Result<bool>;
153
154    /// Adds all facts from given store.
155    fn merge<'src, S>(&'a self, src: &'src Arena, store: &'src S)
156    where
157        S: ReadOnlyFactStore<'src>;
158}
159
160/// Invokes cb for every fact in the store.
161pub fn get_all_facts<'a, S, R: Receiver<'a>>(store: &'a S, cb: &R) -> Result<()>
162where
163    S: ReadOnlyFactStore<'a> + 'a,
164{
165    let arena = Arena::new_with_global_interner();
166    let preds = store.predicates();
167
168    for pred in preds {
169        arena.copy_predicate_sym(store.arena(), pred);
170        store.get(pred, arena.new_query(pred).args, cb)?;
171    }
172    Ok(())
173}