obj-core 1.1.2

Storage engine internals for the obj embedded document database (pager, WAL, B-tree, codec, catalog).
Documentation
//! Secondary indexes (L6) — index B+trees layered over the M4 B+tree.
//!
//! M7 adds *secondary indexes*: per-collection B+trees keyed by an
//! order-preserving encoding of one or more document fields, valued
//! by the document's [`Id`](crate::Id). See `docs/format.md`
//! § Indexes for the authoritative on-disk layout.
//!
//! Each declared index lives in its own B+tree (M4 — no new on-disk
//! page types). The index's root page-id is persisted inside the
//! owning [`CollectionDescriptor`](crate::catalog::CollectionDescriptor)
//! as an [`IndexDescriptor`](crate::catalog::IndexDescriptor) entry
//! (M5 reserved the field; M7 fills it).
//!
//! # Module split
//!
//! - [`spec`] — runtime declaration shapes: [`IndexKind`],
//!   [`IndexSpec`], constructors. The descriptor on-disk shape lives
//!   in [`crate::catalog`] because the catalog owns the wire row.
//! - [`key`] — order-preserving byte encoding for `Dynamic` values
//!   plus the composite envelope. The encoding contract is documented
//!   in `docs/format.md` § Index key encoding.
//!
//! # Power-of-ten posture
//!
//! - **Rule 1.** No recursion: the encoder walks the input
//!   `&[Dynamic]` with a single bounded `for` loop.
//! - **Rule 2.** Per-encode loops are bounded by the input slice
//!   length, which the caller has already validated against
//!   `IndexSpec::key_paths.len()`.
//! - **Rule 5.** Field count is checked against `IndexSpec`'s
//!   `key_paths` at the encode-time runtime boundary; type-level
//!   invariants (kind enum, non-empty `key_paths` for composite,
//!   single-field for `Each`) sit on the constructors.
//! - **Rule 7.** No `unwrap` / `expect` on the production path. The
//!   encoder returns `Err(Error::Codec)` on `String` fields that
//!   contain an embedded `0x00` (the terminator would split the
//!   key — see `docs/format.md`).
//! - **Rule 9.** All dispatch is static — `IndexKind` is an enum
//!   matched at every call site; no `dyn`, no macro generation.

#![forbid(unsafe_code)]

pub mod extract;
pub mod key;
pub mod spec;

pub use crate::index::extract::{extract_index_keys, MAX_EACH_ENTRIES};
pub use crate::index::key::{
    encode_field, encode_index_key, encode_index_key_parts, encoded_id_suffix_len, EncodedIndexKey,
    COMPOSITE_TAG,
};
pub use crate::index::spec::{IndexKind, IndexSpec};