Rindle docs and package mapSkip to main content

Storage

Trait Storage 

Source
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§

Source

fn set(&self, key: &str, value: StorageValue)

Insert or overwrite key’s value (spec 10 §3.1, E3).

Source

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).

Source

fn del(&self, key: &str)

Remove key. No-op if absent (E4).

Source

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§

Source

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.

Implementors§