Module value
Expand description
The value vocabulary — moved to the dependency-free rindle-value crate and
re-exported here, so rindle::value::… is unchanged for every consumer. Crates that
need only cells (the write plane, the CDC apply plane) depend on rindle-value
directly and therefore cannot reach the engine at all.
The canonical value/row model — the union that graduates into
01-foundations §2–§3, refined by the SQLite step-buffer lifetime (the
forcing function). One model serves BOTH leaf backends:
- the borrowed-step-buffer rusqlite cursor (
sqlite.rs), whose column pointers are valid only until the next step, and - the held-
Rccrate::btree::BTreeCursor, which vends a row borrowed from anRc<BNode>snapshot it owns.
Three things are encoded structurally:
- A borrowed
Value<'a>(zero-copy,Copy) split from an ownedOwnedValue. The transient cursor path flowsValue<'a>; the only heap allocation isValue::to_owned, at the well-defined escape points the borrow checker forces (and the JS already copies at). Str/Jsoncarry bytes (&[u8]), not&str. SQLite’s defaultBINARYcollation is a bytewisememcmp, so the comparator needs no UTF-8 validation; the fallible, scanning&[u8]→&strstep is deferred to the app escape (to_owned). This is a deliberate refinement of foundations §2.2 (which wrote&'a str) driven by the SQLite reality: TEXT is not guaranteed UTF-8, and the validation scan is pure waste on the pass-through path.- Two distinct, undirivable comparators.
compare_valuestreatsnull == null(sorting);values_equaltreatsnull != null(join matching, SQL semantics). DerivingOrd/PartialEqwould make calling the wrong one trivially easy; named free functions make that bug hard to write. (Maps tozql/src/ivm/data.tscompareValuesvsvaluesEqual.)
Structs§
- Owned
Row - An owned row: an index-addressed, immutable, cheaply-clonable value sequence,
stored as one flat allocation (
205-FLAT-ROW-SINGLE-BUFFER-DESIGN.md). Cloning a row into an overlay / the view / a heap is a refcount bump, not a deep copy (shared-row aliasing is pervasive) — exactly as when this wasArc<[OwnedValue]>, but the cells now live inline in the row’s own buffer (no per-Str-cellArc<str>block), so materializing a row is one allocation instead of2 + k_text. - RelDef
- A declared outgoing relationship on a table
Schema(slot = index inSchema::relationships). Carries the public name the View surfaces (09) and, when known, the targetSchemathe relationship points at — the hierarchicalSourceSchemathe productionArrayView(09) navigates to sort child entries.childisNonefor a join-onlyRelDef(name resolution alone — the join already holds the child schema separately); the View requiresSome. - RelId
- A resolved relationship slot — the index of a relationship in its parent
table’s
Schema::relationships. Relationship names are resolved to aRelIdonce, at build time (Schema::rel_slot); the hot path (Change::Child``.rel,Relationship``.slot) carries the index, never a string (foundations §3.4, “never a string map”). A distinct newtype fromColIdso the two index spaces can’t be confused. - Scalar
Projection - A scalar projection annotation on a relationship slot (
REDUCE-DESIGN.md§9, Tier 1). A relationship aggregate —issue { commentCount: count(comments) }— lives in the engine tree as an ordinary singular one-row relationship whose child is the synthetic aggregate row[group_key…, agg]. This annotation tells the presentation boundary (theViewmarshaller and every wire receiver) to unwrap that one-row child into a plain scalar field named after the relationship: instead ofcommentCount: [{ issueID: 1, count: 5 }]the consumer seescommentCount: 5. It is purely a result-shape concern — the dataflow and the reconstructed tree stay a plural relationship of one row. - Schema
- The view / pipeline schema: a table’s columns + key + sort plus the
per-query relationship slots and
.one()shape the dataflow and materialized view carry. A source table is registered with the lighterSourceSchema(no relationships, nosingular); the build path widens that to aSchemaand fillsrelationshipsfrom the query AST — never from a source declaration, of which there are none. - Source
Schema - Static, user-declared source table metadata: columns, primary key, and the
table’s default sort. This is the table-registration boundary type — what
Graph::add_sourceand the builder’sresolvecallback speak.
Enums§
- Owned
Value - Owned counterpart, used wherever a value must outlive the cursor step that produced it: overlays, the memory store (the COW B+tree), the view, and operator-buffered state (Take/Exists, merge-heap heads).
- Value
- A cell value as seen while streaming.
Str/Jsonborrow raw bytes from the underlying buffer — a SQLite column-text pointer (valid only until the next step) or the bytes inside an owned row — so the whole value is valid only for'a. - Value
Type - The logical type of a column (or a literal), mirroring the JS
ValueType(zero-schema/table-schema.ts): the five types Zero stores, plus the opt-in exact-integer plane (design 226). It drives the SQLite value boundary —to_sqlite_param(boolean→0/1,json→serialized TEXT) andfrom_sqlite(ty-directedcol()conversion, thenumbersafe-int bound check). The leaf maps each to acrate::valuestorage class.
Traits§
- RowRef
- A borrowed view of one row; columns addressed by
ColId. The returnedValueborrowsself, so it is valid only as long as the row reference — for the SQLite leaf that means until the nextnext_row. - RowStream
- A lending stream of rows.
next_rowreborrowsself, so the row it returns is invalidated by the next call — exactly the SQLite cursor contract, now a compile-time invariant. This is the leaf source’s output shape; it is notstd::iter::Iterator(which hands out owned items and cannot express the borrow). GAT-based lending, stable since Rust 1.65.
Functions§
- compare_
int_ f64 - Exact
Int↔Floatcomparison (design 226 §5.1): compare mathematical values, with the twototal_cmpplacements preserved bit-for-bit so no existing data reorders —Int(i)carries+0.0’s sign (Int(0)>Float(-0.0)), and NaNs keep theirtotal_cmppositions (-NaNbelow everyInt,+NaNabove). - compare_
rows - Compare two owned rows under a sort spec (asc/desc per column). The common
short sorts (one/two columns) are unrolled to drop iterator overhead on the
hottest path. Each cell is borrowed via
as_ref()and fed to theValue<'_>comparator — no allocation. - compare_
values - SORT / identity-of-storage comparison.
null == null(Equal). Total order: null < everything. Floats usetotal_cmp(NOT subtraction — avoids the JSa - boverflow/NaN trap). Strings/json compare bytewise == SQLiteBINARYcollation.Int/Floatare the same JSnumberdomain and compare by widening tof64(JS has no int/float split — the distinction is a Rust-port artifact, so a mixed pair is not a type error). It arises in practice when an AST paging bound — integral literals lower toInt— is sorted against aNumbercolumn that vends asFloat(e.g. a SQLite leaf). A pair of genuinely different JS types (number vs string, …) is still a builder bug and panics, mirroring the JS oracle’scompareValuesthrow. - float_
int_ class - The §5.4 canonical numeric class:
Some(i)iffFloat(f)is exactly equal toInt(i)undercompare_int_f64— finite, integral, in i64 range, and not-0.0(whichtotal_cmporders below+0.0/Int(0)and so keeps float identity). Joint with the exact comparator this makes numeric equality an equivalence relation aHash + Eqkey can represent:Float(2^53)sharesInt(2^53)’s class, whileInt(2^53 + 1)keeps all 64 bits. - owned_
row - Build an
OwnedRowfrom a vec literal (test/util convenience). - same_pk
- True if rows share the same primary key (PK columns are non-null, so
values_equalbehaves like identity here). - values_
equal - JOIN / equality comparison.
null != null(any null operand ⇒ not equal) — the opposite ofcompare_values. Required for correct join semantics. - values_
identical - PREDICATE identity comparison — the third comparator (
07§4.2/§8.1). A compiledwherepredicate’s=/!=/INevaluates with this, NOT withvalues_equal: a filter treatsnullas identical tonull(socol = nullmatches a null cell), the opposite of join semantics. It is distinct from all three of: