obj_core/index/mod.rs
1//! Secondary indexes (L6) — index B+trees layered over the M4 B+tree.
2//!
3//! M7 adds *secondary indexes*: per-collection B+trees keyed by an
4//! order-preserving encoding of one or more document fields, valued
5//! by the document's [`Id`](crate::Id). See `docs/format.md`
6//! § Indexes for the authoritative on-disk layout.
7//!
8//! Each declared index lives in its own B+tree (M4 — no new on-disk
9//! page types). The index's root page-id is persisted inside the
10//! owning [`CollectionDescriptor`](crate::catalog::CollectionDescriptor)
11//! as an [`IndexDescriptor`](crate::catalog::IndexDescriptor) entry
12//! (M5 reserved the field; M7 fills it).
13//!
14//! # Module split
15//!
16//! - [`spec`] — runtime declaration shapes: [`IndexKind`],
17//! [`IndexSpec`], constructors. The descriptor on-disk shape lives
18//! in [`crate::catalog`] because the catalog owns the wire row.
19//! - [`key`] — order-preserving byte encoding for `Dynamic` values
20//! plus the composite envelope. The encoding contract is documented
21//! in `docs/format.md` § Index key encoding.
22//!
23//! # Power-of-ten posture
24//!
25//! - **Rule 1.** No recursion: the encoder walks the input
26//! `&[Dynamic]` with a single bounded `for` loop.
27//! - **Rule 2.** Per-encode loops are bounded by the input slice
28//! length, which the caller has already validated against
29//! `IndexSpec::key_paths.len()`.
30//! - **Rule 5.** Field count is checked against `IndexSpec`'s
31//! `key_paths` at the encode-time runtime boundary; type-level
32//! invariants (kind enum, non-empty `key_paths` for composite,
33//! single-field for `Each`) sit on the constructors.
34//! - **Rule 7.** No `unwrap` / `expect` on the production path. The
35//! encoder returns `Err(Error::Codec)` on `String` fields that
36//! contain an embedded `0x00` (the terminator would split the
37//! key — see `docs/format.md`).
38//! - **Rule 9.** All dispatch is static — `IndexKind` is an enum
39//! matched at every call site; no `dyn`, no macro generation.
40
41#![forbid(unsafe_code)]
42
43pub mod extract;
44pub mod key;
45pub mod spec;
46
47pub use crate::index::extract::{extract_index_keys, MAX_EACH_ENTRIES};
48pub use crate::index::key::{
49 encode_field, encode_index_key, encode_index_key_parts, encoded_id_suffix_len, EncodedIndexKey,
50 COMPOSITE_TAG,
51};
52pub use crate::index::spec::{IndexKind, IndexSpec};