pub trait Storage {
// Required methods
fn set(&self, key: &str, value: StorageValue);
fn get(&self, key: &str) -> Option<StorageValue>;
fn del(&self, key: &str);
fn scan<'s>(
&'s self,
prefix: &str,
) -> Box<dyn Iterator<Item = (Box<str>, StorageValue)> + 's>;
// Provided method
fn clear(&self) { ... }
}Expand description
Per-operator scratch state: a sorted string-keyed map with a prefix range
scan. Ports zql/src/ivm/operator.ts:132 Storage.
Object-safe by design. The builder (08) stores the chosen backend
behind Box<dyn Storage> so the same operator code (Take, Cap) links
against either backend with no per-backend monomorphization. Operators are
already dyn-dispatched at the graph boundary (foundations §6.2), so the extra
vtable here is free. The boxed, lending-free scan return keeps it object-safe.
&self, not &mut self (foundations §6: no &mut on operator-held state
during a shared-borrowed reentrant push). Backends use interior mutability.
Storage ops are synchronous and non-reentrant — they never call back into the
graph — so none of the “no borrow across a vend” hazards apply within the
store (spec 10 §5, E12).
The trait is intentionally infallible (spec 10 §4.1, E14). A backend that
can fail (the SQLite OpStorage) reports errors out of band — it parks a
RindleError on the graph’s runtime-error sink and returns a safe sentinel
(None / empty / no-op); the graph drains it via take_runtime_error at the
mutation boundary (WS02.3). The in-RAM MemoryStorage never fails.
Required Methods§
Sourcefn set(&self, key: &str, value: StorageValue)
fn set(&self, key: &str, value: StorageValue)
Insert or overwrite key’s value (spec 10 §3.1, E3).
Sourcefn get(&self, key: &str) -> Option<StorageValue>
fn get(&self, key: &str) -> Option<StorageValue>
Owned lookup. None if absent (E1). The JS get(key, def) default is a
caller concern — use get(k).unwrap_or(default) (spec 10 §6 deviation
D1); we do not bake it into the signature. The returned value is owned
(never a borrow into the store), so the operator may hold/mutate it past a
later set regardless of backend (spec 10 §3.2 inv.3, E11).
Sourcefn scan<'s>(
&'s self,
prefix: &str,
) -> Box<dyn Iterator<Item = (Box<str>, StorageValue)> + 's>
fn scan<'s>( &'s self, prefix: &str, ) -> Box<dyn Iterator<Item = (Box<str>, StorageValue)> + 's>
Ascending prefix scan. Yields owned (key, value) pairs in byte-ascending
key order, starting at the first key >= prefix and stopping at the
first key not starting with prefix (spec 10 §3.2). prefix == ""
scans the whole keyspace in order (E5/E7).
Returns a boxed iterator of OWNED pairs (the future SQLite backend cannot
lend across a step(); we keep both backends signature-identical — spec
10 §4.1, §6).
Provided Methods§
Sourcefn clear(&self)
fn clear(&self)
Drop every key in this store, leaving it an empty namespace. Called by
Graph::destroy_pipeline to reclaim a
torn-down operator’s scratch state while keeping the slot reusable (the slot —
and, for a SQLite-backed store, its op_id namespace — is recycled by the next
alloc_storage, so we must clear contents, not drop the store object).
Default: collect the full keyspace then del each (the keys are collected
first so we are not iterating the store while mutating it). A backend with a
cheaper bulk delete (e.g. SQLite DELETE … WHERE op_id = ?) should override.