//! S-expression AST.
use crate::error::{SexpShape, SexpWitness, StructuralKind, UnquoteForm};
use std::fmt;
// Bring `fmt::Write` into scope so `f.write_char(Self::LIST_OPEN)` at
// [`fmt::Display for Sexp`] resolves — the outer-structural delimiter
// arms of the `Self::Nil` / `Self::List` rendering routes through
// [`Sexp::LIST_OPEN`] / [`Sexp::LIST_CLOSE`] via `fmt::Write::write_char`
// rather than through the format! machinery (`write!(f, "{}", '(')`)
// so the (typed delimiter, formatter emission) pair binds directly on
// the closed-set outer-algebra without a per-char formatting round-trip.
// The `as _` alias imports the trait's methods without adding a name to
// the ast.rs namespace, matching the Rust idiom for extension-trait
// import hygiene.
use std::fmt::Write as _;
use std::hash::{Hash, Hasher};
/// Compile-time contract verifier — panics at const evaluation time if
/// any two entries of `arr` alias byte-for-byte.
///
/// Lifts the "each family-wide `[char; N]` on the substrate's reader-
/// boundary vocabulary is pairwise distinct" invariant from a runtime
/// pin-per-array (`sexp_non_whitespace_bare_atom_terminators_are_
/// pairwise_distinct`, `sexp_list_delimiters_pairwise_distinct`,
/// `sexp_comment_delimiters_pairwise_distinct`, `quote_form_leads_
/// pairwise_distinct`, `atom_self_escape_table_pairwise_distinct`,
/// `atom_escape_sources_pairwise_distinct`, `atom_escape_decoded_
/// pairwise_distinct`) into a COMPILE-TIME theorem the substrate
/// carries at every array declaration via a co-located `const _: () =
/// assert_char_array_pairwise_distinct(&Self::FOO_ARRAY);` witness.
///
/// The invariant is load-bearing for every consumer that pattern-
/// matches the array's entries as DISJOINT arms — the reader's outer-
/// dispatch cascade in `crate::reader::tokenize` matches on the four
/// [`Sexp::LIST_OPEN`] / [`Sexp::LIST_CLOSE`] / [`Atom::STR_DELIMITER`]
/// / [`Sexp::COMMENT_LEAD`] arms (a duplicate here would break the
/// `match c { … }` exhaustiveness); [`Atom::decode_str_escape`]'s
/// escape table matches on the FIVE [`Atom::ESCAPE_SOURCES`] arms
/// (a duplicate here would silently shadow the second arm);
/// [`QuoteForm::from_lead_char`] matches on the THREE [`QuoteForm::LEADS`]
/// arms (a duplicate here would break the three-way outer-dispatch);
/// and every future family-wide `[char; N]` on the substrate that
/// participates in a `match`-arm partition benefits from the SAME
/// compile-time guarantee via one `const _` line.
///
/// Pre-lift each array carried its pairwise-distinctness contract at
/// ONE runtime test (`cargo test`-triggered): a regression that
/// silently collided two entries would compile cleanly and fail only
/// at test run. Post-lift the contract binds at `cargo check` time —
/// the const-eval panic surfaces the collision at COMPILE time, one
/// invocation stage earlier, catching regressions on `cargo build` /
/// `cargo clippy` runs that skip the test suite.
///
/// Adding a new family-wide `[char; N]` array to the substrate: pair
/// the declaration with `const _: () = assert_char_array_pairwise_
/// distinct(&Self::FOO_ARRAY);` co-located immediately after the
/// array's declaration and the distinctness contract is enforced at
/// compile time. The rustc-forced arity `[char; N]` composes with
/// this const-eval sweep so BOTH cardinality AND injectivity are
/// compile-time theorems on the SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP tokenizer
/// that constructs a `[char; N]` at runtime and wants to verify
/// pairwise distinctness before consuming it — and the panic surfaces
/// normally in that path (pinned by `assert_char_array_pairwise_
/// distinct_panics_at_runtime_on_collision`).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide distinctness
/// contract becomes a TYPE-LEVEL theorem the substrate carries per
/// array declaration rather than a runtime test the developer must
/// remember to write per array.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// sweep IS the generative shape. Every new closed-set char array
/// adds ONE `const _` line to get the distinctness theorem rather
/// than re-deriving a `HashSet::insert` loop test per array.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// distinctness proof at declaration site AND the outer-dispatch
/// match-arm exhaustiveness the consumer relies on regenerate
/// through the SAME `const _` witness.
pub const fn assert_char_array_pairwise_distinct<const N: usize>(arr: &[char; N]) {
let mut i = 0;
while i < N {
let mut j = i + 1;
while j < N {
if arr[i] as u32 == arr[j] as u32 {
panic!(
"assert_char_array_pairwise_distinct: family-wide \
char array carries a duplicate entry across two \
positions — the substrate's pairwise-distinctness \
contract on the array is broken; every consumer \
that pattern-matches the array's entries as \
DISJOINT arms (reader outer-dispatch, escape-table \
decode, quote-family lead dispatch) relies on this \
invariant"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time pairwise-distinctness witnesses — one `const _: () =
// assert_char_array_pairwise_distinct(&…)` per family-wide `[char; N]`
// char array on the substrate's reader-boundary vocabulary. Each
// invocation is const-evaluated at `cargo check` time; a regression
// that silently collides two entries fails the build rather than the
// test suite. Sibling to the runtime `_pairwise_distinct` tests at
// `ast.rs`'s tests module — the two enforce the same theorem at TWO
// stages of the toolchain, so a build that skips tests still catches
// the regression here, and a build that runs tests catches it a
// second time as a safety net if the const-eval sweep is ever
// silently dropped.
const _: () = assert_char_array_pairwise_distinct(&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS);
const _: () = assert_char_array_pairwise_distinct(&Sexp::LIST_DELIMITERS);
const _: () = assert_char_array_pairwise_distinct(&Sexp::COMMENT_DELIMITERS);
const _: () = assert_char_array_pairwise_distinct(&QuoteForm::LEADS);
const _: () = assert_char_array_pairwise_distinct(&Atom::SELF_ESCAPE_TABLE);
const _: () = assert_char_array_pairwise_distinct(&Atom::ESCAPE_SOURCES);
const _: () = assert_char_array_pairwise_distinct(&Atom::ESCAPE_DECODED);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `arr` carries a Unicode scalar value outside the
/// seven-bit ASCII range (`> 0x7F`).
///
/// Element-type row-dual peer to [`assert_str_array_all_ascii`] on the
/// (element-type) axis of the (element-type × contract-shape) matrix at
/// the (per-entry, ASCII) column: where the (`&'static str`) sibling
/// closes the ASCII-BYTE-RANGE per-entry corner on the substrate's
/// closed-set outer algebras' family-wide `[&'static str; N]` label
/// vocabularies, this (`char`) sibling closes the SAME per-entry
/// contract-shape corner on the substrate's reader-boundary `[char; N]`
/// scalar vocabularies. The two helpers close the (element-type ∈
/// {char, `&'static str`} × contract-shape ∈ {ASCII}) 2-corner row of
/// the per-entry ASCII column at ONE peer const-fn helper per element-
/// type. Contract-orthogonal peer to
/// [`assert_char_array_pairwise_distinct`] on the (INJECTIVITY, ASCII)
/// axis of the (per-entry × set-level) column on the SAME (`char`) row:
/// where the pairwise-distinctness sibling binds SET-LEVEL `∀ i ≠ j :
/// arr[i] ≠ arr[j]`, this ASCII sibling binds PER-ENTRY `∀ i : (arr[i]
/// as u32) <= 0x7F` — the two together give every `[char; N]` sub-
/// vocabulary on the substrate BOTH set-level injectivity AND per-
/// entry byte-range containment at compile time. Note the (per-entry,
/// NONEMPTY) corner from the (`&'static str`) row is intentionally
/// absent here: a `char` is a single Unicode scalar value and carries
/// no length dimension, so the NONEMPTY per-entry gate degenerates to
/// a vacuous tautology on the (`char`) row and needs no peer.
///
/// The invariant is load-bearing for every consumer that ships an
/// array entry through a downstream surface whose canonical form is
/// seven-bit-clean — the reader's `matches!(c, LIST_OPEN | LIST_CLOSE
/// | …)` outer-dispatch on [`Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS`]
/// entries; the tokenizer's byte-level scan on [`Sexp::LIST_DELIMITERS`]
/// / [`Sexp::COMMENT_DELIMITERS`] / [`QuoteForm::LEADS`] entries; the
/// atom-payload escape-decode dispatch on [`Atom::SELF_ESCAPE_TABLE`] /
/// [`Atom::ESCAPE_SOURCES`] / [`Atom::ESCAPE_DECODED`] entries. Every
/// consumer treats each entry as a single seven-bit-clean ASCII scalar;
/// a regression that silently re-inlined `LIST_OPEN = '('` (fullwidth
/// U+FF08) or `QUOTE_LEAD = '‘'` (U+2018) — lookalike scalars that
/// would parse as a Rust `char` literal but ship a multi-byte UTF-8
/// sequence at every reader-boundary byte comparison — fails at `cargo
/// check` BEFORE any test scheduler runs.
///
/// Adding a new family-wide `[char; N]` reader-boundary scalar
/// vocabulary whose canonical spelling is seven-bit-clean: pair the
/// declaration with `const _: () = assert_char_array_all_ascii
/// (&Self::FOO_ARRAY);` co-located after the array's declaration and
/// the ASCII-SCALAR-RANGE contract binds at compile time. The rustc-
/// forced arity `[char; N]` composes with this const-eval sweep so
/// BOTH cardinality AND per-entry ASCII are compile-time theorems on
/// the SAME array declaration.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_char_array_all_ascii_panics_at_runtime_on_head_non_ascii` /
/// `_interior_non_ascii` / `_tail_non_ascii` and
/// `assert_char_array_all_ascii_panic_message_names_the_helper_and_axis`.
/// The panic site carries the `"CHAR-NON-ASCII-SCALAR"` axis-
/// provenance string chosen DISTINCT from every sibling helper's axis
/// vocabulary (`"duplicate"` on the pairwise-distinct sibling;
/// `"CHAR-SUBSET-VIOLATION"` on the within-finite-set sibling;
/// `"CHAR-DISJOINTNESS-VIOLATION"` on the arrays-disjoint sibling;
/// `"STR-NON-ASCII-ENTRY"` on the (`&'static str`) row-dual ASCII
/// sibling) so a diagnostic that names the failed axis routes
/// UNAMBIGUOUSLY to THIS specific (`char`)-row ASCII helper. The
/// `"CHAR-"` prefix disambiguates from the (`&'static str`) row-dual
/// ASCII sibling; the shared `"-NON-ASCII-"` infix lets callers grep
/// any row's ASCII sibling by `"NON-ASCII"` alone.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide per-entry
/// ASCII-scalar-range contract on the substrate's reader-boundary
/// `char` vocabulary becomes a TYPE-LEVEL theorem the substrate
/// carries per array declaration rather than a runtime test the
/// developer must remember to write per scalar constant.
/// - THEORY.md §II.1 invariant 1 — typed entry; a reader-boundary
/// scalar's `char` projection IS the entry-point discriminator into
/// the tokenizer's outer dispatch, and a non-ASCII scalar in that
/// projection silently escapes the byte-level assumption every
/// downstream parser encodes into its own byte-position arithmetic.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the ASCII per-entry corner on TWO rows
/// ({`char`, `&'static str`}) at ONE peer const-fn helper per row.
/// The (element-type ∈ {char, `&'static str`}) × (contract-shape ∈
/// {per-entry ASCII}) 2-corner row of the per-entry ASCII column is
/// now closed at TWO peer const-fn helpers.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// scalar-range sweep IS the generative shape. Every new closed-set
/// reader-boundary scalar array adds ONE `const _` line to get the
/// ASCII theorem rather than re-deriving a per-array runtime iterator
/// sweep at each call site.
///
/// Frontier inspiration: Lean 4's `List.all` unfolded to `∀ i : arr[i]
/// ∈ ascii` at the concrete `[char; N]` monomorphic realisation, where
/// `ascii := { c : Char // c.toNat ≤ 0x7F }`. The (`char`, `&'static
/// str`) row-dual pair mirrors Lean's element-polymorphic `List α`
/// realised at the two concrete element-type instantiations the
/// substrate closes at compile time.
pub const fn assert_char_array_all_ascii<const N: usize>(arr: &[char; N]) {
let mut i = 0;
while i < N {
if arr[i] as u32 > 0x7F {
panic!(
"assert_char_array_all_ascii: CHAR-NON-ASCII-SCALAR — \
the family-wide char array carries an entry with a \
Unicode scalar value outside the seven-bit ASCII \
range (> 0x7F) at some position — the substrate's \
ASCII-SCALAR-RANGE contract on the array is broken; \
every consumer that ships an entry through a seven-\
bit-clean reader-boundary surface (the reader's \
`matches!(c, LIST_OPEN | ...)` outer-dispatch on \
NON_WHITESPACE_BARE_ATOM_TERMINATORS entries; the \
tokenizer's byte-level scan on LIST_DELIMITERS / \
COMMENT_DELIMITERS / QuoteForm::LEADS entries; the \
atom-payload escape-decode dispatch on SELF_ESCAPE_\
TABLE / ESCAPE_SOURCES / ESCAPE_DECODED entries) \
treats each entry as a single seven-bit-clean ASCII \
scalar — a non-ASCII scalar silently invites lookalike-\
char collisions (fullwidth U+FF08 `(` vs ASCII U+0028 \
`(`) and multi-byte UTF-8 drift that byte-position \
arithmetic cannot detect. Fix at the ARRAY-DECLARATION \
site by re-inlining the offending scalar constant to \
its seven-bit-clean canonical spelling"
);
}
i += 1;
}
}
// Compile-time ASCII-SCALAR-RANGE witnesses — one `const _: () =
// assert_char_array_all_ascii(&…)` per family-wide `[char; N]` char
// array on the substrate's reader-boundary vocabulary. Each invocation
// is const-evaluated at `cargo check` time; a regression that silently
// re-inlined one scalar constant to a lookalike non-ASCII scalar
// (fullwidth U+FF08 `(`, curly-quote U+2018 `‘`, etc.) fails the
// build rather than deferring to a per-consumer byte-parse
// misbehavior at runtime. Sibling to the pairwise-distinctness
// witnesses above — those pin SET-LEVEL INJECTIVITY on each array,
// these pin the strictly-orthogonal PER-ENTRY byte-range gate on the
// SAME arrays. The two contracts compose orthogonally on every reader-
// boundary `[char; N]` scalar vocabulary. The seven arrays covered
// here mirror the seven arrays already pinned by the
// `_pairwise_distinct` witnesses above — the (per-entry × set-level)
// coverage matrix on the (`char`) row of this file now holds at TWO
// corners {INJECTIVITY (set-level), ASCII (per-entry)} for the seven
// reader-boundary arrays declared here.
const _: () = assert_char_array_all_ascii(&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS);
const _: () = assert_char_array_all_ascii(&Sexp::LIST_DELIMITERS);
const _: () = assert_char_array_all_ascii(&Sexp::COMMENT_DELIMITERS);
const _: () = assert_char_array_all_ascii(&QuoteForm::LEADS);
const _: () = assert_char_array_all_ascii(&Atom::SELF_ESCAPE_TABLE);
const _: () = assert_char_array_all_ascii(&Atom::ESCAPE_SOURCES);
const _: () = assert_char_array_all_ascii(&Atom::ESCAPE_DECODED);
/// Compile-time contract verifier — panics at const evaluation time if
/// the distinct-values set of `arr` is not a subset of the distinct-
/// values set of `set` on the substrate's reader-boundary `char`
/// vocabulary. Binds ONE conjunct clause: CHAR-SUBSET-VIOLATION —
/// every entry in `arr` MUST also appear as an entry in `set`.
///
/// Element-type column-dual peer to
/// [`assert_u8_array_within_u8_finite_set`] on the (element-type) axis:
/// where the `u8` sibling closes the SUBSET-EMBEDDING corner on the
/// outer-`Sexp` cache-key `u8` vocabulary, this `char` sibling closes
/// the SAME corner on the reader-boundary `char` vocabulary. The two
/// helpers close the SUBSET-EMBEDDING × non-contiguous-target-set
/// corner of the (element-type × contract-shape) matrix at ONE
/// primitive per element-type row rather than at a per-embedding
/// runtime iterator sweep per call site. Contract-strength peer to
/// (the future-lift) `assert_char_array_covers_char_finite_set` on the
/// (equality-vs-subset) axis: this helper binds ONLY arr ⊆ set (the
/// SUBSET-VIOLATION arm read in isolation without the SET-CHAR-MISSING
/// full-coverage clause) — a strictly WEAKER contract for arrays that
/// intentionally cover only a PROPER SUBSET of the target partition.
///
/// SET-side well-formedness delegation: [`assert_char_array_pairwise_distinct`]
/// is called on `set` at the top of the helper as the SET-side well-
/// formedness gate. Placed FIRST so drift on the CALLER'S TARGET-SET
/// SPEC (e.g. `['a', 'a', 'b']` fed as `set`) routes to the SET-side
/// well-formedness axis (via the sibling's `"assert_char_array_
/// pairwise_distinct"` panic-name prefix) rather than to a downstream
/// CHAR-SUBSET-VIOLATION symptom on `arr`. Delegates to the SAME
/// helper the ARRAY-side pairwise-distinctness pin uses rather than to
/// a bespoke `assert_char_finite_set_pairwise_distinct` alias because
/// the char row does NOT yet carry a sibling `_covers_char_finite_set`
/// / `_permutes_char_finite_set` helper that would benefit from a
/// distinct SET-side axis-provenance vocabulary across three call
/// sites — the (u8) row's separate `assert_u8_finite_set_pairwise_distinct`
/// alias exists exactly because the finite-set-family compound helpers
/// (`_within_u8_finite_set`, `_covers_u8_finite_set`,
/// `_permutes_u8_finite_set`) all delegate to it. When the char row
/// grows its second finite-set-family compound helper, a future run
/// lifts the SET-side alias then; today the delegation reuses the
/// ARRAY-side helper directly. A well-formed `set` passes this arm as
/// a no-op — const-eval-elidable at rustc-time on the substrate call
/// site.
///
/// The invariant is load-bearing for three intentionally-closed
/// SUBSET-embedding relations on the substrate's reader-boundary
/// `char` vocabulary that pre-lift lived only as prose in the
/// [`Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS`] docstring's
/// four-category composition rule (LIST_DELIMITERS + QuoteForm::LEADS +
/// {STR_DELIMITER} + {COMMENT_LEAD}):
///
/// 1. [`Sexp::LIST_DELIMITERS`] (`[char; 2]` = `[LIST_OPEN,
/// LIST_CLOSE]` — the outer-structural paired-delimiter arm-set)
/// MUST be a SUBSET of
/// [`Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS`] (`[char; 7]`
/// — the reader outer-dispatch category-leading char ALL array).
/// A drift that dropped `LIST_OPEN` (or `LIST_CLOSE`) from
/// `NON_WHITESPACE_BARE_ATOM_TERMINATORS` while it stayed in
/// `LIST_DELIMITERS` (or vice versa: a drift that re-inlined
/// `LIST_DELIMITERS` to a fresh char not in the terminator ALL
/// array) would silently break the four-category composition
/// rule. Post-lift the SUBSET embedding binds at rustc time.
///
/// 2. [`QuoteForm::LEADS`] (`[char; 3]` = `[QUOTE_LEAD,
/// QUASIQUOTE_LEAD, UNQUOTE_LEAD]` — the quote-family lead-char
/// sub-vocabulary) MUST be a SUBSET of
/// [`Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS`]. Same argument
/// as above on the three quote-lead category of the four-category
/// composition rule.
///
/// 3. [`Atom::SELF_ESCAPE_TABLE`] (`[char; 2]` = `[STR_DELIMITER,
/// STR_ESCAPE_LEAD]` — the pattern-EQUALS-value sub-vocabulary of
/// the escape arm-set) MUST be a SUBSET of
/// [`Atom::ESCAPE_SOURCES`] (`[char; 5]` — the SOURCE-column
/// SPAN of all five non-passthrough escape arms). A drift that
/// re-inlined a SELF entry to a fresh char not in the SOURCE-
/// column SPAN would silently violate the composition law
/// `ESCAPE_SOURCES == [NAMED[0].0, NAMED[1].0, NAMED[2].0,
/// SELF[0], SELF[1]]` at the SELF-slot suffix. Post-lift the
/// SUBSET embedding binds at rustc time.
///
/// Every future family-wide `[char; N]` typed-subset carving on the
/// substrate's reader-boundary vocabulary participates in the SAME
/// compile-time guarantee via one `const _` line.
///
/// Adding a new family-wide `[char; N]` subset-embedded array to the
/// substrate: pair the declaration with `const _: () =
/// assert_char_array_within_char_finite_set::<N, M>(&Self::FOO_ARRAY,
/// &Other::SUPERSET_ARRAY);` co-located after the array's declaration
/// and the SUBSET contract binds at compile time. The rustc-forced
/// arities `[char; N]` and `[char; M]` compose with this const-eval
/// sweep so BOTH cardinality-pair AND every-entry-in-superset are
/// compile-time theorems on the SAME (subset, superset) char-array
/// pair.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_char_array_within_char_finite_set_panics_at_runtime_on_out_of_set_entry`
/// and
/// `assert_char_array_within_char_finite_set_panic_message_names_the_helper_and_char_subset_violation_axis`.
/// The panic site carries the `"CHAR-SUBSET-VIOLATION"` axis-
/// provenance string chosen DISTINCT from every sibling helper's axis
/// vocabulary (`"duplicate"` on the ARRAY-side pairwise-distinct
/// sibling; `"SUBSET-VIOLATION"` on the (u8) finite-set SUBSET-only
/// sibling; `"RANGE-SUBSET-VIOLATION"` on the (u8) range SUBSET-only
/// sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the (u8) covers-
/// finite-set sibling; `"OUT-OF-RANGE"` / `"MISSING"` on the (u8)
/// covers-inclusive-range sibling; `"ARITY-MISMATCH"` on both (u8)
/// `_permutes_*` compound helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on
/// the (u8) SET-side well-formedness sibling) so a diagnostic that
/// names the failed axis routes UNAMBIGUOUSLY to THIS specific char
/// SUBSET-embedding helper. The `"CHAR-"` prefix disambiguates from
/// the (u8) SUBSET-only helper's bare `"SUBSET-VIOLATION"`; the shared
/// `"-VIOLATION"` suffix lets callers grep either SUBSET-embedding
/// sibling by `"VIOLATION"` alone or route to the specific element-
/// type row by the disambiguator prefix.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide subset-
/// embedding contract on the reader-boundary `char` vocabulary
/// becomes a TYPE-LEVEL theorem the substrate carries per (subset,
/// superset) array pair rather than a runtime test the developer
/// must remember to write per embedding. The three witness sites
/// above (`LIST_DELIMITERS ⊆ NON_WHITESPACE_BARE_ATOM_TERMINATORS`,
/// `QuoteForm::LEADS ⊆ NON_WHITESPACE_BARE_ATOM_TERMINATORS`,
/// `SELF_ESCAPE_TABLE ⊆ ESCAPE_SOURCES`) previously lived only as
/// prose in their parent arrays' composition-rule docstrings.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the SUBSET-EMBEDDING corner at BOTH
/// the `u8` row and the `char` row, closing the element-type column
/// on the SUBSET-corner face at two peer const-fn helpers rather
/// than at one primitive with a runtime cast per element-type.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// set-membership sweep IS the generative shape. Every new closed-
/// set `char` sub-vocabulary array whose distinct-value set is an
/// intentional SUBSET of another substrate `char` array adds ONE
/// `const _` line to get the subset-embedding theorem rather than
/// re-deriving a per-embedding runtime iterator sweep at each call
/// site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// SUBSET-embedding proof at declaration site AND the reader outer-
/// dispatch cascade's four-category exhaustiveness contract (which
/// assumes LIST_DELIMITERS + QuoteForm::LEADS + STR_DELIMITER +
/// COMMENT_LEAD partition the NON_WHITESPACE_BARE_ATOM_TERMINATORS
/// ALL array) regenerate through the SAME `const _` witnesses at
/// the ARRAY level.
///
/// Frontier inspiration: Lean 4's `Finset.instHasSubsetFinset :
/// (⊆) : Finset α → Finset α → Prop` as a decidable relation on
/// `Finset α` combined with `Finset.subset_iff` unfolding the relation
/// to per-element membership — the substrate primitive here embeds
/// the same subset relation as a rustc const-eval-time proof
/// obligation at every `assert_char_array_within_char_finite_set`
/// call site rather than as a Lean tactic invocation deferred to
/// `elab_command`. The element-type generalization from `u8` to `char`
/// mirrors Lean's polymorphism over the `α` type parameter on
/// `Finset`; the substrate binds the two concrete instantiations
/// (`u8` at [`assert_u8_array_within_u8_finite_set`], `char` here)
/// as separate `pub const fn`s because Rust's const-generic system
/// does not yet admit polymorphism over element type through a
/// custom trait bound at const-eval time. Each element-type row is a
/// monomorphic realisation of the SAME subset-embedding contract
/// shape.
pub const fn assert_char_array_within_char_finite_set<const N: usize, const M: usize>(
arr: &[char; N],
set: &[char; M],
) {
// Delegate target-set well-formedness to the sibling ARRAY-side
// pairwise-distinctness helper FIRST. Placed BEFORE the CHAR-
// SUBSET-VIOLATION sweep below because a malformed `set` (e.g.
// `['a', 'a', 'b']`) is not a well-formed finite set of
// cardinality `M` and silently mis-verifies the intended subset
// contract on any `arr` embedded in the DISTINCT-value subset.
// Routes drift on the CALLER'S TARGET-SET SPEC to the SET-side
// well-formedness axis (via the sibling's own panic-name prefix)
// rather than to a downstream CHAR-SUBSET-VIOLATION symptom on
// `arr`. A well-formed `set` passes this arm as a no-op — the
// sweep is const-eval-elidable and costs zero at rustc-time on
// the substrate call sites.
assert_char_array_pairwise_distinct(set);
let mut i = 0;
while i < N {
let mut j = 0;
let mut found = false;
while j < M {
if arr[i] as u32 == set[j] as u32 {
found = true;
break;
}
j += 1;
}
if !found {
panic!(
"assert_char_array_within_char_finite_set: CHAR-\
SUBSET-VIOLATION — the family-wide char array `arr` \
carries an entry at some position whose char is NOT \
a member of the target finite superset partition \
`set`. The substrate's SUBSET-EMBEDDING contract on \
the array is broken; every consumer that expects the \
array's distinct-value set to be a subset of the \
target finite partition (`Sexp::LIST_DELIMITERS ⊂ \
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS` on the \
outer-structural paired-delimiter axis of the reader \
outer-dispatch terminator ALL array; \
`QuoteForm::LEADS ⊂ \
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS` on the \
quote-family lead-char axis of the SAME terminator \
ALL array; `Atom::SELF_ESCAPE_TABLE ⊂ \
Atom::ESCAPE_SOURCES` on the pattern-EQUALS-value \
sub-vocabulary axis of the escape-arm SOURCE-column \
SPAN; any future typed-subset embedding on the \
substrate's reader-boundary char algebras) relies on \
every array entry staying within the target \
superset. Fix at the ARRAY-DECLARATION site (the \
`arr` under verification, NOT the `set` argument \
specifying the target superset) by dropping the \
offending entry OR by extending `set` to cover it — \
the choice depends on whether the drift is an \
unintended overshoot outside the parent superset or \
an intentional extension of the superset vocabulary"
);
}
i += 1;
}
}
// Compile-time SUBSET-embedding witnesses — the THREE family-wide
// `[char; N]` intentionally-closed PROPER-SUBSET carvings on the
// substrate's reader-boundary vocabulary whose distinct-value set is
// a subset of another family-wide `[char; M]` array's distinct-value
// set. Pre-lift the three subset relations lived only as prose in the
// parent arrays' composition-rule docstrings (the four-category
// composition rule on `NON_WHITESPACE_BARE_ATOM_TERMINATORS`, the
// pattern-EQUALS-value sub-vocabulary partition on `ESCAPE_SOURCES`).
// Post-lift the three ARRAY-LEVEL subset embeddings bind at rustc
// time — a regression that re-inlined either the SUBSET or the
// SUPERSET side of any relation to a fresh char breaking the subset
// containment (e.g. dropping `Sexp::LIST_OPEN` from
// `NON_WHITESPACE_BARE_ATOM_TERMINATORS` while it stayed in
// `LIST_DELIMITERS`; drifting `QuoteForm::QUOTE_LEAD` to a fresh
// char not in the terminator ALL array; re-shuffling `ESCAPE_SOURCES`
// to swap its SELF-slot suffix bytes with unrelated NAMED-slot bytes)
// fails at `cargo check` BEFORE any test scheduler runs. Sibling to
// the pairwise-distinctness witnesses above — those pin INJECTIVITY
// on each individual array, these pin SUBSET containment across
// PAIRS of arrays.
const _: () = assert_char_array_within_char_finite_set::<2, 7>(
&Sexp::LIST_DELIMITERS,
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
);
const _: () = assert_char_array_within_char_finite_set::<3, 7>(
&QuoteForm::LEADS,
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
);
const _: () = assert_char_array_within_char_finite_set::<2, 5>(
&Atom::SELF_ESCAPE_TABLE,
&Atom::ESCAPE_SOURCES,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the distinct-values sets of `a` and `b` share any char on the
/// substrate's reader-boundary `char` vocabulary. Binds ONE conjunct
/// clause: CHAR-DISJOINTNESS-VIOLATION — no entry in `a` may appear as
/// an entry in `b` (symmetric across the two array arguments).
///
/// Contract-orthogonal peer to [`assert_char_array_within_char_finite_set`]
/// on the (subset-vs-disjointness) axis of the (contract-shape) axis:
/// where the SUBSET-EMBEDDING helper binds `arr ⊆ set` at compile time
/// on the (char) row, this DISJOINTNESS helper binds `a ∩ b = ∅` at
/// compile time on the SAME element-type row. Together the two helpers
/// close the (subset, disjointness) 2-corner face on the (char)
/// contract-shape column at ONE primitive per corner rather than at a
/// per-pair runtime iterator sweep per call site. The disjointness
/// relation is SYMMETRIC (unlike the SUBSET-EMBEDDING relation, which
/// distinguishes `arr` from `set`) so the two arguments carry NO axis-
/// provenance role split — either drift site (a char in `a` that
/// aliases a char in `b`, OR a char in `b` that aliases a char in `a`)
/// surfaces at the CHAR-DISJOINTNESS-VIOLATION panic with the OFFENDING
/// arm named by BOTH position indices (`a[i]` AND `b[j]`) rather than
/// by only one side of the pair.
///
/// SYMMETRY IN THE NESTED SWEEP: the inner `while j < M` sweep visits
/// every position of `b` per outer `i` and panics at the FIRST cross-
/// array collision (`a[i] == b[j]`). Because the relation is symmetric
/// and the two-loop sweep visits every `(i, j) ∈ [0, N) × [0, M)` pair,
/// swapping `a` and `b` at the call site produces the SAME verdict —
/// the helper does NOT gratuitously depend on argument order. A future
/// call site that intends to name a SPECIFIC drift side can still route
/// its own preferred first-mention by picking the argument order that
/// serves its diagnostic story; the helper itself carries no such
/// preference.
///
/// The invariant is load-bearing for the reader's outer-dispatch
/// cascade at [`crate::reader::tokenize`]: the SIX outer-dispatch
/// category-leading char families the tokenizer specialises on
/// ([`Sexp::LIST_OPEN`] / [`Sexp::LIST_CLOSE`] arm; every
/// [`QuoteForm::lead_char`] arm; [`Atom::STR_DELIMITER`] arm;
/// [`Sexp::COMMENT_LEAD`] arm; whitespace arm) MUST route to DISJOINT
/// arms — otherwise a shared byte would silently reclassify at the
/// same-position outer dispatch (e.g. a `(` that aliased `,` would
/// silently promote a list-open byte through the quote-family arm, or
/// vice versa). Post-lift the disjointness of the substrate's pinned
/// arm-set pairs binds at rustc time via one `const _` line per pair.
///
/// The invariant is ALSO load-bearing for the Str-payload escape-arm
/// dispatch at [`Atom::decode_str_escape`]: the FIVE non-passthrough
/// escape arms partition into the [`Atom::SELF_ESCAPE_TABLE`] (2 rows,
/// pattern-EQUALS-value) and [`Atom::NAMED_ESCAPE_TABLE`] (3 rows,
/// pattern-DISTINCT-from-value) sub-vocabularies whose entries MUST
/// remain disjoint at the CHAR level from every other reader-boundary
/// sub-vocabulary — otherwise a Str-escape byte would silently
/// promote through the outer-dispatch cascade instead of staying inside
/// the Str-payload boundary.
///
/// Pre-lift the substrate carried these disjointness relations at ONE
/// runtime test per pair (`sexp_comment_delimiters_disjoint_from_list_delimiters`,
/// `sexp_list_delimiters_disjoint_from_comment_lead`, etc.); post-lift
/// the ARRAY-LEVEL disjointness binds at rustc time via one `const _`
/// line per pair. A regression that silently drifted `Sexp::LIST_OPEN`
/// to `';'` (colliding with `Sexp::COMMENT_LEAD`), or drifted
/// `QuoteForm::QUOTE_LEAD` to `'('` (colliding with `Sexp::LIST_OPEN`),
/// fails at `cargo check` BEFORE any test scheduler runs.
///
/// Adding a new family-wide `[char; N]` sub-vocabulary whose distinct-
/// values set must remain disjoint from another substrate `[char; M]`
/// array's distinct-values set: pair the declaration with `const _: ()
/// = assert_char_arrays_disjoint::<N, M>(&Self::FOO_ARRAY,
/// &Other::BAR_ARRAY);` co-located after the array's declaration and
/// the DISJOINTNESS contract binds at compile time. The rustc-forced
/// arities `[char; N]` and `[char; M]` compose with this const-eval
/// sweep so BOTH cardinality-pair AND cross-array disjointness are
/// compile-time theorems on the SAME (a, b) char-array pair.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_char_arrays_disjoint_panics_at_runtime_on_collision` and
/// `assert_char_arrays_disjoint_panic_message_names_the_helper_and_char_disjointness_violation_axis`.
/// The panic site carries the `"CHAR-DISJOINTNESS-VIOLATION"` axis-
/// provenance string chosen DISTINCT from every sibling helper's axis
/// vocabulary (`"duplicate"` on the ARRAY-side pairwise-distinct
/// sibling; `"CHAR-SUBSET-VIOLATION"` on the (char) SUBSET-embedding
/// sibling; `"SUBSET-VIOLATION"` on the (u8) finite-set SUBSET-only
/// sibling; `"RANGE-SUBSET-VIOLATION"` on the (u8) range SUBSET-only
/// sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the (u8) covers-
/// finite-set sibling; `"OUT-OF-RANGE"` / `"MISSING"` on the (u8)
/// covers-inclusive-range sibling; `"ARITY-MISMATCH"` on both (u8)
/// `_permutes_*` compound helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on
/// the (u8) SET-side well-formedness sibling) so a diagnostic that
/// names the failed axis routes UNAMBIGUOUSLY to THIS specific
/// disjointness helper. The `"CHAR-"` prefix disambiguates from a
/// future-lift (u8) disjointness sibling; the `"-VIOLATION"` suffix
/// lets callers grep either DISJOINTNESS or SUBSET-embedding sibling
/// by `"VIOLATION"` alone or route to the specific contract-shape by
/// the axis stem (`"DISJOINTNESS"` vs `"SUBSET"`).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide cross-array
/// disjointness contract on the reader-boundary `char` vocabulary
/// becomes a TYPE-LEVEL theorem the substrate carries per (a, b)
/// char-array pair rather than a runtime test the developer must
/// remember to write per pair.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the DISJOINTNESS corner on the (char)
/// row at ONE peer const-fn helper rather than at a per-pair runtime
/// iterator sweep. The (subset, disjointness) 2-corner face on the
/// (char) row is now closed at TWO peer const-fn helpers —
/// [`assert_char_array_within_char_finite_set`] on the SUBSET corner
/// and this helper on the DISJOINTNESS corner.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// cross-array membership sweep IS the generative shape. Every new
/// closed-set `char` sub-vocabulary array whose distinct-values set
/// is an intentionally-disjoint peer of another substrate `char`
/// array adds ONE `const _` line to get the disjointness theorem
/// rather than re-deriving a per-pair runtime iterator sweep at
/// each call site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// DISJOINTNESS proof at declaration site AND the reader outer-
/// dispatch cascade's arm-set partition contract regenerate through
/// the SAME `const _` witnesses at the ARRAY level.
///
/// Frontier inspiration: Lean 4's `Finset.Disjoint : Finset α →
/// Finset α → Prop` as a decidable relation on `Finset α` combined
/// with `Finset.disjoint_iff` unfolding the relation to negated
/// per-element membership — the substrate primitive here embeds the
/// same disjointness relation as a rustc const-eval-time proof
/// obligation at every `assert_char_arrays_disjoint` call site rather
/// than as a Lean tactic invocation deferred to `elab_command`. The
/// symmetric nested sweep mirrors Lean's `Finset.disjoint_iff_ne`
/// characterisation `∀ a ∈ s, ∀ b ∈ t, a ≠ b` at the concrete
/// two-array `[char; N] × [char; M]` monomorphic realisation.
pub const fn assert_char_arrays_disjoint<const N: usize, const M: usize>(
a: &[char; N],
b: &[char; M],
) {
let mut i = 0;
while i < N {
let mut j = 0;
while j < M {
if a[i] as u32 == b[j] as u32 {
panic!(
"assert_char_arrays_disjoint: CHAR-DISJOINTNESS-\
VIOLATION — the two family-wide char arrays `a` \
and `b` share an entry at some (i, j) position \
pair. The substrate's CROSS-ARRAY DISJOINTNESS \
contract on the pair is broken; every consumer \
that partitions the two arrays' distinct-values \
sets into disjoint sub-vocabularies of the reader-\
boundary char algebra (the reader outer-dispatch \
cascade's SIX category-leading char arm-set \
partition through `Sexp::LIST_DELIMITERS`, \
`QuoteForm::LEADS`, `Sexp::COMMENT_DELIMITERS`, \
`Atom::STR_DELIMITER`; the Str-payload escape-arm \
dispatch cascade through `Atom::SELF_ESCAPE_TABLE`, \
`Atom::NAMED_ESCAPE_TABLE`; any future typed-\
disjointness pair on the substrate's reader-\
boundary char algebras) relies on the two arrays' \
distinct-values sets NOT sharing a byte. Fix at \
WHICHEVER ARRAY-DECLARATION site drifted (the \
symmetric disjointness relation carries no built-\
in axis-provenance role split between `a` and `b`) \
by dropping the offending entry from one array OR \
re-shaping the partition to route the shared \
entry to a single sub-vocabulary"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time DISJOINTNESS witnesses — the FIVE substrate-pinned
// (a, b) `[char; N] × [char; M]` pairs whose distinct-values sets are
// intentionally-closed disjoint sub-vocabularies of the reader-boundary
// char algebra. Pre-lift the five disjointness relations lived only as
// runtime tests (`sexp_comment_delimiters_disjoint_from_list_delimiters`
// on pair 1; `sexp_list_delimiters_disjoint_from_comment_lead` +
// `sexp_list_delimiters_disjoint_from_str_delimiter` +
// `sexp_comment_delimiters_disjoint_from_str_delimiter` as scalar-vs-
// array runtime pins peer to pairs 1–5; the implicit disjointness
// arms of `NON_WHITESPACE_BARE_ATOM_TERMINATORS`'s four-category
// composition rule between LIST_DELIMITERS + LEADS + {STR_DELIMITER,
// COMMENT_LEAD}); post-lift the ARRAY-LEVEL disjointness of the six
// pinned pairs binds at rustc time via one `const _` line per pair.
// A regression that silently drifted one of the eight arm-set-leading
// chars into another arm (e.g. `Sexp::LIST_OPEN` to `';'`, colliding
// with `Sexp::COMMENT_LEAD`; `QuoteForm::QUOTE_LEAD` to `'('`,
// colliding with `Sexp::LIST_OPEN`; `Atom::STR_DELIMITER` to `';'`,
// colliding with `Sexp::COMMENT_LEAD`; `Atom::STR_ESCAPE_LEAD` to
// `'\n'`, colliding with `Sexp::COMMENT_TERM`) fails at `cargo check`
// BEFORE any test scheduler runs. Sibling to the pairwise-distinctness
// witnesses above — those pin INJECTIVITY on each individual array,
// these pin DISJOINTNESS across PAIRS of arrays.
//
// The six pinned pairs jointly close the C(4, 2) = 6 pairwise-
// disjoint face on the four-array reader-boundary set
// `{Sexp::LIST_DELIMITERS, Sexp::COMMENT_DELIMITERS, QuoteForm::LEADS,
// Atom::SELF_ESCAPE_TABLE}` EXHAUSTIVELY — the same closure shape as
// the three-way `SexpShape::LABELS` partition proof in `error.rs`
// (which pins C(3, 2) = 3 pairs on the `AtomKind::LABELS`,
// `QuoteForm::LABELS`, `StructuralKind::LABELS` sub-vocabulary triple)
// scaled up to the four-array reader-boundary partition. Composed
// with the six ARRAY-side pairwise-distinctness `const _:` witnesses
// above, the substrate carries a full DISJOINT-UNION theorem on the
// reader-boundary partition
// `LIST_DELIMITERS ⊕ COMMENT_DELIMITERS ⊕ QuoteForm::LEADS ⊕
// Atom::SELF_ESCAPE_TABLE`
// (with cardinality 2 + 2 + 3 + 2 = 9) as a rustc-time proof
// obligation, closing the eight-arm reader-boundary vocabulary
// partition at compile time.
const _: () =
assert_char_arrays_disjoint::<2, 2>(&Sexp::LIST_DELIMITERS, &Sexp::COMMENT_DELIMITERS);
const _: () = assert_char_arrays_disjoint::<2, 3>(&Sexp::LIST_DELIMITERS, &QuoteForm::LEADS);
const _: () = assert_char_arrays_disjoint::<2, 3>(&Sexp::COMMENT_DELIMITERS, &QuoteForm::LEADS);
const _: () = assert_char_arrays_disjoint::<2, 2>(&Sexp::LIST_DELIMITERS, &Atom::SELF_ESCAPE_TABLE);
const _: () = assert_char_arrays_disjoint::<3, 2>(&QuoteForm::LEADS, &Atom::SELF_ESCAPE_TABLE);
// The sixth (Sexp::COMMENT_DELIMITERS × Atom::SELF_ESCAPE_TABLE) pair
// pins that the comment-boundary vocabulary `{COMMENT_LEAD (`;`),
// COMMENT_TERM (`\n`)}` and the string self-escape vocabulary
// `{STR_DELIMITER (`"`), STR_ESCAPE_LEAD (`\\`)}` remain byte-
// disjoint. Load-bearing because a regression that renamed
// `Sexp::COMMENT_LEAD` from `';'` to `'"'` would make `'"'` both a
// string opener AND a comment starter (silently swallowing every
// string literal into a comment run at the reader's outer dispatch
// cascade), and a regression that renamed `Atom::STR_ESCAPE_LEAD`
// from `'\\'` to `'\n'` would silently mis-terminate every string
// literal at the first newline (drifting the reader-boundary
// vocabulary into overlap with the comment-boundary vocabulary).
// Closes the sixth (C, S) corner of the C(4, 2) = 6-pair
// pairwise-disjoint face on the four-array reader-boundary set
// EXHAUSTIVELY.
const _: () =
assert_char_arrays_disjoint::<2, 2>(&Sexp::COMMENT_DELIMITERS, &Atom::SELF_ESCAPE_TABLE);
/// Compile-time contract verifier — panics at const evaluation time if
/// the sub-slice `full[START..START + M)` does NOT byte-equal the peer
/// sub-array `sub[..]` positionwise (char-by-char).
///
/// Row-dual peer of [`assert_u8_array_slice_equals_u8_array`] on the
/// (element-type) axis: where the `u8` sibling closes the outer-`Sexp`
/// cache-key discriminator sub-carving vocabulary at compile time, this
/// closes the substrate's reader-boundary `[char; N]` scalar-composed
/// vocabulary at compile time. Opens the SUB-SLICE ARRAY-image column
/// on the (char) row of the (element-type × contract-shape) matrix peer
/// to the u8-row sibling's SUB-SLICE ARRAY-image column — the two
/// helpers together lift EVERY positionwise-composition contract
/// `arr[START..START + M) == sub[..]` on scalar-family-wide substrate
/// arrays into a COMPILE-TIME theorem.
///
/// The FULL-ARRAY corner (`M == N`, `START == 0`) collapses to the
/// pointwise identity `arr == [c_0, c_1, …, c_{N-1}]` binding BOTH
/// (a) the per-position ORDER of the outer array's declaration (the
/// CANONICAL variant-declaration order every reader-outer-dispatch
/// consumer depends on) AND (b) each per-role `pub const *_LEAD` /
/// `*_DELIMITER` / `*_ESCAPE_LEAD` / `*_ESCAPE_SOURCE` /
/// `*_ESCAPE_DECODED` alias's canonical `char` value the outer
/// array's slots re-export. Strictly STRONGER on the (contract-
/// strength) axis than the sibling `_pairwise_distinct` witnesses at
/// [`assert_char_array_pairwise_distinct`]: those bind each array's
/// IMAGE SET via INJECTIVITY but are SILENT on which SLOT each char
/// lands at — a regression that swapped [`Sexp::LIST_OPEN`] (`'('`) and
/// [`Sexp::LIST_CLOSE`] (`')'`) (drifting [`Sexp::LIST_DELIMITERS`]
/// from `['(', ')']` to `[')', '(']`) preserves the pairwise-
/// distinctness witness (both chars still distinct) but silently
/// misaligns every consumer indexing `LIST_DELIMITERS[0]` for the
/// reader-open dispatch. THIS helper binds each slot's LITERAL char
/// value at rustc time.
///
/// Consumer sites this helper closes at the FULL-ARRAY corner:
/// * [`Sexp::LIST_DELIMITERS`] `== ['(', ')']` — the reader-outer-
/// dispatch list-delimiter pair whose ordering matches
/// [`Sexp::LIST_OPEN`] / [`Sexp::LIST_CLOSE`] declaration order.
/// * [`Sexp::COMMENT_DELIMITERS`] `== [';', '\n']` — the outer-`Sexp`
/// comment-boundary pair.
/// * [`Atom::SELF_ESCAPE_TABLE`] `== ['"', '\\']` — the pattern-
/// equals-value sub-vocabulary of the Str-escape closed set.
/// * [`Atom::ESCAPE_SOURCES`] `== ['n', 't', 'r', '"', '\\']` — the
/// FIVE non-passthrough SOURCE-column chars of
/// [`Atom::decode_str_escape`] in canonical declaration order.
/// * [`Atom::ESCAPE_DECODED`] `== ['\n', '\t', '\r', '"', '\\']` —
/// the FIVE column-dual DECODED-column chars.
/// * [`Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS`] `== ['(', ')',
/// '\'', '`', ',', '"', ';']` — the SEVEN category-leading chars
/// the reader's outer-dispatch cascade specialises on, spanning
/// THREE type namespaces ([`Sexp`], [`Atom`], [`QuoteForm`]) in
/// canonical outer-dispatch order.
/// * [`QuoteForm::LEADS`] `== ['\'', '`', ',']` — the three quote-
/// family reader-lead-chars in canonical variant-declaration order.
/// * [`crate::error::UnquoteForm::LEADS`] `== [',']` — the shared-
/// lead-char collapse of the two-of-four substitution subset (both
/// `Unquote` and `UnquoteSplice` share the `,` lead byte and
/// disambiguate on the peek-then-consume `@` second char).
///
/// Pre-lift each identity lived ONLY at the array's DECLARATION site
/// (the per-slot initializer's identifier references resolve at
/// substitution to the LITERAL char values); a regression that
/// renamed [`Sexp::LIST_OPEN`] from `'('` to `'['` (a hypothetical
/// Racket-compat port) would compile silently — the array's slot
/// inherits the drifted char, every consumer indexing into
/// `LIST_DELIMITERS[0]` continues to work with the drifted value, and
/// only test-surface references to the LITERAL char `'('` would
/// catch the drift at test runtime rather than at `cargo check` time.
/// Post-lift the per-slot LITERAL char value binds at rustc time via
/// ONE `const _` witness per array; the drift fails at `cargo check`
/// BEFORE any test scheduler runs. Sibling to the pairwise-
/// distinctness witnesses above [`assert_char_array_pairwise_distinct`]
/// — those pin INJECTIVITY on each array; these pin per-slot ORDER
/// against the CANONICAL literal-char listing.
///
/// The three axis-partitioned panic messages (`START-OUT-OF-BOUNDS`,
/// `SLICE-LENGTH-OUT-OF-BOUNDS`, `CHAR-SLICE-EQUALS-ARRAY-VIOLATION`)
/// mirror the u8 sibling's message vocabulary with the `CHAR-` prefix
/// on the CONTENT-drift axis so callers grep either the (u8) row's
/// plain `SLICE-EQUALS-ARRAY-VIOLATION` or the (char) row's
/// `CHAR-SLICE-EQUALS-ARRAY-VIOLATION` axis-prefix by element-type.
///
/// Adding a new family-wide `[char; N]` array to the substrate whose
/// declaration is a positionwise composition against named per-role
/// `pub const` `char` constants: pair the declaration with `const _:
/// () = assert_char_array_slice_equals_char_array::<N, N, 0>(
/// &Self::FOO_ARRAY, &[literal chars; N]);` co-located after the
/// array's declaration and the per-slot ORDER contract binds at
/// compile time. The rustc-forced arity `[char; N]` composes with
/// this const-eval sweep so BOTH cardinality AND per-slot canonical-
/// char-value are compile-time theorems on the SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// tokenizer that constructs a `[char; N]` at runtime and wants to
/// verify positionwise composition against a peer sub-array before
/// consuming it — and the panic surfaces normally in that path
/// (pinned by
/// `assert_char_array_slice_equals_char_array_panics_at_runtime_on_positionwise_drift`,
/// `assert_char_array_slice_equals_char_array_panics_at_runtime_on_start_out_of_bounds`,
/// `assert_char_array_slice_equals_char_array_panics_at_runtime_on_slice_length_out_of_bounds`,
/// AND
/// `assert_char_array_slice_equals_char_array_panic_message_names_the_helper_and_char_slice_equals_array_violation_axis`).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide per-position
/// ORDER contract on the `char`-typed vocabulary becomes a TYPE-
/// LEVEL theorem the substrate carries per array declaration
/// rather than a runtime iterator sweep the developer must
/// remember to write per array.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// positionwise sweep IS the generative shape. Every new closed-
/// set char array declared as a positionwise composition against
/// named-scalar constants adds ONE `const _` line to get the
/// per-slot ORDER theorem rather than re-deriving a runtime index-
/// by-index `assert_eq!` block per array.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs;
/// the per-slot-ORDER proof at declaration site AND the per-role
/// `pub const` alias-chain composition every consumer relies on
/// regenerate through the SAME `const _` witness.
pub const fn assert_char_array_slice_equals_char_array<
const N: usize,
const M: usize,
const START: usize,
>(
full: &[char; N],
sub: &[char; M],
) {
if START > N {
panic!(
"assert_char_array_slice_equals_char_array: START-OUT-OF-\
BOUNDS — the const parameter `START` sits OUTSIDE the \
outer array's valid position range `[0..N]` (inclusive \
upper bound: `START == N` combined with `M == 0` is the \
LEGAL empty-slice-at-right-endpoint corner). Fix at the \
`const _` witness's turbofish by reconciling `START` \
against the outer array's declared arity `N`. The \
START-OUT-OF-BOUNDS gate fires FIRST — a mistyped \
`START` on the caller side fails HERE before the peer \
`SLICE-LENGTH-OUT-OF-BOUNDS` gate reads `N - START` \
(which would underflow `usize` had this gate not caught \
the slip), so a subtle bounds slip doesn't silently \
degenerate into a subtraction wrap-around OR a panic \
deeper in `full[START + i]` bounds-checking."
);
}
if M > N - START {
panic!(
"assert_char_array_slice_equals_char_array: SLICE-LENGTH-\
OUT-OF-BOUNDS — the peer sub-array's arity `M` exceeds \
the outer array's tail cardinality `N - START`, so the \
positionwise sweep `full[START + i]` for `i ∈ [0..M)` \
would overrun the outer array's valid position range \
`[0..N)` at some `i ∈ [N - START..M)`. Fix at the \
`const _` witness's turbofish by reconciling `M` against \
the outer array's tail cardinality `N - START` OR by \
narrowing `START` to leave a longer tail. The peer \
`START-OUT-OF-BOUNDS` gate above guarantees `START ≤ N` \
so `N - START` never underflows `usize` at this gate. \
The LEGAL exact-fit corner `M == N - START` (the sub-\
array reaches EXACTLY to the outer array's right \
endpoint) is accepted; the STRICT `M > N - START` slip \
is what this gate rejects."
);
}
let mut i = 0;
while i < M {
if full[START + i] as u32 != sub[i] as u32 {
panic!(
"assert_char_array_slice_equals_char_array: CHAR-\
SLICE-EQUALS-ARRAY-VIOLATION — the outer `[char; N]` \
array `full` carries a `char` at some position \
`START + i` (for `i ∈ [0..M)`) that does NOT byte-\
equal the peer `[char; M]` sub-array `sub` at the \
offset-matched position `i`. The substrate's SLICE-\
EQUALS-ARRAY positionwise-composition contract on the \
sub-slice `full[START..START + M) == sub[..]` is \
broken; every consumer that reads `full[START..START \
+ M)` as a positionwise-aligned copy of a peer literal-\
char listing (the reader-outer-dispatch pair \
`Sexp::LIST_DELIMITERS == [Sexp::LIST_OPEN, \
Sexp::LIST_CLOSE]` at `[0..2)`; the comment-boundary \
pair `Sexp::COMMENT_DELIMITERS == [Sexp::COMMENT_LEAD, \
Sexp::COMMENT_TERM]` at `[0..2)`; the escape-self \
pair `Atom::SELF_ESCAPE_TABLE == [Atom::STR_DELIMITER, \
Atom::STR_ESCAPE_LEAD]` at `[0..2)`; the escape-\
source column `Atom::ESCAPE_SOURCES == [n, t, r, \", \
\\]` at `[0..5)`; the escape-decoded column \
`Atom::ESCAPE_DECODED == [\\n, \\t, \\r, \", \\]` at \
`[0..5)`; the reader-boundary category-leading \
seven-char SPAN `Sexp::NON_WHITESPACE_BARE_ATOM_\
TERMINATORS` at `[0..7)`; the quote-family lead-char \
triple `QuoteForm::LEADS == [QuoteForm::QUOTE_LEAD, \
QuoteForm::QUASIQUOTE_LEAD, QuoteForm::UNQUOTE_LEAD]` \
at `[0..3)`; the substitution-subset singleton \
`UnquoteForm::LEADS == [UnquoteForm::UNQUOTE_LEAD]` \
at `[0..1)`; any future family-wide `[char; N]` sub-\
slice byte-for-byte equal to a peer literal-char \
listing) relies on this invariant. Fix at the ARRAY-\
DECLARATION site (the drifted `full[START + i]` slot \
inside the slice segment) OR at the peer per-role \
`pub const *_LEAD` / `*_DELIMITER` / `*_ESCAPE_LEAD` \
/ `*_ESCAPE_SOURCE` / `*_ESCAPE_DECODED` alias's \
declaration — the choice depends on whether the \
drift is an unintended slot reorder in the outer \
array's initializer OR in the per-role alias's \
canonical `char` value."
);
}
i += 1;
}
}
// Compile-time FULL-ARRAY per-position ORDER pins — one `const _: () =
// assert_char_array_slice_equals_char_array::<N, N, 0>(&…, &[literal
// chars; N])` per family-wide `[char; N]` scalar-composed substrate
// array on the reader-boundary closed-set outer algebras. Each
// invocation exercises the [`assert_char_array_slice_equals_char_array`]
// helper at its FULL-ARRAY corner (`M == N`, `START == 0`) — the
// SLICE-EQUALS-ARRAY sweep collapses to the ALL-positions-equal-peer-
// array pointwise identity `arr == [c_0, c_1, …, c_{N-1}]`. The peer
// literal-char sub-array on the RHS pins BOTH (a) the per-position
// ORDER of the outer array's declaration (the CANONICAL variant-
// declaration order every reader-outer-dispatch consumer depends on)
// AND (b) each per-role `pub const *_LEAD` / `*_DELIMITER` /
// `*_ESCAPE_LEAD` / `*_ESCAPE_SOURCE` / `*_ESCAPE_DECODED` alias's
// canonical `char` value the outer array's slots re-export. Strictly
// STRONGER on the (contract-strength) axis than the sibling
// `_pairwise_distinct` witnesses at lines 116..=122 above: those bind
// each array's IMAGE SET via INJECTIVITY but are SILENT on which SLOT
// each char lands at — a regression that swapped `Sexp::LIST_OPEN`
// (`'('`) and `Sexp::LIST_CLOSE` (`')'`) (drifting
// `Sexp::LIST_DELIMITERS` from `['(', ')']` to `[')', '(']`) preserves
// the pairwise-distinctness witness (both chars still distinct) but
// silently misaligns every consumer indexing `LIST_DELIMITERS[0]` for
// the reader-open dispatch. Post-lift the ARRAY-LEVEL per-position
// order binds at rustc time via ONE `const _` witness per array; a
// drift at either the per-role `pub const` char OR the array
// declaration's ordering fails at `cargo check` BEFORE any test
// scheduler runs.
//
// Sibling posture to the FOUR-witness EXHAUSTIVE per-position sweep on
// the FOUR sub-carving `[u8; N]` `HASH_DISCRIMINATORS` arrays in the
// (u8) row's FULL-ARRAY per-position ORDER cluster below in this file.
// Those four witnesses close the FOUR sub-carving arrays against their
// LITERAL byte listing at the (u8) row's FULL-ARRAY corner; these
// EIGHT witnesses close the EIGHT reader-boundary scalar-composed
// arrays against their LITERAL char listing at the (char) row's FULL-
// ARRAY corner. Together the twelve witnesses close the (element-
// type × contract-shape) matrix's FULL-ARRAY per-position ORDER
// column across BOTH the (u8) row (outer-`Sexp` cache-key
// discriminator vocabulary) AND the (char) row (reader-boundary char
// vocabulary) EXHAUSTIVELY at rustc time.
//
// The eight pinned arrays appear here in canonical (owning-algebra,
// per-role-alias-count-ascending) order:
// * `Sexp::LIST_DELIMITERS == ['(', ')']` — outer-`Sexp` list pair.
// * `Sexp::COMMENT_DELIMITERS == [';', '\n']` — outer-`Sexp` comment
// boundary pair.
// * `Atom::SELF_ESCAPE_TABLE == ['"', '\\']` — `Atom` escape-self
// pair (pattern-equals-value sub-vocabulary of the Str-escape
// closed set).
// * `Atom::ESCAPE_SOURCES == ['n', 't', 'r', '"', '\\']` — `Atom`
// escape-source column (non-passthrough SOURCE-column chars).
// * `Atom::ESCAPE_DECODED == ['\n', '\t', '\r', '"', '\\']` —
// `Atom` escape-decoded column (column-dual DECODED-column chars).
// * `Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS == ['(', ')', '\'',
// '`', ',', '"', ';']` — outer-`Sexp` reader-boundary category-
// leading seven-char SPAN across THREE type namespaces ([`Sexp`],
// [`QuoteForm`], [`Atom`]).
// * `QuoteForm::LEADS == ['\'', '`', ',']` — quote-family reader-
// lead-char triple.
// * `UnquoteForm::LEADS == [',']` — substitution-subset shared-lead
// singleton (both `Unquote` and `UnquoteSplice` share the `,`
// lead byte and disambiguate on the peek-then-consume `@` second
// char).
const _: () =
assert_char_array_slice_equals_char_array::<2, 2, 0>(&Sexp::LIST_DELIMITERS, &['(', ')']);
const _: () =
assert_char_array_slice_equals_char_array::<2, 2, 0>(&Sexp::COMMENT_DELIMITERS, &[';', '\n']);
const _: () =
assert_char_array_slice_equals_char_array::<2, 2, 0>(&Atom::SELF_ESCAPE_TABLE, &['"', '\\']);
const _: () = assert_char_array_slice_equals_char_array::<5, 5, 0>(
&Atom::ESCAPE_SOURCES,
&['n', 't', 'r', '"', '\\'],
);
const _: () = assert_char_array_slice_equals_char_array::<5, 5, 0>(
&Atom::ESCAPE_DECODED,
&['\n', '\t', '\r', '"', '\\'],
);
const _: () = assert_char_array_slice_equals_char_array::<7, 7, 0>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&['(', ')', '\'', '`', ',', '"', ';'],
);
const _: () =
assert_char_array_slice_equals_char_array::<3, 3, 0>(&QuoteForm::LEADS, &['\'', '`', ',']);
const _: () =
assert_char_array_slice_equals_char_array::<1, 1, 0>(&crate::error::UnquoteForm::LEADS, &[',']);
// Compile-time SUB-CARVING per-position ARRAY-LEVEL POSITIONAL-
// COMPOSITION witnesses on `Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS`
// (`[char; 7]`) — the outer-`Sexp` reader-boundary category-leading
// seven-char SPAN whose declaration order composes across THREE type
// namespaces (`Sexp`, `QuoteForm`, `Atom`) as the segmented
// concatenation
//
// NON_WHITESPACE_BARE_ATOM_TERMINATORS
// == Sexp::LIST_DELIMITERS // slots [0..2)
// ++ QuoteForm::LEADS // slots [2..5)
// ++ [Atom::STR_DELIMITER] // slot [5..6)
// ++ [Sexp::COMMENT_LEAD] // slot [6..7)
//
// Each of the FOUR right-hand-side segments names an INDEPENDENT
// substrate primitive on ONE of the three sub-algebras — the OUTER
// terminator SPAN is the composition surface where the FOUR sub-
// vocabularies land at their canonical reader-outer-dispatch slots. The
// pre-existing FULL-ARRAY LITERAL-listing witness IMMEDIATELY ABOVE
// (`assert_char_array_slice_equals_char_array::<7, 7, 0>(&…, &['(', ')',
// '\'', '`', ',', '"', ';'])`) binds the SPAN against a HARDCODED
// `[char; 7]` peer literal — it catches drifts of the PER-ROLE `pub
// const` chars each sub-carving array's slot re-exports through the
// underlying `Sexp::LIST_OPEN` / `Sexp::LIST_CLOSE` / `QuoteForm::
// QUOTE_LEAD` / … / `Sexp::COMMENT_LEAD` primitives, but is SILENT on
// the ARRAY-LEVEL structural composition axis — a regression that
// reorders `Sexp::LIST_DELIMITERS` from `[LIST_OPEN, LIST_CLOSE]` to
// `[LIST_CLOSE, LIST_OPEN]` (or `QuoteForm::LEADS` from `[QUOTE_LEAD,
// QUASIQUOTE_LEAD, UNQUOTE_LEAD]` to any other permutation of the same
// three chars) while leaving `NON_WHITESPACE_BARE_ATOM_TERMINATORS` in
// its canonical initializer form silently misaligns every consumer that
// treats the composite's HEAD-2-slice as positionally-interchangeable
// with `Sexp::LIST_DELIMITERS` (or the MIDDLE-3-slice with
// `QuoteForm::LEADS`) — the OUTER LITERAL witness accepts both
// sub-carving reorders because the LITERAL peer array's slot-0 (`'('`)
// and slot-1 (`')'`) still match `NON_WHITESPACE_BARE_ATOM_TERMINATORS`
// even though the sub-carving's declaration slot-0 and slot-1 drifted.
// The pre-existing SET-level SUBSET witnesses at lines 369..=380 above
// (`assert_char_array_within_char_finite_set::<{2,3}, 7>(&{LIST_
// DELIMITERS, QuoteForm::LEADS}, &NON_WHITESPACE_BARE_ATOM_TERMINATORS)`)
// bind the sub-carvings' distinct-value SET is CONTAINED in the
// composite's distinct-value SET but are silent on positional alignment
// — the SAME sub-carving reorders survive those witnesses because
// distinct-value SET membership is order-invariant.
//
// These FOUR new `const _` witnesses close the missing corner: each
// binds a SUB-CARVING array positionwise-equal to its canonical SLOT
// SEGMENT of the composite terminator SPAN via
// [`assert_char_array_slice_equals_char_array`] at the SUB-SLICE ARRAY-
// image corner (`START ∈ {0, 2, 5, 6}`, `M ∈ {2, 3, 1, 1}`,
// `M < N == 7`). Post-lift a drift at ANY of the sub-carvings'
// declaration ordering (or at the composite's slot ordering) fails
// AT rustc time BEFORE the pre-existing FULL-ARRAY LITERAL witness re-
// verifies the composite's literal identity — the two witness families
// bind the composite through DISTINCT drift-detection axes (LITERAL
// against inline chars, POSITIONAL against sub-carving arrays) that
// TOGETHER catch every ARRAY-LEVEL misalignment the pre-lift
// (INJECTIVITY + SUBSET-EMBEDDING) 2-corner face silently accepted.
//
// Sibling posture to the FOUR-witness EXHAUSTIVE per-position sub-
// carving composition sweep on the OUTER `SexpShape::HASH_DISCRIMINATORS`
// container (the trio of `assert_u8_array_slice_equals_u8_array::<12,
// {1, 4}, {0, 7, 8}>` witnesses + the `assert_u8_array_slice_is_scalar_
// replica::<12, 1, 7>` witness below in this file). Those FOUR
// witnesses pin the (u8) row's twelve-slot outer container against its
// FOUR sub-carvings at rustc time; THESE FOUR witnesses pin the (char)
// row's seven-slot outer terminator SPAN against its FOUR sub-carvings
// at rustc time. Together the eight witnesses close the (element-type
// × contract-shape) matrix's SUB-CARVING per-position POSITIONAL-
// COMPOSITION corner across BOTH the (u8) row (outer-`Sexp` cache-key
// discriminator hierarchy) AND the (char) row (reader-outer-dispatch
// terminator SPAN) EXHAUSTIVELY at the FOUR-sub-carving-per-container
// depth.
//
// A hypothetical seventh reader-outer-dispatch category (e.g. a
// `#|…|#` block-comment lead byte pinning a fresh `Sexp::BLOCK_COMMENT_
// LEAD` primitive) would extend `NON_WHITESPACE_BARE_ATOM_TERMINATORS`
// to `[char; 8]` AND require a FIFTH witness below binding
// `NON_WHITESPACE_BARE_ATOM_TERMINATORS[7..8) == [Sexp::BLOCK_COMMENT_
// LEAD]` (or, if the new lead byte joins an EXISTING sub-carving like
// `Sexp::COMMENT_LEAD`'s comment axis, a widened `Sexp::COMMENT_LEADS`
// array replaces the singleton at slot `[6..7)` and its widened arity
// propagates through the widened witness's const-generic turbofish).
// Rustc's forced-arity check on `[char; N]` fails compilation if the
// composite's arity grows without the corresponding sub-carving
// widening (or vice versa).
const _: () = assert_char_array_slice_equals_char_array::<7, 2, 0>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&Sexp::LIST_DELIMITERS,
);
const _: () = assert_char_array_slice_equals_char_array::<7, 3, 2>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&QuoteForm::LEADS,
);
const _: () = assert_char_array_slice_equals_char_array::<7, 1, 5>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&[Atom::STR_DELIMITER],
);
const _: () = assert_char_array_slice_equals_char_array::<7, 1, 6>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&[Sexp::COMMENT_LEAD],
);
/// Compile-time contract verifier — panics at const evaluation time if
/// any two entries of `arr` alias byte-for-byte through
/// [`str::as_bytes`].
///
/// Column-dual peer to [`assert_char_array_pairwise_distinct`] on the
/// (element-type) axis: where the `char` sibling closes the reader-
///
/// Column-dual peer to [`assert_char_array_pairwise_distinct`] on the
/// (element-type) axis: where the `char` sibling closes the reader-
/// boundary `[char; N]` vocabulary at compile time, this closes the
/// substrate's family-wide `[&'static str; N]` vocabulary at compile
/// time. The two helpers together lift EVERY `pub const` scalar-
/// family-wide array declared on the substrate's closed-set outer
/// algebras (`Sexp` / `Atom` / `AtomKind` / `QuoteForm`) into a
/// COMPILE-TIME pairwise-distinctness theorem — a regression that
/// silently collides two entries fails the build at `cargo check`
/// time, one invocation stage earlier than the test-run pin.
///
/// The invariant is load-bearing for every consumer that pattern-
/// matches the array's entries as DISJOINT arms —
/// [`Atom::bool_literal`]'s two-arm projection through
/// [`Atom::BOOL_LITERALS`] (a duplicate here would silently shadow
/// the second arm's `#f` spelling at the same-index projection);
/// [`AtomKind::label`]'s six-arm projection through
/// [`AtomKind::LABELS`] (a duplicate here would collapse two
/// distinct atomic-payload variants onto the same diagnostic
/// label, breaking every downstream label-driven partition on
/// the closed-set AtomKind algebra); [`QuoteForm::prefix`]'s
/// four-arm projection over [`QuoteForm::PREFIXES`] (a duplicate
/// here would silently collapse two distinct quote-family
/// variants onto the same reader-prefix `&'static str`);
/// [`QuoteForm::iac_forge_tag`]'s four-arm projection through
/// [`QuoteForm::IAC_FORGE_TAGS`] (a duplicate here would silently
/// collapse two distinct quote-family variants onto the same
/// canonical-form tag, breaking the iac-forge interop round-trip
/// through [`QuoteForm::from_iac_forge_tag`]); AND
/// [`QuoteForm::label`]'s four-arm projection through
/// [`QuoteForm::LABELS`] (a duplicate here would collapse two
/// distinct quote-family variants onto the same diagnostic
/// label). Every future family-wide `[&'static str; N]` on the
/// substrate that participates in a `match`-arm partition or a
/// same-index alias-chain benefits from the SAME compile-time
/// guarantee via one `const _` line.
///
/// Pre-lift each array carried its pairwise-distinctness contract
/// EITHER at a runtime test (`atom_bool_literals_pairwise_distinct`,
/// `atom_kind_labels_pairwise_distinct`, `quote_form_prefixes_
/// pairwise_distinct`, `quote_form_iac_forge_tags_pairwise_distinct`,
/// `quote_form_labels_pairwise_distinct`) OR implicitly through the
/// same-index alias-chain composition law's runtime pin; post-lift
/// the pairwise-distinctness contract binds at `cargo check` time,
/// one invocation stage earlier, catching regressions on `cargo
/// build` / `cargo clippy` runs that skip the test suite.
///
/// Adding a new family-wide `[&'static str; N]` array to the
/// substrate: pair the declaration with `const _: () = assert_str_
/// array_pairwise_distinct(&Self::FOO_ARRAY);` co-located immediately
/// after the array's declaration and the distinctness contract is
/// enforced at compile time. The rustc-forced arity `[&'static str;
/// N]` composes with this const-eval sweep so BOTH cardinality AND
/// injectivity are compile-time theorems on the SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// autocomplete surface that constructs a `[&'static str; N]` at
/// runtime from a user-supplied vocabulary AND wants to verify
/// pairwise distinctness before consuming it — and the panic
/// surfaces normally in that path (pinned by
/// `assert_str_array_pairwise_distinct_panics_at_runtime_on_binary_
/// collision`).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide
/// distinctness contract on the `&'static str`-typed vocabulary
/// becomes a TYPE-LEVEL theorem the substrate carries per array
/// declaration rather than a runtime test the developer must
/// remember to write per array.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// sweep IS the generative shape. Every new closed-set string
/// array adds ONE `const _` line to get the distinctness theorem
/// rather than re-deriving a per-array runtime iterator sweep.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs;
/// the distinctness proof at declaration site AND the same-index
/// alias-chain composition the consumer relies on regenerate
/// through the SAME `const _` witness.
pub const fn assert_str_array_pairwise_distinct<const N: usize>(arr: &[&'static str; N]) {
let mut i = 0;
while i < N {
let mut j = i + 1;
while j < N {
if str_bytes_equal(arr[i], arr[j]) {
panic!(
"assert_str_array_pairwise_distinct: family-wide \
&'static str array carries a duplicate entry \
across two positions — the substrate's pairwise-\
distinctness contract on the array is broken; \
every consumer that pattern-matches the array's \
entries as DISJOINT arms (bool-literal dispatch, \
atomic-kind label decode, quote-family prefix \
decode, iac-forge tag decode, quote-family label \
projection) relies on this invariant"
);
}
j += 1;
}
i += 1;
}
}
/// Const-fn byte-equality helper for `assert_str_array_pairwise_
/// distinct` — compares two `&'static str`s byte-for-byte through
/// their [`str::as_bytes`] projections. Lifted as a co-located
/// module-private helper rather than an inline sweep so the outer
/// helper's triangular `(i, j)` pair-walk mirrors the shape of
/// [`assert_char_array_pairwise_distinct`] at the outer method
/// axis without an inline byte-loop obscuring the `(i, j)` sweep.
///
/// The equality relation this helper computes is EXACTLY
/// [`str::eq`] (i.e. byte-for-byte length + content equality on
/// the underlying UTF-8 bytes), just re-derived in a const-eval
/// friendly shape since `str::eq` / `<[u8]>::eq` are not (yet)
/// callable from `const fn` context on the substrate's toolchain.
/// A future toolchain that stabilises `const fn str::eq` collapses
/// this helper to a one-line `str::eq(a, b)` delegation.
const fn str_bytes_equal(a: &str, b: &str) -> bool {
let a = a.as_bytes();
let b = b.as_bytes();
if a.len() != b.len() {
return false;
}
let mut k = 0;
while k < a.len() {
if a[k] != b[k] {
return false;
}
k += 1;
}
true
}
// Compile-time pairwise-distinctness witnesses — one `const _: () =
// assert_str_array_pairwise_distinct(&…)` per family-wide `[&'static
// str; N]` array on the substrate's closed-set outer algebras. Each
// invocation is const-evaluated at `cargo check` time; a regression
// that silently collides two entries fails the build rather than the
// test suite. Sibling to the runtime `_pairwise_distinct` tests at
// `ast.rs`'s tests module — the two enforce the same theorem at TWO
// stages of the toolchain, so a build that skips tests still catches
// the regression here, and a build that runs tests catches it a
// second time as a safety net if the const-eval sweep is ever
// silently dropped. Peer to the seven `assert_char_array_pairwise_
// distinct` witnesses above on the (element-type) axis: `char` covers
// the reader-boundary vocabulary; `&'static str` covers the closed-
// set outer-algebras' family-wide label / prefix / tag / literal
// vocabularies.
const _: () = assert_str_array_pairwise_distinct(&Atom::BOOL_LITERALS);
const _: () = assert_str_array_pairwise_distinct(&AtomKind::LABELS);
const _: () = assert_str_array_pairwise_distinct(&QuoteForm::PREFIXES);
const _: () = assert_str_array_pairwise_distinct(&QuoteForm::IAC_FORGE_TAGS);
const _: () = assert_str_array_pairwise_distinct(&QuoteForm::LABELS);
// Compile-time FULL-ARRAY per-position ORDER pins — one `const _: () =
// assert_str_array_slice_equals_str_array::<N, N, 0>(&…, &[literal strs;
// N])` per family-wide `[&'static str; N]` scalar-composed substrate
// array on the closed-set outer-algebras' label / prefix / tag / literal
// vocabularies. Each invocation exercises the
// [`assert_str_array_slice_equals_str_array`] helper at its FULL-ARRAY
// corner (`M == N`, `START == 0`) — the SLICE-EQUALS-ARRAY sweep
// collapses to the ALL-positions-equal-peer-array pointwise identity
// `arr == [s_0, s_1, …, s_{N-1}]`. The peer literal-str sub-array on
// the RHS pins BOTH (a) the per-position ORDER of the outer array's
// declaration (the CANONICAL variant-declaration order every
// closed-set outer-algebra consumer depends on) AND (b) each per-role
// `pub const *_LABEL` / `*_PREFIX` / `*_TAG` / `TRUE_LITERAL` /
// `FALSE_LITERAL` alias's canonical `&'static str` value the outer
// array's slots re-export. Strictly STRONGER on the (contract-strength)
// axis than the sibling `_pairwise_distinct` witnesses at lines
// 1173..=1177 above: those bind each array's IMAGE SET via INJECTIVITY
// but are SILENT on which SLOT each str lands at — a regression that
// swapped `Atom::TRUE_LITERAL` (`"#t"`) and `Atom::FALSE_LITERAL`
// (`"#f"`) (drifting `Atom::BOOL_LITERALS` from `["#t", "#f"]` to
// `["#f", "#t"]`) preserves the pairwise-distinctness witness (both
// strs still distinct) but silently misaligns every consumer indexing
// `BOOL_LITERALS[0]` for the canonical `true`-lexeme dispatch. A
// silent value-drift of a per-role scalar (e.g. an ELisp-compat
// rename of `AtomKind::SYMBOL_LABEL` from `"symbol"` to `"sym"`, a
// Racket-compat rename of `QuoteForm::QUASIQUOTE_LABEL`) that flows
// through the composed array without updating the outer array's
// literal image ALSO fails HERE where the pairwise-distinctness
// witness stays silent. Post-lift the ARRAY-LEVEL per-position order
// binds at rustc time via ONE `const _` witness per array; a drift
// at either the per-role `pub const *_LABEL` / `*_PREFIX` / `*_TAG`
// str OR the array declaration's ordering fails at `cargo check`
// BEFORE any test scheduler runs.
//
// Sibling posture to the EIGHT-witness (char)-row FULL-ARRAY per-
// position ORDER cluster at lines 893..=914 above (the eight
// `assert_char_array_slice_equals_char_array::<N, N, 0>(&…, &[literal
// chars; N])` witnesses on the substrate's `[char; N]` reader-boundary
// vocabulary) and the FOUR-witness (u8)-row FULL-ARRAY per-position
// ORDER cluster below in this file (four
// `assert_u8_array_slice_equals_u8_array::<N, N, 0>(&…, &[literal
// bytes; N])` witnesses on the sub-carving `[u8; N]`
// `HASH_DISCRIMINATORS` arrays). Together the eight (char)-row + four
// (u8)-row + these five (str)-row witnesses close the (element-type
// × contract-shape) matrix's FULL-ARRAY per-position ORDER column
// across ALL THREE scalar element-type rows (char, u8, &'static str)
// EXHAUSTIVELY at rustc time.
//
// The five pinned arrays appear here in canonical (owning-algebra,
// per-role-alias-count-ascending) order:
// * `Atom::BOOL_LITERALS == ["#t", "#f"]` — Scheme-canonical bool-
// lexeme spellings on the `Atom` algebra (two per-role literals).
// * `AtomKind::LABELS == ["symbol", "keyword", "string", "int",
// "float", "bool"]` — atomic-payload diagnostic labels on the
// `AtomKind` subset algebra (six per-role labels).
// * `QuoteForm::PREFIXES == ["'", "`", ",", ",@"]` — quote-family
// reader-punctuation prefix bytes on the `QuoteForm` algebra (four
// per-role prefixes; the fourth `",@"` is the ONLY two-char prefix
// on the closed set — pinned separately by
// `quote_form_unquote_splice_prefix_constant_composes_from_unquote_lead_and_splice_discriminator`).
// * `QuoteForm::LABELS == ["quote", "quasiquote", "unquote",
// "unquote-splice"]` — diagnostic labels on the `QuoteForm` algebra
// (four per-role labels; the fourth `"unquote-splice"` is the
// substrate's SHORTER diagnostic idiom for `LispError::TypeMismatch.got`
// surfaces — INTENTIONALLY DISTINCT from the iac-forge tag's
// Common-Lisp-canonical `"unquote-splicing"` spelling).
// * `QuoteForm::IAC_FORGE_TAGS == ["quote", "quasiquote", "unquote",
// "unquote-splicing"]` — cross-crate canonical-form tags on the
// `QuoteForm` algebra (four per-role tags; the fourth
// `"unquote-splicing"` is Common-Lisp-canonical and distinct from
// `QuoteForm::LABELS[3]`'s shorter `"unquote-splice"` spelling —
// pinned by
// `quote_form_iac_forge_tag_and_label_disagree_only_on_unquote_splice_arm`).
const _: () =
assert_str_array_slice_equals_str_array::<2, 2, 0>(&Atom::BOOL_LITERALS, &["#t", "#f"]);
const _: () = assert_str_array_slice_equals_str_array::<6, 6, 0>(
&AtomKind::LABELS,
&["symbol", "keyword", "string", "int", "float", "bool"],
);
const _: () = assert_str_array_slice_equals_str_array::<4, 4, 0>(
&QuoteForm::PREFIXES,
&["'", "`", ",", ",@"],
);
const _: () = assert_str_array_slice_equals_str_array::<4, 4, 0>(
&QuoteForm::LABELS,
&["quote", "quasiquote", "unquote", "unquote-splice"],
);
const _: () = assert_str_array_slice_equals_str_array::<4, 4, 0>(
&QuoteForm::IAC_FORGE_TAGS,
&["quote", "quasiquote", "unquote", "unquote-splicing"],
);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `arr` has zero length under [`str::len`] (equivalently
/// `str::is_empty`).
///
/// Contract-orthogonal peer to [`assert_str_array_pairwise_distinct`]
/// on the (contract-shape) column of the (`&'static str`) row of the
/// (element-type × contract-shape) matrix: where the pairwise-
/// distinctness sibling binds INTRA-array `∀ i ≠ j : arr[i] ≠ arr[j]`
/// (INJECTIVITY on the multiset of entries), this NONEMPTY-CARDINALITY-
/// LOWER-BOUND sibling binds the strictly-weaker per-entry cardinality
/// gate `∀ i : arr[i].len() > 0` (NO ENTRY is the zero-length byte
/// sequence). The two contracts compose orthogonally: an array that
/// carries `["", ""]` fails the pairwise-distinctness contract at the
/// zero-length-pair corner (pinned by
/// `assert_str_array_pairwise_distinct_rejects_length_zero_collision`),
/// but an array that carries `["", "a"]` passes pairwise-distinctness
/// while failing NONEMPTY — so the NONEMPTY sibling closes the
/// remaining `""`-carrying corner that INJECTIVITY alone cannot pin.
/// The inner test is a direct [`str::is_empty`] delegation — const-
/// stable since Rust 1.39 and const-callable on the substrate's
/// toolchain — so no `str_bytes_equal`-shaped auxiliary helper is
/// needed for this contract (the peer `_pairwise_distinct` sibling
/// uses `str_bytes_equal` because it must compare TWO strings byte-
/// for-byte while `const fn str::eq` remains unstable; this sibling
/// only tests ONE string's length so it delegates directly).
///
/// The invariant is load-bearing for every consumer that spells a
/// closed-set variant through its `&'static str` label — every
/// [`AtomKind::label`] / [`QuoteForm::label`] / `parse_label` /
/// `find_by_label` composition on the ClosedSet trait's family-wide
/// label vocabularies (`Atom::BOOL_LITERALS` on the bool-literal
/// dispatch; `AtomKind::LABELS` on the atomic-payload kind decode;
/// `QuoteForm::LABELS` on the quote-family diagnostic vocabulary;
/// `QuoteForm::PREFIXES` on the reader-boundary prefix vocabulary;
/// `QuoteForm::IAC_FORGE_TAGS` on the canonical iac-forge tag
/// vocabulary) treats each entry as a NONEMPTY identifier and would
/// silently mis-behave on a `""` entry: `parse_label("")` would decode
/// the empty string to that variant (silently making empty user input a
/// valid variant spelling); `find_by_label("")` would return `Some(v)`
/// rather than `None`; every string-search consumer that scans for a
/// prefix or contains a label as a substring would spuriously match on
/// every input (since `""` is a prefix and a substring of every
/// string). Post-lift a regression that silently re-inlined one label
/// constant to `""` (e.g. `AtomKind::SYMBOL_LABEL = "";`) fails at
/// `cargo check` BEFORE any test scheduler runs.
///
/// Adding a new family-wide `[&'static str; N]` label / prefix / tag /
/// literal vocabulary to the substrate: pair the declaration with
/// `const _: () = assert_str_array_all_nonempty(&Self::FOO_ARRAY);`
/// co-located after the array's declaration and the NONEMPTY-CARDINALITY-
/// LOWER-BOUND contract binds at compile time. The rustc-forced arity
/// `[&'static str; N]` composes with this const-eval sweep so BOTH
/// cardinality AND per-entry nonempty are compile-time theorems on the
/// SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_str_array_all_nonempty_panics_at_runtime_on_head_empty` /
/// `_interior_empty` / `_tail_empty` and
/// `assert_str_array_all_nonempty_panic_message_names_the_helper`. The
/// panic site carries the `"STR-EMPTY-ENTRY"` axis-provenance string
/// chosen DISTINCT from every sibling helper's axis vocabulary
/// (`"duplicate"` on the pairwise-distinct sibling; `"STR-DISJOINTNESS-
/// VIOLATION"` on the arrays-disjoint sibling; `"STR-SUBSET-VIOLATION"`
/// on the within-finite-set sibling) so a diagnostic that names the
/// failed axis routes UNAMBIGUOUSLY to THIS specific NONEMPTY helper.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide nonempty-
/// cardinality-lower-bound contract on the `&'static str` label
/// vocabulary becomes a TYPE-LEVEL theorem the substrate carries per
/// array declaration rather than a runtime test the developer must
/// remember to write per label constant.
/// - THEORY.md §II.1 invariant 1 — typed entry; a closed-set variant's
/// label projection is the entry-point discriminator into the typed
/// algebra, and a `""` entry would silently break the discriminator
/// at the boundary between untyped `&str` input and typed enum
/// variant.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// sweep IS the generative shape. Every new closed-set label array
/// adds ONE `const _` line to get the NONEMPTY theorem rather than
/// re-deriving a per-array runtime iterator sweep at each call site.
pub const fn assert_str_array_all_nonempty<const N: usize>(arr: &[&'static str; N]) {
let mut i = 0;
while i < N {
if arr[i].is_empty() {
panic!(
"assert_str_array_all_nonempty: STR-EMPTY-ENTRY — the \
family-wide &'static str array carries a zero-length \
entry at some position — the substrate's NONEMPTY-\
CARDINALITY-LOWER-BOUND contract on the array is \
broken; every consumer that spells a closed-set variant \
through its `&'static str` label (AtomKind / QuoteForm \
/ UnquoteForm / StructuralKind / SexpShape label \
projections; the reader-boundary prefix / tag \
vocabularies; the bool-literal dispatch) treats each \
entry as a NONEMPTY identifier — `parse_label(\"\")` \
would silently decode the empty string to the offending \
variant, `find_by_label(\"\")` would return `Some(v)` \
rather than `None`, every substring / prefix scan would \
spuriously match on every input. Fix at the ARRAY-\
DECLARATION site by removing the `\"\"` entry OR by \
giving it a nonempty canonical spelling"
);
}
i += 1;
}
}
// Compile-time NONEMPTY-CARDINALITY-LOWER-BOUND witnesses — one
// `const _: () = assert_str_array_all_nonempty(&…)` per family-wide
// `[&'static str; N]` array on the substrate's closed-set outer
// algebras. Each invocation is const-evaluated at `cargo check` time; a
// regression that silently re-inlined one label constant to `""` fails
// the build rather than deferring to a per-consumer misbehavior at
// runtime. Sibling to the pairwise-distinctness witnesses above — those
// pin INJECTIVITY on each array, these pin the strictly-weaker per-
// entry cardinality gate on the SAME arrays. The two contracts compose
// orthogonally on every closed-set outer algebra's label vocabulary.
// The five arrays covered here mirror the five arrays already pinned
// by the `_pairwise_distinct` witnesses above (`Atom::BOOL_LITERALS`,
// `AtomKind::LABELS`, `QuoteForm::PREFIXES`, `QuoteForm::IAC_FORGE_TAGS`,
// `QuoteForm::LABELS`) — the (array × contract-shape) coverage matrix
// on the (`&'static str`) row of this file now holds at every
// (INJECTIVITY, NONEMPTY) corner for the five outer-algebra arrays
// declared here. Analogous witnesses on the (`&'static str`) arrays
// declared under `crate::error` (`CompilerSpecIoStage::LABELS`,
// `MacroDefHead::KEYWORDS`, `MacroParams::LAMBDA_LIST_KEYWORDS`,
// `UnquoteForm::MARKERS` / `IAC_FORGE_TAGS` / `LABELS`,
// `KwargPathKind::LABELS`, `ExpectedKwargShape::LABELS`,
// `SexpShape::LABELS`, `StructuralKind::LABELS`) land co-located with
// the pre-existing `_pairwise_distinct` witnesses at that file's
// module-level prelude.
const _: () = assert_str_array_all_nonempty(&Atom::BOOL_LITERALS);
const _: () = assert_str_array_all_nonempty(&AtomKind::LABELS);
const _: () = assert_str_array_all_nonempty(&QuoteForm::PREFIXES);
const _: () = assert_str_array_all_nonempty(&QuoteForm::IAC_FORGE_TAGS);
const _: () = assert_str_array_all_nonempty(&QuoteForm::LABELS);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `arr` carries a byte outside the seven-bit ASCII range
/// (`>= 0x80`, the first byte of any non-ASCII UTF-8 sequence).
///
/// Per-entry peer to [`assert_str_array_all_nonempty`] on the (per-
/// entry × contract-shape) axis of the (`&'static str`) row: where the
/// NONEMPTY sibling pins the length-lower-bound gate (`∀ i :
/// arr[i].len() > 0`), this ASCII sibling pins the byte-range
/// containment gate (`∀ i, ∀ b ∈ arr[i].as_bytes() : b <= 0x7F`). The
/// two contracts compose orthogonally — an array carrying `["café"]`
/// passes NONEMPTY while failing ASCII; an array carrying `["", "a"]`
/// passes ASCII while failing NONEMPTY. Together with the INJECTIVITY
/// sibling ([`assert_str_array_pairwise_distinct`]) the substrate's
/// (per-entry × contract-shape) coverage matrix on the (`&'static
/// str`) row closes at THREE corners: {NONEMPTY, ASCII, INJECTIVITY}
/// on the SAME five outer-algebra arrays declared here.
///
/// The invariant is load-bearing for every consumer that ships an
/// array entry through a downstream surface whose canonical form is
/// seven-bit-clean — Kubernetes annotation keys + label values (RFC
/// 1123 subset of ASCII); YAML flow-scalar map keys the reader-boundary
/// prefix vocabulary threads through the four-Lisp projection; BLAKE3
/// hash inputs on the three-pillar attestation chain (identical byte
/// sequences hash identically regardless of encoding, but authoring a
/// non-ASCII label silently invites U+FEFF BOMs and Unicode-normalization
/// drift on the wire); Rust `matches!(s, "quote" | …)` byte-pattern
/// arms the compiler lowers to `[u8]` comparison. Post-lift a
/// regression that silently re-inlined one label constant to a byte-
/// equivalent non-ASCII spelling (e.g. `AtomKind::SYMBOL_LABEL =
/// "sýmbol";`, a lookalike that would parse as a Rust `&'static str`
/// but ship non-ASCII bytes at every consumer) fails at `cargo check`
/// BEFORE any test scheduler runs.
///
/// Adding a new family-wide `[&'static str; N]` label / prefix / tag /
/// literal vocabulary whose canonical spelling is seven-bit-clean:
/// pair the declaration with `const _: () =
/// assert_str_array_all_ascii(&Self::FOO_ARRAY);` co-located after
/// the array's declaration and the ASCII-BYTE-RANGE contract binds at
/// compile time. The rustc-forced arity `[&'static str; N]` composes
/// with this const-eval sweep so BOTH cardinality AND per-entry ASCII
/// are compile-time theorems on the SAME array declaration.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_str_array_all_ascii_panics_at_runtime_on_head_non_ascii` /
/// `_interior_non_ascii` / `_tail_non_ascii` and
/// `assert_str_array_all_ascii_panic_message_names_the_helper_and_axis`.
/// The panic site carries the `"STR-NON-ASCII-ENTRY"` axis-provenance
/// string chosen DISTINCT from every sibling helper's axis vocabulary
/// (`"duplicate"` on the pairwise-distinct sibling; `"STR-EMPTY-
/// ENTRY"` on the per-entry NONEMPTY sibling; `"STR-DISJOINTNESS-
/// VIOLATION"` on the arrays-disjoint sibling; `"STR-SUBSET-
/// VIOLATION"` on the within-finite-set sibling) so a diagnostic that
/// names the failed axis routes UNAMBIGUOUSLY to THIS specific ASCII
/// helper.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide per-entry
/// ASCII-byte-range contract on the substrate's `&'static str`
/// label vocabulary becomes a TYPE-LEVEL theorem the substrate
/// carries per array declaration rather than a runtime test the
/// developer must remember to write per label constant.
/// - THEORY.md §II.1 invariant 1 — typed entry; a closed-set variant's
/// label projection is the entry-point discriminator into the typed
/// algebra, and a non-ASCII byte in that projection silently
/// escapes the seven-bit-clean assumption every downstream wire
/// surface encodes into its own byte-level parser.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// byte-range sweep IS the generative shape. Every new closed-set
/// label array adds ONE `const _` line to get the ASCII theorem
/// rather than re-deriving a per-array runtime iterator sweep at
/// each call site.
pub const fn assert_str_array_all_ascii<const N: usize>(arr: &[&'static str; N]) {
let mut i = 0;
while i < N {
let bytes = arr[i].as_bytes();
let mut j = 0;
while j < bytes.len() {
if bytes[j] > 0x7F {
panic!(
"assert_str_array_all_ascii: STR-NON-ASCII-ENTRY — \
the family-wide &'static str array carries an \
entry with a byte outside the seven-bit ASCII \
range (>= 0x80) at some position — the \
substrate's ASCII-BYTE-RANGE contract on the \
array is broken; every consumer that ships an \
entry through a seven-bit-clean downstream \
surface (K8s annotation keys + label values; \
YAML flow-scalar map keys; BLAKE3 hash inputs on \
the three-pillar attestation chain; Rust \
`matches!(s, ...)` byte-pattern arms) treats \
each entry as ASCII — a non-ASCII byte silently \
invites Unicode-normalization drift on the wire, \
BOM injection, and lookalike-label collisions \
that byte-equality parsing cannot detect. Fix at \
the ARRAY-DECLARATION site by re-inlining the \
offending label constant to its seven-bit-clean \
canonical spelling"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time ASCII-BYTE-RANGE witnesses — one `const _: () =
// assert_str_array_all_ascii(&…)` per family-wide `[&'static str; N]`
// array on the substrate's closed-set outer algebras. Each invocation
// is const-evaluated at `cargo check` time; a regression that
// silently re-inlined one label constant to a lookalike non-ASCII
// spelling fails the build rather than deferring to a per-consumer
// byte-parse misbehavior at runtime. Sibling to the NONEMPTY witnesses
// above — those pin the per-entry length-lower-bound gate on each
// array, these pin the strictly-orthogonal per-entry byte-range gate
// on the SAME arrays. The two contracts compose orthogonally on every
// closed-set outer algebra's label vocabulary. The five arrays covered
// here mirror the five arrays already pinned by the `_pairwise_distinct`
// AND `_all_nonempty` witnesses above — the (per-entry × contract-shape)
// coverage matrix on the (`&'static str`) row of this file now holds
// at THREE corners {NONEMPTY, ASCII, INJECTIVITY} for the five outer-
// algebra arrays declared here. Analogous witnesses on the (`&'static
// str`) arrays declared under `crate::error` land co-located with the
// pre-existing `_pairwise_distinct` + `_all_nonempty` witnesses at
// that file's module-level prelude.
const _: () = assert_str_array_all_ascii(&Atom::BOOL_LITERALS);
const _: () = assert_str_array_all_ascii(&AtomKind::LABELS);
const _: () = assert_str_array_all_ascii(&QuoteForm::PREFIXES);
const _: () = assert_str_array_all_ascii(&QuoteForm::IAC_FORGE_TAGS);
const _: () = assert_str_array_all_ascii(&QuoteForm::LABELS);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `a` aliases any entry of `b` byte-for-byte through
/// [`str::as_bytes`].
///
/// Row-dual peer to [`assert_char_arrays_disjoint`] and
/// [`assert_u8_arrays_disjoint`] on the (element-type) axis of the
/// (element-type × contract-shape) matrix at the (disjointness)
/// column: where the (char) sibling closes the reader-boundary char
/// DISJOINTNESS corner and the (u8) sibling closes the outer-`Sexp`
/// cache-key `u8` DISJOINTNESS corner at compile time, this (`&'static
/// str`) sibling closes the outer-algebras' family-wide `[&'static
/// str; N]` label / prefix / tag / literal DISJOINTNESS corner on the
/// SAME contract-shape column. Together with the pre-existing
/// [`assert_char_arrays_disjoint`] + [`assert_u8_arrays_disjoint`]
/// row-siblings the three helpers close the (element-type ∈
/// {char, u8, &'static str} × contract-shape ∈ {disjointness})
/// 3-corner row of the DISJOINTNESS column at ONE peer const-fn helper
/// per element-type. Contract-orthogonal peer to
/// [`assert_str_array_pairwise_distinct`] on the (INJECTIVITY,
/// DISJOINTNESS) axis of the (contract-shape) column on the SAME
/// (`&'static str`) row: where the pairwise-distinctness sibling binds
/// INTRA-array `∀ i ≠ j : arr[i] ≠ arr[j]`, this DISJOINTNESS sibling
/// binds INTER-array `∀ i, j : a[i] ≠ b[j]` — the two together give
/// every `&'static str` sub-vocabulary on the substrate BOTH intra-
/// array injectivity AND inter-array disjointness at compile time.
///
/// The invariant is load-bearing for every consumer that partitions
/// the two arrays' distinct-values sets into disjoint sub-vocabularies
/// of a shared outer surface —
/// [`QuoteForm::PREFIXES`] (`["'", "\`", ",", ",@"]` — reader-boundary
/// prefix tokens the tokenizer scans in [`crate::reader::tokenize`])
/// is intentionally-closed disjoint from
/// [`QuoteForm::LABELS`] (`["quote", "quasiquote", "unquote",
/// "unquote-splice"]` — human-diagnostic labels the error module
/// projects through [`QuoteForm::label`]) so a reader-boundary token
/// never aliases a diagnostic label spelling; the SAME `QuoteForm::
/// PREFIXES` array is disjoint from
/// [`QuoteForm::IAC_FORGE_TAGS`] (`["quote", "quasiquote", "unquote",
/// "unquote-splicing"]` — canonical iac-forge interop symbol heads the
/// `crate::interop` (removed) round-trip pins through
/// [`QuoteForm::from_iac_forge_tag`]) so the reader-boundary vocabulary
/// stays clean of the canonical-form serialization vocabulary; the
/// SAME `QuoteForm::PREFIXES` array is disjoint from
/// [`AtomKind::LABELS`] (`["symbol", "keyword", "string", "int",
/// "float", "bool"]` — atomic-payload kind labels) so a reader-boundary
/// prefix never aliases an atom-kind diagnostic label; AND
/// [`AtomKind::LABELS`] is intentionally-closed disjoint from
/// [`QuoteForm::LABELS`] so a diagnostic that identifies "the token is
/// an atom of kind X" never aliases "the token is a quote form of
/// kind Y". Every future `[&'static str; N]` pair on the substrate
/// whose distinct-values sets must remain disjoint sub-vocabularies of
/// a shared outer surface participates in the SAME compile-time
/// guarantee via one `const _` line per pair.
///
/// Pre-lift the four disjointness relations lived only as runtime
/// tests (`quote_form_prefixes_disjoint_from_quote_form_labels`,
/// `quote_form_prefixes_disjoint_from_iac_forge_tags`,
/// `quote_form_prefixes_disjoint_from_atom_kind_labels`,
/// `atom_kind_labels_disjoint_from_quote_form_labels`) or implicitly
/// through the outer-algebra's non-aliasing composition rule; post-
/// lift the ARRAY-LEVEL disjointness of the four pinned pairs binds at
/// rustc time via one `const _` line per pair. A regression that
/// silently renamed one of `QuoteForm::PREFIXES`'s entries to a string
/// that aliased a `QuoteForm::LABELS` / `QuoteForm::IAC_FORGE_TAGS` /
/// `AtomKind::LABELS` entry (or vice versa) fails at `cargo check`
/// BEFORE any test scheduler runs.
///
/// Adding a new `[&'static str; N]` sub-vocabulary whose distinct-
/// values set must remain disjoint from another substrate `[&'static
/// str; M]` array's distinct-values set: pair the declaration with
/// `const _: () = assert_str_arrays_disjoint::<N, M>(&Self::FOO_ARRAY,
/// &Other::BAR_ARRAY);` co-located after the array's declaration and
/// the DISJOINTNESS contract binds at compile time. The rustc-forced
/// arities `[&'static str; N]` and `[&'static str; M]` compose with
/// this const-eval sweep so BOTH cardinality-pair AND cross-array
/// disjointness are compile-time theorems on the SAME (a, b) str-array
/// pair.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_str_arrays_disjoint_panics_at_runtime_on_collision` and
/// `assert_str_arrays_disjoint_panic_message_names_the_helper_and_str_disjointness_violation_axis`.
/// The panic site carries the `"STR-DISJOINTNESS-VIOLATION"` axis-
/// provenance string chosen DISTINCT from every sibling helper's axis
/// vocabulary (`"duplicate"` on the ARRAY-side pairwise-distinct
/// sibling; `"CHAR-DISJOINTNESS-VIOLATION"` on the (char) row-dual
/// DISJOINTNESS sibling; `"U8-DISJOINTNESS-VIOLATION"` on the (u8)
/// row-dual DISJOINTNESS sibling; `"CHAR-SUBSET-VIOLATION"` on the
/// (char) SUBSET-embedding sibling; `"SUBSET-VIOLATION"` on the (u8)
/// finite-set SUBSET-only sibling; `"RANGE-SUBSET-VIOLATION"` on the
/// (u8) range SUBSET-only sibling; `"OUT-OF-SET"` / `"SET-BYTE-
/// MISSING"` on the (u8) covers-finite-set sibling; `"OUT-OF-RANGE"` /
/// `"MISSING"` on the (u8) covers-inclusive-range sibling; `"ARITY-
/// MISMATCH"` on both (u8) `_permutes_*` compound helpers; `"SET-NOT-
/// PAIRWISE-DISTINCT"` on the (u8) SET-side well-formedness sibling)
/// so a diagnostic that names the failed axis routes UNAMBIGUOUSLY to
/// THIS specific `&'static str` DISJOINTNESS helper. The `"STR-"`
/// prefix disambiguates from the (char) + (u8) row-dual DISJOINTNESS
/// siblings; the shared `"-DISJOINTNESS-VIOLATION"` suffix lets
/// callers grep any row's DISJOINTNESS sibling by
/// `"DISJOINTNESS-VIOLATION"` alone.
///
/// Byte-equality reuse: the helper delegates to the same module-
/// private [`str_bytes_equal`] const-fn helper the sibling
/// [`assert_str_array_pairwise_distinct`] uses — a single canonical
/// site for `&'static str` byte-equality in const context, so a future
/// toolchain stabilising `const fn str::eq` collapses BOTH callers at
/// ONE edit rather than two.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide cross-array
/// disjointness contract on the substrate's `&'static str`
/// vocabulary becomes a TYPE-LEVEL theorem the substrate carries per
/// (a, b) str-array pair rather than a runtime test the developer
/// must remember to write per pair.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the DISJOINTNESS corner on THREE rows
/// ({char, u8, `&'static str`}) at ONE peer const-fn helper per row.
/// The (element-type ∈ {char, u8, `&'static str`}) × (contract-shape
/// ∈ {pairwise-distinctness (INJECTIVITY), disjointness}) 3×2 =
/// 6-corner face on the array-pair-contract prism is now closed at
/// SIX peer const-fn helpers.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// cross-array byte-membership sweep IS the generative shape. Every
/// new `[&'static str; N]` sub-vocabulary array whose distinct-
/// values set is an intentionally-disjoint peer of another substrate
/// `[&'static str; M]` array adds ONE `const _` line to get the
/// disjointness theorem rather than re-deriving a per-pair runtime
/// iterator sweep at each call site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// DISJOINTNESS proof at declaration site AND the outer-algebra's
/// arm-set partition contract (`QuoteForm::PREFIXES` on the reader-
/// boundary token surface vs. `QuoteForm::LABELS` on the human-
/// diagnostic label surface, etc.) regenerate through the SAME
/// `const _` witnesses at the ARRAY level.
///
/// Frontier inspiration: Lean 4's `Finset.disjoint_iff` unfolded to
/// `∀ a ∈ s, ∀ b ∈ t, a ≠ b` at the concrete two-array
/// `[&'static str; N] × [&'static str; M]` monomorphic realisation.
/// The (char, u8, `&'static str`) row triple mirrors Lean's
/// polymorphic `[DecidableEq α] → Finset α → Finset α → Prop`
/// realised at the three concrete element-type instantiations the
/// substrate closes at compile time.
pub const fn assert_str_arrays_disjoint<const N: usize, const M: usize>(
a: &[&'static str; N],
b: &[&'static str; M],
) {
let mut i = 0;
while i < N {
let mut j = 0;
while j < M {
if str_bytes_equal(a[i], b[j]) {
panic!(
"assert_str_arrays_disjoint: STR-DISJOINTNESS-\
VIOLATION — the two family-wide &'static str \
arrays `a` and `b` share an entry at some (i, j) \
position pair. The substrate's CROSS-ARRAY \
DISJOINTNESS contract on the pair is broken; \
every consumer that partitions the two arrays' \
distinct-values sets into disjoint sub-\
vocabularies of a shared outer surface (the \
reader-boundary prefix vocabulary at \
`QuoteForm::PREFIXES` vs the human-diagnostic \
label vocabulary at `QuoteForm::LABELS`; the \
reader-boundary prefix vocabulary vs the \
canonical iac-forge tag vocabulary at \
`QuoteForm::IAC_FORGE_TAGS`; the reader-boundary \
prefix vocabulary vs the atomic-kind label \
vocabulary at `AtomKind::LABELS`; the atomic-kind \
label vocabulary vs the quote-family label \
vocabulary; any future typed-disjointness pair on \
the substrate's `&'static str` sub-vocabularies) \
relies on the two arrays' distinct-values sets \
NOT sharing an entry. Fix at WHICHEVER ARRAY-\
DECLARATION site drifted (the symmetric \
disjointness relation carries no built-in axis-\
provenance role split between `a` and `b`) by \
renaming the offending entry on one array OR re-\
shaping the partition to route the shared entry \
to a single sub-vocabulary"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time DISJOINTNESS witnesses — the FOUR substrate-pinned
// (a, b) `[&'static str; N] × [&'static str; M]` pairs whose distinct-
// values sets are intentionally-closed disjoint sub-vocabularies of a
// shared outer surface. Pre-lift the four disjointness relations lived
// only as runtime tests (or implicitly through the outer-algebra's
// non-aliasing composition rule); post-lift the ARRAY-LEVEL
// disjointness of the four pinned pairs binds at rustc time via one
// `const _` line per pair. A regression that silently renamed
// `QuoteForm::QUOTE_PREFIX` (`"'"`) to `"quote"` (aliasing
// `QuoteForm::QUOTE_LABEL` and `QuoteForm::QUOTE_IAC_FORGE_TAG`),
// renamed `AtomKind::SYMBOL_LABEL` (`"symbol"`) to `"quote"` (aliasing
// `QuoteForm::QUOTE_LABEL`), or drifted any entry of one array to
// bytes shared with an entry of a disjoint peer array fails at
// `cargo check` BEFORE any test scheduler runs. Sibling to the FIVE
// `assert_char_arrays_disjoint` witnesses and the TWO
// `assert_u8_arrays_disjoint` witnesses above on the (element-type)
// axis: `char` covers the reader-boundary char sub-vocabularies;
// `u8` covers the outer-`Sexp` cache-key discriminator sub-
// vocabularies; `&'static str` covers the outer-algebras' family-wide
// label / prefix / tag vocabularies.
//
// The four pinned pairs are (all under the shared `&'static str`
// element-type):
// 1. `QuoteForm::PREFIXES` ∩ `QuoteForm::LABELS` = ∅
// 2. `QuoteForm::PREFIXES` ∩ `QuoteForm::IAC_FORGE_TAGS` = ∅
// 3. `QuoteForm::PREFIXES` ∩ `AtomKind::LABELS` = ∅
// 4. `AtomKind::LABELS` ∩ `QuoteForm::LABELS` = ∅
//
// The TWO remaining disjointness pairs on the twelve-arm
// `SexpShape::LABELS` partition triple
// (`AtomKind::LABELS`, `QuoteForm::LABELS`, `StructuralKind::LABELS`)
// — namely (`AtomKind::LABELS`, `StructuralKind::LABELS`) and
// (`QuoteForm::LABELS`, `StructuralKind::LABELS`) — are pinned as
// peer `const _` lines in `error.rs` (the file where the
// `StructuralKind` host type lives). Split by host-file, unified in
// theorem: together with pair 4 above they cover every pair on the
// three-element sub-vocabulary triple (C(3, 2) = 3), closing the
// DISJOINT-UNION proof
// `SexpShape::LABELS ≡ AtomKind::LABELS ⊕ QuoteForm::LABELS ⊕
// StructuralKind::LABELS`
// at compile time.
//
// Note on the intentionally-NOT-pinned pair
// (`QuoteForm::LABELS`, `QuoteForm::IAC_FORGE_TAGS`): the two
// deliberately OVERLAP on three of four arms (`"quote"`, `"quasiquote"`,
// `"unquote"`) because both surfaces spell those three quote-family
// heads with the Common-Lisp-canonical name — `QuoteForm::LABELS` for
// diagnostics, `QuoteForm::IAC_FORGE_TAGS` for canonical serialization.
// Only the fourth arm differs (`QuoteForm::UNQUOTE_SPLICE_LABEL` at
// `"unquote-splice"` vs `QuoteForm::UNQUOTE_SPLICE_IAC_FORGE_TAG` at
// `"unquote-splicing"`) so the pair is NOT disjoint and would fail
// this witness. Pinning it here would be a category error — the
// overlap is load-bearing, not accidental.
const _: () = assert_str_arrays_disjoint::<4, 4>(&QuoteForm::PREFIXES, &QuoteForm::LABELS);
const _: () = assert_str_arrays_disjoint::<4, 4>(&QuoteForm::PREFIXES, &QuoteForm::IAC_FORGE_TAGS);
const _: () = assert_str_arrays_disjoint::<4, 6>(&QuoteForm::PREFIXES, &AtomKind::LABELS);
const _: () = assert_str_arrays_disjoint::<6, 4>(&AtomKind::LABELS, &QuoteForm::LABELS);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `arr` is NOT a member of `set` (byte-for-byte through
/// [`str::as_bytes`]).
///
/// Row-dual peer to [`assert_char_array_within_char_finite_set`] and
/// [`assert_u8_array_within_u8_finite_set`] on the (element-type) axis
/// of the (element-type × contract-shape) matrix at the (subset-
/// embedding) column: where the (char) sibling closes the reader-
/// boundary `[char; N] ⊆ [char; M]` corner and the (u8) sibling closes
/// the outer-`Sexp` cache-key `[u8; N] ⊆ [u8; M]` finite-set embedding
/// corner at compile time, this (`&'static str`) sibling closes the
/// outer-algebras' family-wide `[&'static str; N] ⊆ [&'static str; M]`
/// label / prefix / tag SUB-VOCABULARY carving corner. Together with
/// the pre-existing [`assert_char_array_within_char_finite_set`] +
/// [`assert_u8_array_within_u8_finite_set`] row-siblings the three
/// helpers close the (element-type ∈ {char, u8, &'static str} ×
/// contract-shape ∈ {subset-embedding}) 3-corner row of the SUBSET-
/// EMBEDDING column at ONE peer const-fn helper per element-type.
/// Contract-orthogonal peer to [`assert_str_array_pairwise_distinct`]
/// and [`assert_str_arrays_disjoint`] on the (INJECTIVITY,
/// DISJOINTNESS, SUBSET-EMBEDDING) axis of the (contract-shape) column
/// on the SAME (`&'static str`) row: where the pairwise-distinctness
/// sibling binds INTRA-array `∀ i ≠ j : arr[i] ≠ arr[j]` and the
/// disjointness sibling binds INTER-array `∀ i, j : a[i] ≠ b[j]`, this
/// SUBSET-EMBEDDING sibling binds ORIENTED-INTER-array `∀ i : ∃ j :
/// arr[i] = set[j]` — the three together give every `&'static str`
/// sub-vocabulary on the substrate INTRA-array injectivity AND INTER-
/// array disjointness (symmetric) AND INTER-array subset embedding
/// (oriented) at compile time.
///
/// The invariant is load-bearing for every consumer that carves a
/// SUB-vocabulary of a shared OUTER `&'static str` vocabulary:
/// [`AtomKind::LABELS`] (`[&; 6]`, `["symbol", "keyword", "string",
/// "int", "float", "bool"]` — the atomic-payload kind labels) is an
/// intentionally-closed proper subset of
/// [`crate::error::SexpShape::LABELS`] (`[&; 12]`, the twelve outer-
/// `Sexp` shape labels; six atomic + two structural + four quote-
/// family) so every atom-kind diagnostic label stays inside the outer-
/// shape label vocabulary; [`QuoteForm::LABELS`] (`[&; 4]`, `["quote",
/// "quasiquote", "unquote", "unquote-splice"]` — the quote-family
/// labels) is likewise a proper subset of the SAME
/// [`crate::error::SexpShape::LABELS`] so every quote-family diagnostic
/// stays inside the outer-shape vocabulary; and
/// [`crate::error::StructuralKind::LABELS`] (`[&; 2]`, `["nil",
/// "list"]` — the structural-shape labels) is the third proper subset
/// of the SAME twelve-arm superset. Union together `AtomKind::LABELS`
/// (6) + `QuoteForm::LABELS` (4) + `StructuralKind::LABELS` (2) = 12
/// = `SexpShape::LABELS.len()` closes a NON-CONTIGUOUS PARTITION of
/// the outer twelve-arm vocabulary at compile time; the three
/// SUBSET-EMBEDDING witnesses PLUS the pre-existing pairwise-
/// distinctness witnesses PLUS the pre-existing (AtomKind, QuoteForm)
/// disjointness witness compose to a full partition proof. Every
/// future `[&'static str; N]` sub-vocabulary on the substrate whose
/// distinct-values set must remain embedded in a shared outer surface
/// (a new tokenizer keyword vocabulary embedded in an outer prefix
/// vocabulary; a new diagnostic label vocabulary embedded in an outer
/// error-family label vocabulary; a new algebra whose display / label
/// / prefix arrays must remain sub-vocabularies of the closed-set
/// outer algebras' `&'static str` surface) gets the subset-embedding
/// theorem at ONE `const _` line rather than a per-pair runtime
/// iterator sweep.
///
/// SET-side well-formedness is DELEGATED to the sibling ARRAY-side
/// pairwise-distinctness helper ([`assert_str_array_pairwise_distinct`])
/// via a co-located call at the TOP of the sweep — a malformed `set`
/// (e.g. `["a", "a", "b"]`) is NOT a well-formed finite set of
/// cardinality `M` and silently mis-verifies the intended subset
/// contract on any `arr` embedded in the DISTINCT-value subset. The
/// delegated arm routes drift on the CALLER'S TARGET-SET SPEC to the
/// SET-side well-formedness axis rather than to a downstream STR-
/// SUBSET-VIOLATION symptom on `arr`. A well-formed `set` passes this
/// arm as a no-op — the sweep is const-eval-elidable and costs zero
/// at rustc-time on the substrate call sites. The (str) row does NOT
/// carry a separate `assert_str_finite_set_pairwise_distinct` alias
/// (the (u8) row's `assert_u8_finite_set_pairwise_distinct` is the
/// only SET-side well-formedness peer on the substrate); the
/// delegation reuses the ARRAY-side helper directly, matching the
/// (char) row's (`assert_char_array_within_char_finite_set` →
/// `assert_char_array_pairwise_distinct`) delegation shape.
///
/// Pre-lift the three subset embeddings lived as prose in the parent
/// arrays' partition-rule docstrings (the `SexpShape::LABELS` twelve-
/// arm decomposition into atomic / structural / quote-family sub-
/// vocabularies) and as runtime `_pairwise_distinct` cross-checks on
/// the tests submodule — the ARRAY-LEVEL embedding was not itself
/// pinned. Post-lift the three witnesses bind at rustc time via one
/// `const _` line per pair; a regression that silently re-inlined
/// either the SUBSET side (dropping `AtomKind::SYMBOL_LABEL`'s
/// `SexpShape::SYMBOL_LABEL` alias to a fresh distinct byte spelling)
/// or the SUPERSET side (dropping `SexpShape::SYMBOL_LABEL` and
/// leaving `AtomKind::SYMBOL_LABEL` as a stale copy of `"symbol"`)
/// fails at `cargo check` BEFORE any test scheduler runs.
///
/// Adding a new family-wide `[&'static str; N]` sub-vocabulary whose
/// distinct-values set must remain embedded in another substrate
/// `[&'static str; M]` array's distinct-values set: pair the
/// declaration with `const _: () = assert_str_array_within_str_finite_
/// set::<N, M>(&Self::FOO_ARRAY, &Other::BAR_ARRAY);` co-located after
/// the array's declaration and the SUBSET-EMBEDDING contract binds at
/// compile time. The rustc-forced arities `[&'static str; N]` and
/// `[&'static str; M]` compose with this const-eval sweep so BOTH
/// cardinality-pair AND cross-array subset embedding are compile-time
/// theorems on the SAME (arr, set) str-array pair.
///
/// Delegates to the existing module-private [`str_bytes_equal`] const-
/// fn helper so a future toolchain stabilising `const fn str::eq`
/// collapses ALL THREE (str)-row helpers ((str, pairwise-distinct),
/// (str, disjointness), (str, subset-embedding)) through ONE edit.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_str_array_within_str_finite_set_panics_at_runtime_on_out_of_set_entry`
/// and
/// `assert_str_array_within_str_finite_set_panic_message_names_the_helper_and_str_subset_violation_axis`.
/// The panic site carries the `"STR-SUBSET-VIOLATION"` axis-provenance
/// string chosen DISTINCT from every sibling helper's axis vocabulary
/// (`"duplicate"` on the ARRAY-side pairwise-distinct sibling; `"STR-
/// DISJOINTNESS-VIOLATION"` on the (str) row DISJOINTNESS sibling;
/// `"CHAR-SUBSET-VIOLATION"` on the (char) row-dual SUBSET sibling;
/// `"SUBSET-VIOLATION"` on the (u8) row-dual finite-set SUBSET-only
/// sibling; `"RANGE-SUBSET-VIOLATION"` on the (u8) range SUBSET-only
/// sibling; `"CHAR-DISJOINTNESS-VIOLATION"` / `"U8-DISJOINTNESS-
/// VIOLATION"` on the (char) / (u8) row-dual DISJOINTNESS siblings;
/// `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the (u8) covers-finite-
/// set sibling; `"OUT-OF-RANGE"` / `"MISSING"` on the (u8) covers-
/// inclusive-range sibling; `"ARITY-MISMATCH"` on both (u8)
/// `_permutes_*` compound helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on
/// the (u8) SET-side well-formedness sibling) so a diagnostic that
/// names the failed axis routes UNAMBIGUOUSLY to (a) this specific
/// `&'static str` SUBSET-embedding helper, (b) the `arr` argument as
/// the drift site rather than the `set` argument specifying the
/// target superset. The `"STR-"` prefix disambiguates from the
/// (char) + (u8) row-dual peers; the shared `"-SUBSET-VIOLATION"`
/// suffix lets callers grep any row's SUBSET-embedding sibling by
/// the shared `"SUBSET-VIOLATION"` suffix alone.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide cross-array
/// subset-embedding contract on `&'static str` sub-vocabularies
/// becomes a TYPE-LEVEL theorem the substrate carries per (arr,
/// set) str-array pair rather than a runtime test the developer
/// must remember to write per pair.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the SUBSET-EMBEDDING corner on THREE
/// rows at ONE peer const-fn helper per row. The (subset,
/// disjointness) 2-corner face on the (`&'static str`) row is now
/// closed at TWO peer const-fn helpers —
/// [`assert_str_arrays_disjoint`] on the DISJOINTNESS corner and
/// this helper on the SUBSET corner.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// cross-array membership sweep IS the generative shape. Every new
/// closed-set `&'static str` sub-vocabulary array whose distinct-
/// values set is an intentionally-embedded proper subset of another
/// substrate `&'static str` array adds ONE `const _` line to get
/// the subset-embedding theorem rather than re-deriving a per-pair
/// runtime iterator sweep at each call site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// SUBSET-EMBEDDING proof at declaration site AND the outer-
/// algebra's twelve-arm shape-label partition contract regenerate
/// through the SAME `const _` witnesses at the ARRAY level.
///
/// Frontier inspiration: Lean 4's `Finset.subset_iff : s ⊆ t ↔ ∀ a ∈
/// s, a ∈ t` unfolded at the concrete `[&'static str; N] ⊆ [&'static
/// str; M]` monomorphic realisation — the substrate primitive here
/// embeds the same subset relation as a rustc const-eval-time proof
/// obligation at every `assert_str_array_within_str_finite_set` call
/// site rather than as a Lean tactic invocation deferred to
/// `elab_command`. The (char, u8, `&'static str`) row triple mirrors
/// Lean's polymorphic `[DecidableEq α] → Finset α → Finset α → Prop`
/// realised at three concrete element-type instantiations the
/// substrate closes at compile time.
pub const fn assert_str_array_within_str_finite_set<const N: usize, const M: usize>(
arr: &[&'static str; N],
set: &[&'static str; M],
) {
// Delegate target-set well-formedness to the sibling ARRAY-side
// pairwise-distinctness helper FIRST. Placed BEFORE the STR-
// SUBSET-VIOLATION sweep below because a malformed `set` (e.g.
// `["a", "a", "b"]`) is not a well-formed finite set of
// cardinality `M` and silently mis-verifies the intended subset
// contract on any `arr` embedded in the DISTINCT-value subset.
// Routes drift on the CALLER'S TARGET-SET SPEC to the SET-side
// well-formedness axis (via the sibling's own panic-name prefix)
// rather than to a downstream STR-SUBSET-VIOLATION symptom on
// `arr`. A well-formed `set` passes this arm as a no-op — the
// sweep is const-eval-elidable and costs zero at rustc-time on
// the substrate call sites.
assert_str_array_pairwise_distinct(set);
let mut i = 0;
while i < N {
let mut j = 0;
let mut found = false;
while j < M {
if str_bytes_equal(arr[i], set[j]) {
found = true;
break;
}
j += 1;
}
if !found {
panic!(
"assert_str_array_within_str_finite_set: STR-SUBSET-\
VIOLATION — the family-wide &'static str array `arr` \
carries an entry at some position whose bytes are \
NOT a member of the target finite superset partition \
`set`. The substrate's SUBSET-EMBEDDING contract on \
the array is broken; every consumer that expects the \
array's distinct-value set to be a subset of the \
target finite partition (`AtomKind::LABELS ⊂ \
SexpShape::LABELS` on the atomic-payload sub-\
vocabulary carve of the twelve-arm outer-shape label \
vocabulary; `QuoteForm::LABELS ⊂ SexpShape::LABELS` \
on the quote-family sub-vocabulary carve of the SAME \
twelve-arm outer-shape label vocabulary; \
`StructuralKind::LABELS ⊂ SexpShape::LABELS` on the \
structural sub-vocabulary carve of the SAME twelve-\
arm outer-shape label vocabulary; any future typed-\
subset embedding on the substrate's `&'static str` \
sub-vocabularies) relies on every array entry \
staying within the target superset. Fix at the \
ARRAY-DECLARATION site (the `arr` under \
verification, NOT the `set` argument specifying the \
target superset) by dropping the offending entry OR \
by extending `set` to cover it — the choice depends \
on whether the drift is an unintended overshoot \
outside the parent superset or an intentional \
extension of the superset vocabulary"
);
}
i += 1;
}
}
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of the target finite `set` is NOT reached by at least one
/// entry across the three sub-vocabulary arrays `a`, `b`, `c`.
///
/// SURJECTIVITY dual of [`assert_str_array_within_str_finite_set`] at
/// the (`&'static str`) row of the (element-type × contract-shape)
/// matrix, extended to the 3-array-union carrier shape: where the
/// within-helper closes the SUBSET direction for a single array
/// (`arr ⊆ set`), this helper closes the COVERAGE direction for a
/// three-array partition triple (`set ⊆ a ∪ b ∪ c`) at compile time.
/// Composed with the three sibling SUBSET-EMBEDDING witnesses (each
/// sub-array's `_within_str_finite_set` pin) AND the three sibling
/// pairwise-DISJOINTNESS witnesses (each pair's
/// `assert_str_arrays_disjoint` pin) AND the parent's INJECTIVITY
/// witness (`_pairwise_distinct` on the parent set), the four
/// contract-shape corners jointly close the full DISJOINT-UNION
/// theorem `set ≡ a ⊕ b ⊕ c` at rustc const-eval time on the
/// substrate's twelve-arm `SexpShape::LABELS` outer-vocabulary
/// partition — the pre-existing runtime cross-check
/// `sexp_shape_labels_is_disjoint_union_of_three_sub_vocabularies`
/// becomes a defense-in-depth safety net for the SAME theorem the
/// compile-time witness triple now enforces at `cargo check` time,
/// one invocation stage earlier.
///
/// Delegates target-set well-formedness to the ARRAY-side
/// [`assert_str_array_pairwise_distinct`] helper via a co-located
/// call at the TOP of the sweep — a malformed `set` (e.g.
/// `["a", "a", "b"]`) is not a well-formed finite set of cardinality
/// `W` and silently mis-verifies the intended COVERAGE contract on
/// any `(a, b, c)` triple whose distinct-value union misses the
/// duplicated set byte (the duplicated byte still counts as covered
/// on the FIRST hit even if the second copy is absent from the
/// union). Routes drift on the CALLER'S TARGET-SET SPEC to the SET-
/// side well-formedness axis rather than to a downstream SET-STR-
/// MISSING symptom on `(a, b, c)`. The (str) row does NOT carry a
/// separate `assert_str_finite_set_pairwise_distinct` alias; the
/// delegation reuses the ARRAY-side helper directly, matching the
/// (str) row's sibling delegation shape at
/// [`assert_str_array_within_str_finite_set`].
///
/// The sub-vocabulary arities `N`, `M`, `K` and the parent
/// cardinality `W` are INDEPENDENT const generics: this helper
/// intentionally does NOT enforce `N + M + K == W` at const-eval
/// time. That arity sum is a CONSEQUENCE of the disjoint-union
/// theorem (COVERAGE here + pairwise DISJOINTNESS at the sibling
/// witnesses + parent INJECTIVITY) rather than a separate pre-
/// condition; a caller that binds all three peer witnesses AND this
/// COVERAGE witness AND finds a cardinality mismatch has necessarily
/// broken one of the four contract corners, and the diagnostic fires
/// on the specific corner that broke rather than on a synthetic
/// arity-sum pre-check. Under-covering triples (`N + M + K < W`) fire
/// the SET-STR-MISSING panic here; over-covering triples
/// (`N + M + K > W`) fire the STR-DISJOINTNESS-VIOLATION panic at the
/// sibling pairwise-disjointness witness or the STR-SUBSET-VIOLATION
/// panic at the sibling `_within_str_finite_set` witness. The four-
/// corner diagnostic partition stays sharp on the FAILURE mode rather
/// than collapsing every drift onto a single arity-sum axis.
///
/// Pre-lift the twelve-arm `SexpShape::LABELS` disjoint-union
/// theorem lived as a runtime cross-check
/// (`sexp_shape_labels_is_disjoint_union_of_three_sub_vocabularies`
/// at `error.rs` tests module) that iterated every parent label and
/// counted its multiplicity across the three sub-vocabularies. The
/// runtime sweep enforced BOTH directions (⊆) and (⊇) of the
/// disjoint-union at test time; the (⊇) direction was already lifted
/// to compile time via three `_within_str_finite_set` witnesses in
/// `error.rs` (each sub-vocab ⊂ parent) and three
/// `assert_str_arrays_disjoint` witnesses (pairwise disjoint), but
/// the (⊆) direction — every parent label appears in at least one
/// sub-vocabulary — remained runtime-only. Post-lift this helper
/// binds the (⊆) direction at `cargo check` time via ONE `const _`
/// line on the (`AtomKind::LABELS`, `QuoteForm::LABELS`,
/// `StructuralKind::LABELS`, `SexpShape::LABELS`) partition-triple-
/// with-parent quadruple; a regression that silently drops a variant
/// from one of the three sub-vocabularies (e.g. removing
/// `AtomKind::Bool` and its `AtomKind::BOOL_LABEL` alias while
/// leaving `SexpShape::Bool` and its `SexpShape::BOOL_LABEL` alias in
/// the parent vocabulary) fires the SET-STR-MISSING panic at
/// `cargo check` BEFORE any test scheduler runs.
///
/// Adding a new n-way partition proof on the substrate's `&'static
/// str` vocabularies (e.g. a hypothetical fourth sub-vocabulary
/// carving of a widened `SexpShape` parent, or an independent
/// partition on `Atom::ESCAPE_SOURCES` into printable / whitespace /
/// control sub-vocabularies): pair the parent+partition declaration
/// with `const _: () = assert_str_finite_set_covered_by_three_str_
/// arrays::<N, M, K, W>(&Foo::LABELS, &Bar::LABELS, &Baz::LABELS,
/// &Parent::LABELS);` co-located after the partition arrays'
/// declarations and the COVERAGE contract binds at compile time. The
/// rustc-forced arities `[&'static str; N]`, `[&'static str; M]`,
/// `[&'static str; K]`, `[&'static str; W]` compose with this const-
/// eval sweep so BOTH the four cardinalities AND the (⊆) disjoint-
/// union direction are compile-time theorems on the SAME partition
/// quadruple.
///
/// Delegates to the existing module-private [`str_bytes_equal`]
/// const-fn helper so a future toolchain stabilising `const fn
/// str::eq` collapses ALL FOUR (str)-row helpers ((str, pairwise-
/// distinct), (str, disjointness), (str, subset-embedding), (str,
/// three-array-coverage)) through ONE edit.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_str_finite_set_covered_by_three_str_arrays_panics_at_runtime_on_uncovered_parent_entry`
/// and
/// `assert_str_finite_set_covered_by_three_str_arrays_panic_message_names_the_helper_and_set_str_missing_axis`.
/// The panic site carries the `"SET-STR-MISSING"` axis-provenance
/// string chosen DISTINCT from every sibling helper's axis vocabulary
/// (`"duplicate"` on the ARRAY-side pairwise-distinct sibling; `"STR-
/// SUBSET-VIOLATION"` on the (str) row SUBSET sibling; `"STR-
/// DISJOINTNESS-VIOLATION"` on the (str) row DISJOINTNESS sibling;
/// `"CHAR-SUBSET-VIOLATION"` on the (char) row-dual SUBSET sibling;
/// `"SUBSET-VIOLATION"` on the (u8) row-dual finite-set SUBSET-only
/// sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the (u8) covers-
/// finite-set sibling; `"OUT-OF-RANGE"` / `"MISSING"` on the (u8)
/// covers-inclusive-range sibling; `"ARITY-MISMATCH"` on both (u8)
/// `_permutes_*` compound helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on
/// the (u8) SET-side well-formedness sibling) so a diagnostic that
/// names the failed axis routes UNAMBIGUOUSLY to (a) this specific
/// three-array COVERAGE helper on the `&'static str` element-type
/// row, (b) the `set` argument as the drift-target (the parent
/// element that no sub-array reaches) rather than any single sub-
/// vocabulary carrier. The `"SET-STR-MISSING"` axis distinguishes
/// from the (u8) row's `"SET-BYTE-MISSING"` peer via the element-
/// type infix — one substring search per element-type routes any
/// row's SET-side COVERAGE-VIOLATION back to its element-type peer.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the DISJOINT-UNION theorem
/// on `&'static str` sub-vocabulary partitions becomes a TYPE-LEVEL
/// theorem the substrate carries per (partition-triple, parent)
/// quadruple rather than a runtime test the developer must
/// remember to write per partition.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the THREE-ARRAY-COVERAGE corner on
/// the (`&'static str`) row at ONE peer const-fn helper. Combined
/// with the pre-existing (str, pairwise-distinct), (str, subset-
/// embedding), and (str, disjointness) siblings, the four contract-
/// shape corners on the (`&'static str`) row jointly close the
/// full DISJOINT-UNION theorem on any n-way partition of a
/// `&'static str` vocabulary at compile time.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// coverage sweep IS the generative shape. Every new n-way `&'static
/// str` vocabulary partition adds ONE `const _` line (plus the
/// sibling SUBSET-EMBEDDING and pairwise-DISJOINTNESS witnesses per
/// sub-array pair) to get the DISJOINT-UNION theorem rather than
/// re-deriving a per-partition runtime iterator sweep at each site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// COVERAGE proof at declaration site AND the outer-algebra's
/// twelve-arm shape-label partition regenerate through the SAME
/// `const _` witness at the ARRAY level.
///
/// Frontier inspiration: Lean 4's `Finset.disjUnion` /
/// `Finset.biUnion_eq_iff_forall_mem_exists` unfolded at the
/// concrete 3-arm `[&'static str; W] ⊆ [&'static str; N] ∪ [&'static
/// str; M] ∪ [&'static str; K]` monomorphic realisation — the
/// substrate primitive here embeds the same coverage relation as a
/// rustc const-eval-time proof obligation at every partition site
/// rather than as a Lean tactic invocation deferred to `elab_command`.
pub const fn assert_str_finite_set_covered_by_three_str_arrays<
const N: usize,
const M: usize,
const K: usize,
const W: usize,
>(
a: &[&'static str; N],
b: &[&'static str; M],
c: &[&'static str; K],
set: &[&'static str; W],
) {
// Delegate target-set well-formedness to the sibling ARRAY-side
// pairwise-distinctness helper FIRST. Placed BEFORE the SET-STR-
// MISSING sweep below because a malformed `set` (e.g. `["a", "a",
// "b"]`) is not a well-formed finite set of cardinality `W` and
// silently mis-verifies the intended COVERAGE contract — the
// duplicated byte still counts as covered on the FIRST hit even
// if the second copy is absent from the union. Routes drift on
// the CALLER'S TARGET-SET SPEC to the SET-side well-formedness
// axis rather than to a downstream SET-STR-MISSING symptom on
// `(a, b, c)`. A well-formed `set` passes this arm as a no-op —
// the sweep is const-eval-elidable and costs zero at rustc-time
// on the substrate call sites.
assert_str_array_pairwise_distinct(set);
let mut w = 0;
while w < W {
let target = set[w];
let mut found = false;
let mut i = 0;
while i < N {
if str_bytes_equal(target, a[i]) {
found = true;
break;
}
i += 1;
}
if !found {
let mut j = 0;
while j < M {
if str_bytes_equal(target, b[j]) {
found = true;
break;
}
j += 1;
}
}
if !found {
let mut k = 0;
while k < K {
if str_bytes_equal(target, c[k]) {
found = true;
break;
}
k += 1;
}
}
if !found {
panic!(
"assert_str_finite_set_covered_by_three_str_arrays: \
SET-STR-MISSING — the target finite `set` carries a \
parent entry at some position whose bytes are NOT \
reached by any of the three sub-vocabulary arrays \
`a`, `b`, `c`. The substrate's THREE-ARRAY COVERAGE \
contract on the partition-triple is broken; every \
consumer that expects the union `a ∪ b ∪ c` to span \
the parent finite vocabulary (`SexpShape::LABELS ≡ \
AtomKind::LABELS ⊕ QuoteForm::LABELS ⊕ \
StructuralKind::LABELS` on the twelve-arm outer-\
shape label partition; any future n-way disjoint-\
union theorem on the substrate's `&'static str` \
vocabularies) relies on every parent entry being \
reached by at least one sub-array. Fix at the SUB-\
VOCABULARY DECLARATION site (the missing entry is \
an intentional variant of the parent that ONE sub-\
vocabulary must carry) OR at the PARENT-VOCABULARY \
DECLARATION site (the missing entry was inadvertently \
added to the parent without extending any sub-\
vocabulary) — the choice depends on whether the \
drift is an unintended parent overshoot or an \
unintended sub-vocabulary shrinkage"
);
}
w += 1;
}
}
/// Compile-time contract verifier — panics at const evaluation time if
/// `arr` is NOT the concatenation of `K` byte-verbatim replicas of
/// `head` followed by `N - K` byte-verbatim replicas of `tail` on the
/// substrate's family-wide `[&'static str; N]` MANY-TO-ONE variant →
/// canonical-projection vocabulary. Binds ONE conjunct clause: BLOCK-
/// CONSTANCY-VIOLATION — every entry in the HEAD segment `arr[0..K)`
/// MUST byte-equal `head` and every entry in the TAIL segment
/// `arr[K..N)` MUST byte-equal `tail`.
///
/// Contract-orthogonal peer to [`assert_str_array_pairwise_distinct`]
/// on the (INJECTIVITY, MANY-TO-ONE-BLOCK-CONSTANCY) axis of the
/// (contract-shape) column on the SAME (`&'static str`) row: where the
/// pairwise-distinctness sibling binds `∀ i ≠ j : arr[i] ≠ arr[j]` at
/// compile time (INTRA-ARRAY INJECTIVITY on arrays whose per-index
/// projection is bijective with a per-index typed source), this BLOCK-
/// CONSTANCY sibling binds `arr = [head; K] ++ [tail; N - K]` at
/// compile time (INTRA-ARRAY BLOCK-CONSTANT MANY-TO-ONE PROJECTION on
/// arrays whose per-index projection is a MANY-TO-ONE pattern
/// collapsing multiple contiguous typed sources onto ONE canonical
/// scalar byte). The two helpers close the (INJECTIVITY, MANY-TO-ONE-
/// BLOCK-CONSTANCY) 2-corner face on the (`&'static str`) row at ONE
/// peer const-fn helper per structural shape; a single family-wide
/// `[&'static str; N]` array picks whichever helper matches its
/// per-index projection cardinality (a BIJECTIVE per-index projection
/// binds the pairwise-distinct sibling; a MANY-TO-ONE per-index
/// projection binds this block-constancy sibling).
///
/// The invariant is load-bearing for the substrate's typed variant →
/// canonical-projection MANY-TO-ONE closed-set surface at
/// [`crate::error::CompilerSpecIoStage::OPERATIONS`]: the four typed
/// variants of [`crate::error::CompilerSpecIoStage`] project through
/// [`crate::error::CompilerSpecIoStage::operation`] onto EXACTLY TWO
/// canonical `&'static str` operation labels
/// ([`crate::error::CompilerSpecIoStage::REALIZE_TO_DISK_OPERATION`]
/// (`"realize_to_disk"`) shared by
/// [`crate::error::CompilerSpecIoStage::RealizeToDiskSerialize`] and
/// [`crate::error::CompilerSpecIoStage::RealizeToDiskWrite`];
/// [`crate::error::CompilerSpecIoStage::LOAD_FROM_DISK_OPERATION`]
/// (`"load_from_disk"`) shared by
/// [`crate::error::CompilerSpecIoStage::LoadFromDiskRead`] and
/// [`crate::error::CompilerSpecIoStage::LoadFromDiskDeserialize`]).
/// The `[REALIZE, REALIZE, LOAD, LOAD]` block-constant shape encodes
/// the compound-key `"{operation}: {stage}"` surface's 2-of-2-to-2
/// partition — a regression that silently flip-flopped the projection
/// (e.g. reorder to `[REALIZE, LOAD, REALIZE, LOAD]`, drift a variant
/// slot to a distinct third operation label) would compile cleanly
/// past the sibling `_pairwise_distinct` exclusion (this array is
/// INTENTIONALLY non-injective, so the pairwise-distinct helper does
/// NOT bind it) and only fail at test time via the runtime pin
/// `compiler_spec_io_stage_operations_align_with_all_by_index`; post-
/// lift the ARRAY-LEVEL block-constancy binds at rustc time via ONE
/// `const _` line, one invocation stage earlier than the runtime pin.
///
/// The `K = 0` and `K = N` degenerate corners collapse the array into
/// a ONE-BLOCK replica: `K = 0` yields `arr = [tail; N]`; `K = N`
/// yields `arr = [head; N]`. Both corners pass through the same
/// sweep without a distinct code path, and both are covered by the
/// helper's test surface — a future substrate array whose per-index
/// projection collapses ALL positions onto ONE canonical byte binds
/// through either degenerate corner at ONE const-generic setting.
///
/// SET-side well-formedness: no SET-side arm here — the helper takes
/// TWO scalars, NOT a scalar plus a target-set spec, so there's no
/// SET well-formedness axis to gate on the CALLER'S input. The two
/// scalars `head` and `tail` MAY be byte-equal (in which case the
/// helper degenerates to a SINGLE-BLOCK replica-check that binds the
/// SAME constancy across all `N` positions with `head == tail`); the
/// two scalars MAY be byte-distinct (the intended TWO-BLOCK partition
/// shape). Either case is a well-formed BLOCK-CONSTANCY invariant.
///
/// CARDINALITY-MISMATCH gate: `K > N` fails FIRST at const-eval time
/// (before any per-position sweep begins) with a CARDINALITY-MISMATCH
/// arm so a caller-side turbofish arity slip on the `K` const-generic
/// routes to the CARDINALITY axis rather than silently degenerating
/// into a truncated head-only sweep. The `K == N` and `K == 0`
/// corners are LEGAL (the ONE-BLOCK degenerate shapes) so the gate
/// is `K > N`, not `K >= N`.
///
/// Adding a new family-wide `[&'static str; N]` MANY-TO-ONE variant →
/// canonical-projection array to the substrate: pair the declaration
/// with `const _: () = assert_str_array_is_concatenation_of_two_
/// scalar_replicas::<N, K>(&Self::FOO, HEAD_SCALAR, TAIL_SCALAR);`
/// co-located after the array's declaration and the block-constancy
/// contract binds at compile time. The rustc-forced arity
/// `[&'static str; N]` composes with this const-eval sweep so BOTH
/// cardinality AND per-index MANY-TO-ONE block-constancy are compile-
/// time theorems on the SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_str_array_is_concatenation_of_two_scalar_replicas_panics_
/// at_runtime_on_head_segment_drift`, `..._on_tail_segment_drift`,
/// `..._on_arity_slip`, and `..._panic_message_names_the_helper_and_
/// block_constancy_violation_axis`.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the MANY-TO-ONE variant →
/// canonical-projection block-constant contract on the `&'static
/// str` per-index projection axis becomes a TYPE-LEVEL theorem the
/// substrate carries per (arr, head, tail, K) quadruple rather than
/// a runtime iterator sweep the developer must remember to write
/// per quadruple.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the MANY-TO-ONE-BLOCK-CONSTANCY corner
/// on the (`&'static str`) row at ONE peer const-fn helper. Combined
/// with the pre-existing (`_pairwise_distinct`) INJECTIVITY sibling
/// the two helpers close the (INJECTIVITY, MANY-TO-ONE-BLOCK-
/// CONSTANCY) 2-corner face on the (`&'static str`) row — every
/// family-wide `[&'static str; N]` per-index projection array picks
/// the corner that matches its per-index projection cardinality.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// block-constant sweep IS the generative shape. Every new MANY-TO-
/// ONE variant → canonical-projection substrate closed set adds ONE
/// `const _` line to get the block-constant theorem rather than
/// re-deriving a per-projection runtime multiplicity check.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// BLOCK-CONSTANCY proof at declaration site AND the compound-key
/// `"{operation}: {stage}"` surface's partition contract regenerate
/// through the SAME `const _` witness at the ARRAY level.
///
/// Frontier inspiration: Lean 4's `List.replicate` unfolded at the
/// concrete 2-block `List.replicate K head ++ List.replicate (N - K)
/// tail` monomorphic realisation — the substrate primitive embeds
/// the same run-length shape as a rustc const-eval-time proof
/// obligation at every block-constant projection site rather than as
/// a Lean tactic invocation deferred to `elab_command`. The MANY-TO-
/// ONE variant → canonical-projection shape mirrors GHC Core's
/// constant-folding of a `case` scrutinee whose match arms collapse a
/// wider sum type onto a narrower sum type via a per-arm literal
/// projection; where GHC folds this at Core compilation, the
/// substrate binds the projection identity at rustc const-eval time.
pub const fn assert_str_array_is_concatenation_of_two_scalar_replicas<
const N: usize,
const K: usize,
>(
arr: &[&'static str; N],
head: &'static str,
tail: &'static str,
) {
if K > N {
panic!(
"assert_str_array_is_concatenation_of_two_scalar_replicas: \
CARDINALITY-MISMATCH — the two const parameters `N` and \
`K` must satisfy `K <= N` so the HEAD segment of `arr` \
(positions `[0..K)`) followed by the TAIL segment \
(positions `[K..N)`) exactly cover `arr`'s `N` \
positions. Fix at the `const _` witness's turbofish by \
reconciling the two arities against the composite's \
declared arity. The CARDINALITY-MISMATCH gate \
distinguishes THIS failure from every content-drift arm \
— a mistyped ARITY on the caller side fails HERE before \
any per-position sweep begins, so a subtle arity slip \
doesn't silently degenerate into a truncated head-only \
sweep."
);
}
let mut i = 0;
while i < K {
if !str_bytes_equal(arr[i], head) {
panic!(
"assert_str_array_is_concatenation_of_two_scalar_replicas: \
HEAD-SEGMENT-BLOCK-CONSTANCY-VIOLATION — the family-\
wide `&'static str` array `arr` carries an entry at \
some position in `[0, K)` (the HEAD segment) that \
does NOT byte-for-byte equal the peer `head` scalar. \
The substrate's HEAD-SEGMENT BLOCK-CONSTANCY \
contract on the array is broken; every consumer that \
reads `arr[0..K)` and the peer `head` scalar as \
INTERCHANGEABLE (any MANY-TO-ONE variant → \
canonical-projection consumer expecting the first \
`K` variant slots to share ONE canonical projection \
byte — e.g. the `zip(Self::ALL, Self::OPERATIONS)` \
compound-key `\"{{operation}}: {{stage}}\"` surface \
consumers on \
`crate::error::CompilerSpecIoStage::OPERATIONS` \
whose first two slots project through \
`crate::error::CompilerSpecIoStage::REALIZE_TO_DISK_\
OPERATION`) relies on this invariant. Fix at the \
ARRAY-DECLARATION site (the drifted `arr[i]` entry) \
OR at the per-role scalar constant that `head` \
re-exports — the choice depends on whether the drift \
is an unintended slot reorder inside the array or a \
rename of the canonical projection byte upstream."
);
}
i += 1;
}
let mut j = K;
while j < N {
if !str_bytes_equal(arr[j], tail) {
panic!(
"assert_str_array_is_concatenation_of_two_scalar_replicas: \
TAIL-SEGMENT-BLOCK-CONSTANCY-VIOLATION — the family-\
wide `&'static str` array `arr` carries an entry at \
some position in `[K, N)` (the TAIL segment) that \
does NOT byte-for-byte equal the peer `tail` scalar. \
The substrate's TAIL-SEGMENT BLOCK-CONSTANCY \
contract on the array is broken; every consumer that \
reads `arr[K..N)` and the peer `tail` scalar as \
INTERCHANGEABLE (any MANY-TO-ONE variant → \
canonical-projection consumer expecting the last \
`N - K` variant slots to share ONE canonical \
projection byte — e.g. the `zip(Self::ALL, \
Self::OPERATIONS)` compound-key `\"{{operation}}: \
{{stage}}\"` surface consumers on \
`crate::error::CompilerSpecIoStage::OPERATIONS` whose \
last two slots project through \
`crate::error::CompilerSpecIoStage::LOAD_FROM_DISK_\
OPERATION`) relies on this invariant. Fix at the \
ARRAY-DECLARATION site (the drifted `arr[j]` entry) \
OR at the per-role scalar constant that `tail` \
re-exports — the choice depends on whether the drift \
is an unintended slot reorder inside the array or a \
rename of the canonical projection byte upstream."
);
}
j += 1;
}
}
/// Compile-time contract verifier — panics at const evaluation time if
/// the sub-slice `full[START..START + M)` does NOT byte-equal the peer
/// sub-array `sub[..]` positionwise (`&'static str`-by-`&'static str`).
///
/// Row-dual peer of [`assert_u8_array_slice_equals_u8_array`] and
/// [`assert_char_array_slice_equals_char_array`] on the (element-type)
/// axis: where the `u8` sibling closes the outer-`Sexp` cache-key
/// discriminator sub-carving vocabulary at compile time AND the `char`
/// sibling closes the substrate's reader-boundary `[char; N]` scalar-
/// composed vocabulary at compile time, this closes the substrate's
/// family-wide `[&'static str; N]` label / prefix / tag / literal
/// vocabulary at compile time. Opens the SUB-SLICE ARRAY-image column
/// on the (str) row of the (element-type × contract-shape) matrix peer
/// to the u8-row + char-row siblings' SUB-SLICE ARRAY-image column —
/// the three helpers together lift EVERY positionwise-composition
/// contract `arr[START..START + M) == sub[..]` on scalar-family-wide
/// substrate arrays into a COMPILE-TIME theorem, one per element-type
/// row of the matrix.
///
/// The MIDDLE-SLICE corner (`0 < START`, `START + M < N`) — the shape
/// the (str) row uniquely exercises against the substrate's twelve-arm
/// [`crate::error::SexpShape::LABELS`] vocabulary — pins that each
/// sub-carving's LABELS array occupies its CANONICAL SLOTS on the
/// parent superset's declaration order, one invocation stage stronger
/// than the pre-existing SET-level DISJOINT-UNION witnesses (three
/// `assert_str_array_within_str_finite_set::<sub, 12>` embeddings,
/// three `assert_str_arrays_disjoint::<a, b>` pairwise-disjointness
/// witnesses, one `assert_str_finite_set_covered_by_three_str_arrays::
/// <6, 4, 2, 12>` coverage witness, one `assert_str_array_pairwise_
/// distinct(&SexpShape::LABELS)` INJECTIVITY witness). The SET-level
/// theorem `SexpShape::LABELS ≡ AtomKind::LABELS ⊕ QuoteForm::LABELS ⊕
/// StructuralKind::LABELS` those seven witnesses close is SILENT on
/// which SLOTS each sub-vocabulary's arms occupy — a regression that
/// permuted `SexpShape::LABELS` from
/// `[NIL, SYMBOL, KEYWORD, STRING, INT, FLOAT, BOOL, LIST, QUOTE,
/// QUASIQUOTE, UNQUOTE, UNQUOTE_SPLICE]` (`StructuralKind` at slots
/// `{0, 7}`, `AtomKind` at slots `[1..7)`, `QuoteForm` at slots
/// `[8..12)` — the CANONICAL positional decomposition) to
/// `[SYMBOL, NIL, KEYWORD, STRING, INT, FLOAT, BOOL, LIST, QUOTE,
/// QUASIQUOTE, UNQUOTE, UNQUOTE_SPLICE]` (swapping slots `0` and `1`,
/// interleaving `AtomKind` into a slot the structural-residual carving
/// previously owned) preserves the SET-level disjoint-union theorem
/// (both sub-vocabularies still embed into the parent, still cover, still
/// disjoint, parent still injective) but silently misaligns every
/// consumer indexing `SexpShape::LABELS[0]` for the NIL diagnostic
/// literal. THIS helper binds each sub-slice's positionwise composition
/// against its sub-vocabulary's canonical array at rustc time —
/// strictly STRONGER on the (contract-strength) axis than the sibling
/// SET-level DISJOINT-UNION witnesses.
///
/// Consumer sites this helper closes at the MIDDLE-SLICE corner:
/// * [`crate::error::SexpShape::LABELS`] `[0..1) ==
/// [crate::error::StructuralKind::NIL_LABEL]` — the singleton left-
/// endpoint slot of the outer twelve-shape LABELS array binds the
/// structural-residual carving's NIL role at the CANONICAL slot `0`.
/// * [`crate::error::SexpShape::LABELS`] `[1..7) == AtomKind::LABELS` —
/// the six-slot atomic-payload middle slice binds the six atomic
/// variants' LABELS at the CANONICAL slots `[1..7)`, one invocation
/// stage stronger than the (u8)-row peer at the SAME slice range
/// `[1..7)` where the six slots collapse to a single scalar
/// [`AtomKind::OUTER_HASH_DISCRIMINATOR`] byte (`1u8`) — the (str)
/// row's per-slot LABELS listing distinguishes ALL SIX slots
/// individually, so a permutation of the six atomic arms inside the
/// parent's `[1..7)` slice fails HERE where the (u8)-row's SCALAR-
/// REPLICA sibling stays silent.
/// * [`crate::error::SexpShape::LABELS`] `[7..8) ==
/// [crate::error::StructuralKind::LIST_LABEL]` — the singleton mirror-
/// endpoint slot at the atomic-collapse right endpoint binds the
/// structural-residual carving's LIST role at the CANONICAL slot `7`.
/// * [`crate::error::SexpShape::LABELS`] `[8..12) == QuoteForm::LABELS`
/// — the four-slot quote-family tail slice binds the four quote-
/// family variants' LABELS at the CANONICAL slots `[8..12)`, peer to
/// the (u8)-row's `assert_u8_array_slice_equals_u8_array::<12, 4, 8>
/// (&SexpShape::HASH_DISCRIMINATORS, &QuoteForm::HASH_DISCRIMINATORS)`
/// witness.
///
/// Together the FOUR positional witnesses cover the ENTIRE twelve-slot
/// outer container's per-position LABEL sequence at rustc time — the
/// UNION of the four disjoint slice ranges `[0..1) ∪ [1..7) ∪ [7..8) ∪
/// [8..12)` exhausts the twelve-slot outer container's position space.
/// Sibling posture to the (u8)-row's FOUR positional witnesses on
/// `SexpShape::HASH_DISCRIMINATORS` (the two singleton
/// slice-equals-array witnesses on `[0..1)` and `[7..8)`, the six-slot
/// slice-is-scalar-replica witness on `[1..7)`, the four-slot
/// slice-equals-array witness on `[8..12)`) — both rows now carry the
/// FULL positional decomposition of the twelve-slot outer container at
/// rustc time on BOTH the (u8) discriminator axis AND the (str) label
/// axis. A regression that reordered `SexpShape::LABELS` fails at BOTH
/// the (u8)-row `HASH_DISCRIMINATORS` positional witnesses (through
/// the parallel outer twelve-slot ordering) AND the (str)-row LABELS
/// positional witnesses lifted here.
///
/// Pre-lift the twelve-arm `SexpShape::LABELS` positional decomposition
/// lived ONLY through the runtime cross-check
/// `sexp_shape_labels_align_with_sub_vocabularies_by_position` (in
/// `error.rs`, sweeping the twelve positions and routing each
/// `SexpShape::LABELS[i]` through its sub-vocabulary via
/// `SexpShape::ALL[i].as_atom_kind() / .as_quote_form()` composition);
/// post-lift the ARRAY-LEVEL positional decomposition binds at rustc
/// time via FOUR `const _` lines, one invocation stage earlier than
/// the runtime pin. A regression that reorders the outer
/// `SexpShape::LABELS` array's initializer (e.g. swapping slot `0`'s
/// `Self::NIL_LABEL` with slot `1`'s `Self::SYMBOL_LABEL`) while
/// leaving each sub-vocabulary in its canonical order fails at
/// `cargo check` BEFORE any test scheduler runs.
///
/// The three axis-partitioned panic messages (`START-OUT-OF-BOUNDS`,
/// `SLICE-LENGTH-OUT-OF-BOUNDS`, `STR-SLICE-EQUALS-ARRAY-VIOLATION`)
/// mirror the u8 sibling's message vocabulary with the `STR-` prefix
/// on the CONTENT-drift axis so callers grep either the (u8) row's
/// plain `SLICE-EQUALS-ARRAY-VIOLATION`, the (char) row's
/// `CHAR-SLICE-EQUALS-ARRAY-VIOLATION`, or the (str) row's
/// `STR-SLICE-EQUALS-ARRAY-VIOLATION` axis-prefix by element-type. The
/// shared `-SLICE-EQUALS-ARRAY-VIOLATION` infix lets callers grep any
/// element-type variant by the shared axis substring.
///
/// Adding a new family-wide `[&'static str; N]` array to the substrate
/// whose declaration is a positionwise composition against named per-
/// role `pub const *_LABEL` / `*_PREFIX` / `*_TAG` `&'static str`
/// constants: pair the declaration with `const _: () =
/// assert_str_array_slice_equals_str_array::<N, M, START>(&Self::FOO_
/// ARRAY, &Self::SUB_ARRAY);` co-located after the array's declaration
/// and the per-slot ORDER contract binds at compile time. The rustc-
/// forced arities `[&'static str; N]` + `[&'static str; M]` compose
/// with this const-eval sweep so BOTH cardinality AND per-slot
/// canonical-str-value are compile-time theorems on the SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP surface
/// that constructs a `[&'static str; N]` at runtime from a user-
/// supplied vocabulary and wants to verify positionwise composition
/// against a peer sub-array before consuming it — and the panic
/// surfaces normally in that path (pinned by
/// `assert_str_array_slice_equals_str_array_panics_at_runtime_on_positionwise_drift`,
/// `assert_str_array_slice_equals_str_array_panics_at_runtime_on_start_out_of_bounds`,
/// `assert_str_array_slice_equals_str_array_panics_at_runtime_on_slice_length_out_of_bounds`,
/// AND
/// `assert_str_array_slice_equals_str_array_panic_message_names_the_helper_and_str_slice_equals_array_violation_axis`).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide per-position
/// ORDER contract on the `&'static str`-typed vocabulary becomes a
/// TYPE-LEVEL theorem the substrate carries per array declaration
/// rather than a runtime iterator sweep the developer must remember
/// to write per array.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// positionwise sweep IS the generative shape. Every new closed-set
/// string array declared as a positionwise composition against
/// named-per-role `pub const` labels adds ONE `const _` line to get
/// the per-slot ORDER theorem rather than re-deriving a runtime
/// index-by-index `assert_eq!` block per array.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// per-slot-ORDER proof at declaration site AND the per-role
/// `pub const *_LABEL` alias-chain composition every consumer relies
/// on regenerate through the SAME `const _` witness.
pub const fn assert_str_array_slice_equals_str_array<
const N: usize,
const M: usize,
const START: usize,
>(
full: &[&'static str; N],
sub: &[&'static str; M],
) {
if START > N {
panic!(
"assert_str_array_slice_equals_str_array: START-OUT-OF-\
BOUNDS — the const parameter `START` sits OUTSIDE the \
outer array's valid position range `[0..N]` (inclusive \
upper bound: `START == N` combined with `M == 0` is the \
LEGAL empty-slice-at-right-endpoint corner). Fix at the \
`const _` witness's turbofish by reconciling `START` \
against the outer array's declared arity `N`. The \
START-OUT-OF-BOUNDS gate fires FIRST — a mistyped \
`START` on the caller side fails HERE before the peer \
`SLICE-LENGTH-OUT-OF-BOUNDS` gate reads `N - START` \
(which would underflow `usize` had this gate not caught \
the slip), so a subtle bounds slip doesn't silently \
degenerate into a subtraction wrap-around OR a panic \
deeper in `full[START + i]` bounds-checking."
);
}
if M > N - START {
panic!(
"assert_str_array_slice_equals_str_array: SLICE-LENGTH-\
OUT-OF-BOUNDS — the peer sub-array's arity `M` exceeds \
the outer array's tail cardinality `N - START`, so the \
positionwise sweep `full[START + i]` for `i ∈ [0..M)` \
would overrun the outer array's valid position range \
`[0..N)` at some `i ∈ [N - START..M)`. Fix at the \
`const _` witness's turbofish by reconciling `M` against \
the outer array's tail cardinality `N - START` OR by \
narrowing `START` to leave a longer tail. The peer \
`START-OUT-OF-BOUNDS` gate above guarantees `START ≤ N` \
so `N - START` never underflows `usize` at this gate. \
The LEGAL exact-fit corner `M == N - START` (the sub-\
array reaches EXACTLY to the outer array's right \
endpoint) is accepted; the STRICT `M > N - START` slip \
is what this gate rejects."
);
}
let mut i = 0;
while i < M {
if !str_bytes_equal(full[START + i], sub[i]) {
panic!(
"assert_str_array_slice_equals_str_array: STR-SLICE-\
EQUALS-ARRAY-VIOLATION — the outer `[&'static str; \
N]` array `full` carries a str at some position \
`START + i` (for `i ∈ [0..M)`) that does NOT byte-\
equal the peer `[&'static str; M]` sub-array `sub` \
at the offset-matched position `i`. The substrate's \
SLICE-EQUALS-ARRAY positionwise-composition contract \
on the sub-slice `full[START..START + M) == sub[..]` \
is broken; every consumer that reads `full[START..\
START + M)` as a positionwise-aligned copy of a peer \
sub-vocabulary's canonical `[&'static str; M]` \
listing (the twelve-slot outer container \
`crate::error::SexpShape::LABELS` whose four \
canonical sub-slices `[0..1) == \
[crate::error::StructuralKind::NIL_LABEL]`, `[1..7) \
== AtomKind::LABELS`, `[7..8) == [crate::error::\
StructuralKind::LIST_LABEL]`, `[8..12) == \
QuoteForm::LABELS` compose the parent LABELS \
vocabulary from the three sub-carvings' LABELS \
arrays; any future container-array sub-slice byte-\
for-byte equal to a peer sub-carving's canonical \
`[&'static str; M]` listing) relies on this \
invariant. Fix at the ARRAY-DECLARATION site (the \
drifted `full[START + i]` entry inside the slice \
segment) OR at the peer sub-array's arm listing — \
the choice depends on whether the drift is an \
unintended slot reorder in the outer array's tail \
OR in the sub-carving's own listing."
);
}
i += 1;
}
}
/// Compile-time contract verifier — panics at const evaluation time if
/// any two entries of `arr` alias byte-for-byte.
///
/// Column-dual peer to [`assert_char_array_pairwise_distinct`] and
/// [`assert_str_array_pairwise_distinct`] on the (element-type) axis:
/// where the `char` sibling closes the reader-boundary `[char; N]`
/// vocabulary at compile time and the `&'static str` sibling closes
/// the outer-algebras' family-wide label / prefix / tag / literal
/// vocabularies, this closes the substrate's family-wide `[u8; N]`
/// cache-key discriminator vocabulary. The three helpers together
/// lift EVERY `pub const` scalar-family-wide array declared on the
/// substrate's closed-set outer algebras (`Sexp` / `Atom` /
/// `AtomKind` / `QuoteForm` / `StructuralKind` / `UnquoteForm`) into
/// a COMPILE-TIME pairwise-distinctness theorem — a regression that
/// silently collides two entries fails the build at `cargo check`
/// time, one invocation stage earlier than the test-run pin.
///
/// The invariant is load-bearing for the outer-`Sexp` cache-key
/// algebra: every consumer that pattern-matches the array's entries
/// as DISJOINT arms of a hash-discriminator projection —
/// [`AtomKind::hash_discriminator`]'s six-arm `{0..=5}` byte partition
/// under [`Hash for Atom`](crate::ast::Atom); [`QuoteForm::hash_discriminator`]'s
/// four-arm `{3, 4, 5, 6}` byte partition under
/// [`Hash for Sexp`](crate::ast::Sexp); [`crate::error::StructuralKind::hash_discriminator`]'s
/// two-arm `{0, 2}` byte partition under the outer-`Sexp` cache-key
/// algebra's structural-residual carve; AND
/// [`crate::error::UnquoteForm::hash_discriminator`]'s two-arm byte
/// partition on the substitution-subset carving — relies on this
/// invariant. A duplicate here would silently collide two DISTINCT
/// variants at the SAME cache-key byte, breaking the `Expander::cache`
/// keying on `(macro_name, args)` hash and mis-hashing every cached
/// expansion across the collided variants.
///
/// Pre-lift each of these four arrays carried its pairwise-
/// distinctness contract at a runtime test
/// (`atom_kind_hash_discriminators_pairwise_distinct`,
/// `quote_form_hash_discriminators_pairwise_distinct`,
/// `structural_kind_hash_discriminators_pairwise_distinct`,
/// `unquote_form_hash_discriminators_pairwise_distinct`); post-lift
/// the pairwise-distinctness contract binds at `cargo check` time,
/// one invocation stage earlier, catching regressions on `cargo
/// build` / `cargo clippy` runs that skip the test suite.
///
/// NB: [`crate::error::SexpShape::HASH_DISCRIMINATORS`] (`[u8; 12]`)
/// is INTENTIONALLY excluded from this compile-time sweep — the
/// twelve outer shapes DELIBERATELY collapse onto only SEVEN outer
/// cache-key bytes `{0..=6}` (the six atomic shapes all map to `1`
/// per the outer-Sexp `Atom` marker byte, per the collapse rule
/// documented on [`AtomKind::OUTER_HASH_DISCRIMINATOR`]). A
/// pairwise-distinctness pin there would fire correctly, matching
/// the load-bearing non-injectivity that closes the twelve-arm
/// shape space onto the seven-arm outer-Sexp cache-key space.
///
/// Adding a new family-wide `[u8; N]` array to the substrate: pair
/// the declaration with `const _: () = assert_u8_array_pairwise_
/// distinct(&Self::FOO_ARRAY);` co-located after the array's
/// declaration and the distinctness contract is enforced at
/// compile time. The rustc-forced arity `[u8; N]` composes with
/// this const-eval sweep so BOTH cardinality AND injectivity are
/// compile-time theorems on the SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_array_pairwise_distinct_panics_at_runtime_on_binary_
/// collision`. Unlike [`assert_str_array_pairwise_distinct`] this
/// helper needs no auxiliary byte-equality helper: `u8` supports
/// `==` directly in const-fn context, collapsing the triangular
/// pair sweep to a two-loop shape without an inner byte walk.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide
/// distinctness contract on the `u8` cache-key vocabulary becomes
/// a TYPE-LEVEL theorem the substrate carries per array
/// declaration rather than a runtime test the developer must
/// remember to write per array.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the discriminator arrays on the typed algebra makes
/// attestation-key drift a compile error rather than a silent
/// BLAKE3 mis-hash on any consumer keyed on `Hash for Sexp`.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// sweep IS the generative shape. Every new closed-set
/// discriminator array adds ONE `const _` line to get the
/// distinctness theorem rather than re-deriving a per-array
/// runtime iterator sweep.
pub const fn assert_u8_array_pairwise_distinct<const N: usize>(arr: &[u8; N]) {
let mut i = 0;
while i < N {
let mut j = i + 1;
while j < N {
if arr[i] == arr[j] {
panic!(
"assert_u8_array_pairwise_distinct: family-wide \
u8 array carries a duplicate entry across two \
positions — the substrate's pairwise-\
distinctness contract on the array is broken; \
every consumer that pattern-matches the array's \
entries as DISJOINT arms (Atom / Sexp cache-key \
hash-discriminator projection, structural-\
residual / quote-family / substitution-subset \
byte partition) relies on this invariant",
);
}
j += 1;
}
i += 1;
}
}
// Compile-time pairwise-distinctness on family-wide `[u8; N]` hash-
// discriminator arrays no longer surfaces at this level as DIRECT
// witnesses — every family-wide `[u8; N]` HASH_DISCRIMINATORS array
// whose INJECTIVITY contract binds now does so through ONE of the two
// stronger COMPOUND (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) permutation
// helpers defined below (`assert_u8_array_permutes_inclusive_range` on
// the CONTIGUOUS-INCLUSIVE-RANGE corner of the (contiguity) axis at
// `AtomKind::HASH_DISCRIMINATORS` / `QuoteForm::HASH_DISCRIMINATORS` /
// `UnquoteForm::HASH_DISCRIMINATORS`; `assert_u8_array_permutes_
// finite_set` on the NON-CONTIGUOUS-FINITE-SET corner at
// `StructuralKind::HASH_DISCRIMINATORS`), each of which delegates
// through this pairwise-distinct helper for the INJECTIVITY arm — the
// helper is now purely a delegation target. `SexpShape::HASH_
// DISCRIMINATORS` is intentionally OMITTED from BOTH compound helpers
// per the intentionally-non-injective twelve-shape → seven-byte
// collapse rule documented on the helper above — INJECTIVITY does not
// hold, so no permutation contract can bind on any contiguity corner
// (its SURJECTIVITY-only contract binds through the single-axis
// `assert_u8_array_covers_inclusive_range` sibling further below).
//
// Adding a new family-wide `[u8; N]` permutation-shaped HASH_
// DISCRIMINATORS array: prefer the compound helpers below
// (`_permutes_inclusive_range` for the contiguous-range corner or
// `_permutes_finite_set` for the non-contiguous-finite-set corner)
// which bind INJECTIVITY ∧ SURJECTIVITY ∧ ARITY at ONE `const _` line;
// fall back to a DIRECT `const _: () = assert_u8_array_pairwise_
// distinct(&Self::FOO_ARRAY);` witness at this level ONLY for an array
// that is intentionally injective but whose distinct-value set is
// NEITHER a contiguous inclusive range NOR a known finite set (a
// hypothetical looser-contract case not currently exercised by any
// substrate array). Sibling to the runtime `_hash_discriminators_
// pairwise_distinct` tests at `ast.rs` + `error.rs`'s tests modules —
// those enforce the same theorem at `cargo test` time through direct
// runtime calls to this helper, so the theorem is still bound at
// TWO stages of the toolchain (compile time through the delegated
// path inside the compound helpers, test time through the direct
// runtime calls). Peer to the seven `assert_char_array_pairwise_
// distinct` witnesses AND the thirteen `assert_str_array_pairwise_
// distinct` witnesses above on the (element-type) axis: `char`
// covers the reader-boundary vocabulary; `&'static str` covers the
// closed-set outer-algebras' label / prefix / tag / literal
// vocabularies; `u8` (via the compound helpers below) covers the
// outer-`Sexp` cache-key discriminator vocabulary.
/// Compile-time contract verifier — panics at const evaluation time if
/// any two entries of `arr` share their LEFT `char` column OR their
/// RIGHT `char` column, i.e. binds the `[(char, char); N]` array as a
/// BIJECTION on the substrate's escape-table product-vocabulary.
///
/// Product-element sibling to the scalar-element trio
/// ([`assert_char_array_pairwise_distinct`],
/// [`assert_str_array_pairwise_distinct`], and
/// [`assert_u8_array_pairwise_distinct`]) on the (element-type) axis:
/// where the three scalar-element helpers close every family-wide
/// SINGLE-column array declared on the substrate's closed-set outer
/// algebras (`Sexp` / `Atom` / `AtomKind` / `QuoteForm` /
/// `StructuralKind` / `UnquoteForm` on the reader-boundary + label +
/// prefix + tag + cache-key vocabularies), this closes the substrate's
/// family-wide TWO-column `[(char, char); N]` bijection tables at
/// compile time. A `[(char, char); N]` array is a bijection iff BOTH
/// column projections are pairwise-distinct (LEFT-column injectivity
/// witnesses that `source → decoded` is a well-defined function on
/// distinct sources; RIGHT-column injectivity witnesses that
/// `decoded → source` inverts unambiguously) — since |LEFT| = |RIGHT| =
/// N is finite, the conjunction of the two injectivities IS bijectivity
/// on the paired substrate vocabulary.
///
/// The invariant is load-bearing for the Str-payload escape-table
/// tokenization boundary. [`Atom::NAMED_ESCAPE_TABLE`] (`[(char, char);
/// 3]`, the three pattern-DISTINCT-from-value named-escape rows —
/// `'n' → '\n'`, `'t' → '\t'`, `'r' → '\r'`) is the paired algebra
/// [`Atom::decode_str_escape`]'s three named arms dispatch through; a
/// LEFT-column collision would silently route two escape sequences
/// through the first-matching decoded byte (e.g. a drift of
/// `TAB_ESCAPE_SOURCE` to `'n'` would collapse `\t` and `\n` at the
/// same source arm), and a RIGHT-column collision would collapse two
/// distinct decoded bytes onto ONE (e.g. a drift of `TAB_ESCAPE_DECODED`
/// to `'\n'` would emit `\n` on BOTH `\t` and `\n` in the tokenized
/// payload). [`Atom::ESCAPE_TABLE`] (`[(char, char); 5]`, the
/// composite paired SPAN over the three named + two self-escape rows)
/// binds the SAME bijection at the composite level; a LEFT-column
/// collision AT THE COMPOSITE would witness cross-sub-vocabulary
/// aliasing (a named-escape source colliding with a self-escape
/// source, e.g. `'n'` = `Self::STR_DELIMITER`), and a RIGHT-column
/// collision would witness the same at the DECODED axis. Every future
/// family-wide `[(char, char); N]` paired substrate array participates
/// in the SAME compile-time guarantee via one `const _` line.
///
/// Pre-lift each of these two bijection tables carried its
/// column-wise pairwise-distinctness contract at TWO runtime tests
/// (`atom_named_escape_table_sources_pairwise_distinct` +
/// `atom_named_escape_table_decoded_pairwise_distinct` on the
/// NAMED_ESCAPE_TABLE arm; the composite `atom_escape_table_
/// sources_and_decoded_columns_pairwise_distinct` on the ESCAPE_TABLE
/// arm); post-lift the CONJOINED bijectivity contract binds at `cargo
/// check` time — the const-eval panic surfaces the collision at
/// COMPILE time, one invocation stage earlier, catching regressions
/// on `cargo build` / `cargo clippy` runs that skip the test suite.
///
/// Adding a new family-wide `[(char, char); N]` paired array to the
/// substrate: pair the declaration with `const _: () =
/// assert_char_pair_array_bijective(&Self::FOO_TABLE);` co-located
/// after the declaration and the BIJECTION contract binds at compile
/// time. The rustc-forced arity `[(char, char); N]` composes with this
/// const-eval sweep so cardinality AND left-column injectivity AND
/// right-column injectivity are ALL compile-time theorems on the SAME
/// array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP tokenizer
/// that constructs a `[(char, char); N]` at runtime and wants to
/// verify bijectivity before consuming it — and the two panic sites
/// (LEFT-column collision, RIGHT-column collision) surface normally in
/// that path with column-provenance-preserving panic messages
/// (pinned by
/// `assert_char_pair_array_bijective_panics_at_runtime_on_left_
/// column_collision` +
/// `assert_char_pair_array_bijective_panics_at_runtime_on_right_
/// column_collision`).
///
/// Column-provenance in the panic message is load-bearing: downstream
/// diagnostics (`cargo check` const-eval error output, test-suite
/// failure reports) route the drift back to the failed COLUMN (LEFT
/// source vs. RIGHT decoded) by string search — a bijection failure
/// on a `[(char, char); N]` table names WHICH column collapsed,
/// halving the search space for the operator debugging the drift.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide bijectivity
/// contract on the `(char, char)` paired escape-table vocabulary
/// becomes a TYPE-LEVEL theorem the substrate carries per paired-
/// array declaration rather than a two-runtime-test pair the
/// developer must remember to write per array (one per column).
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// bijection proof at declaration site AND the outer-dispatch
/// match-arm exhaustiveness at [`Atom::decode_str_escape`]'s five
/// arms regenerate through the SAME `const _` witness.
/// - THEORY.md §VI.1 — generation over composition; the two-column
/// const-eval sweep IS the generative shape. Every new closed-set
/// paired-array vocabulary adds ONE `const _` line to get the
/// bijection theorem rather than re-deriving TWO per-column
/// iterator sweeps at runtime.
pub const fn assert_char_pair_array_bijective<const N: usize>(arr: &[(char, char); N]) {
let mut i = 0;
while i < N {
let mut j = i + 1;
while j < N {
if arr[i].0 as u32 == arr[j].0 as u32 {
panic!(
"assert_char_pair_array_bijective: LEFT column of \
family-wide `[(char, char); N]` paired substrate \
array carries a duplicate SOURCE char across two \
positions — the substrate's LEFT-column pairwise-\
distinctness contract (source-column injectivity, \
i.e. `source → decoded` is a well-defined \
function on distinct sources) is broken; every \
consumer that pattern-matches the array's SOURCE \
column as DISJOINT arms (Atom::decode_str_escape \
escape-source outer dispatch, ESCAPE_SOURCES \
column-dual SPAN projection) relies on this \
invariant"
);
}
if arr[i].1 as u32 == arr[j].1 as u32 {
panic!(
"assert_char_pair_array_bijective: RIGHT column of \
family-wide `[(char, char); N]` paired substrate \
array carries a duplicate DECODED char across two \
positions — the substrate's RIGHT-column \
pairwise-distinctness contract (decoded-column \
injectivity, i.e. `source → decoded` inverts \
unambiguously through `decoded → source` on the \
finite paired vocabulary) is broken; every \
consumer that enumerates the array's DECODED \
column as a disjoint alphabet (ESCAPE_DECODED \
column-dual SPAN projection, escape-family \
decoded-byte enumeration) relies on this \
invariant"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time bijectivity witnesses — one `const _: () =
// assert_char_pair_array_bijective(&…)` per family-wide `[(char, char);
// N]` paired escape-table array on the substrate's Str-payload
// tokenization boundary. Each invocation is const-evaluated at `cargo
// check` time; a regression that silently collided two entries at
// EITHER the LEFT source column OR the RIGHT decoded column fails the
// build rather than the test suite. Sibling to the runtime
// `_pairwise_distinct` tests at `ast::tests` (`atom_named_escape_
// table_sources_pairwise_distinct`, `atom_named_escape_table_decoded_
// pairwise_distinct`, `atom_escape_table_sources_and_decoded_columns_
// pairwise_distinct`) — the two enforce the same theorem at TWO
// stages of the toolchain, so a build that skips tests still catches
// the regression here, and a build that runs tests catches it a
// second time as a safety net if the const-eval sweep is ever
// silently dropped. Peer to the seven `assert_char_array_pairwise_
// distinct` + thirteen `assert_str_array_pairwise_distinct` + four
// `assert_u8_array_pairwise_distinct` witnesses above on the
// (element-type) axis: the three scalar-element helpers close every
// family-wide SINGLE-column array; this product-element helper closes
// the family-wide TWO-column paired escape-table arrays.
const _: () = assert_char_pair_array_bijective(&Atom::NAMED_ESCAPE_TABLE);
const _: () = assert_char_pair_array_bijective(&Atom::ESCAPE_TABLE);
/// Compile-time contract verifier — panics at const evaluation time if
/// the family-wide `[(char, char); N]` paired substrate array `arr`
/// carries a pair at some position whose `(SOURCE, DECODED)` tuple is
/// NOT a member of the target finite superset paired-array partition
/// `set`. Binds ONE conjunct clause on the `(char, char)` product-
/// element row of the (element-type × contract-shape) matrix at the
/// (subset-embedding) column — CHAR-PAIR-SUBSET-VIOLATION — every
/// entry of `arr` MUST be a byte-for-byte-equal `(char, char)` pair
/// found somewhere in `set` (ORIENTED across the two arguments — the
/// SUBSET side `arr` vs the SUPERSET side `set`). Pair equality is
/// CONJOINED across BOTH columns: `arr[i] == set[j]` iff `arr[i].0 ==
/// set[j].0 AND arr[i].1 == set[j].1` — a per-column membership check
/// on either column alone would silently accept a pair whose LEFT
/// column matches ONE set entry and RIGHT column matches a DIFFERENT
/// set entry (a cross-row aliasing collision the CONJOINED-pair
/// contract catches).
///
/// Delegates target-set well-formedness to the sibling
/// [`assert_char_pair_array_bijective`] helper FIRST (peer to the
/// (char, u8, `&'static str`) scalar rows' delegation to the SCALAR
/// pairwise-distinct sibling — the well-formedness delegation lifts
/// TO THE `(char, char)` row through the strongest well-formedness
/// contract on the row, which is BIJECTIVITY on the paired array). A
/// malformed `set` (e.g. `[('a', 'x'), ('a', 'y')]` — LEFT-column
/// collision, or `[('a', 'x'), ('b', 'x')]` — RIGHT-column collision)
/// routes to the SET-side BIJECTIVITY panic (via the sibling's own
/// panic-name prefix) BEFORE the CHAR-PAIR-SUBSET-VIOLATION sweep
/// silently mis-verifies against the distinct-value bijective subset.
/// A well-formed `set` passes this arm as a no-op — the sweep is
/// const-eval-elidable and costs zero at rustc-time on the substrate
/// call sites.
///
/// The substrate binds the paired-array SUBSET theorem at ONE
/// intentionally-closed `(char, char)` sub-vocabulary pair: [`Atom::
/// NAMED_ESCAPE_TABLE`] (`[(char, char); 3]`, the three pattern-
/// DISTINCT-from-value named-escape rows — `'n' → '\n'`, `'t' → '\t'`,
/// `'r' → '\r'`) ⊂ [`Atom::ESCAPE_TABLE`] (`[(char, char); 5]`, the
/// composite paired SPAN over the three named + two self-escape rows).
/// Pre-lift the SUBSET relation lived only implicitly at the composite
/// array's declaration site (`Self::NAMED_ESCAPE_TABLE[0]`,
/// `Self::NAMED_ESCAPE_TABLE[1]`, `Self::NAMED_ESCAPE_TABLE[2]`
/// indexing into the composite's first three positions); post-lift
/// the ARRAY-LEVEL subset embedding binds at rustc time via ONE
/// `const _` line. A regression that silently re-inlined either the
/// SUBSET or the SUPERSET side of the relation to a fresh pair
/// breaking the subset containment (e.g. dropping `NEWLINE` from
/// `NAMED_ESCAPE_TABLE` while keeping it as a `Self::NAMED_ESCAPE_
/// TABLE[0]` index in `ESCAPE_TABLE`; drifting `Self::TAB_ESCAPE_
/// SOURCE` on the NAMED side to a fresh char not present at the
/// composite's second position; re-shuffling the composite's first
/// three positions to swap with the SELF-escape suffix bytes) fails
/// at `cargo check` BEFORE any test scheduler runs.
///
/// Row-dual peer to
/// [`assert_char_array_within_char_finite_set`] +
/// [`assert_u8_array_within_u8_finite_set`] +
/// [`assert_str_array_within_str_finite_set`] on the (element-type)
/// axis of the SAME (subset-embedding) contract-shape column: where
/// the three sibling helpers close the SCALAR (`char`, `u8`,
/// `&'static str`) rows at ONE peer helper per row, this helper
/// opens the PRODUCT-ELEMENT `(char, char)` row on the same column
/// — extending the (element-type × contract-shape) matrix's
/// (subset-embedding) column past the three scalar rows onto the
/// paired-array row.
///
/// Contract-orthogonal peer to
/// [`assert_char_pair_array_bijective`] on the (BIJECTIVITY,
/// SUBSET-EMBEDDING) axis of the (contract-shape) column on the SAME
/// `(char, char)` row: where the BIJECTIVITY sibling binds
/// (LEFT-column INJECTIVITY ∧ RIGHT-column INJECTIVITY) on the SAME
/// array, this SUBSET-EMBEDDING sibling binds (CONJOINED-pair
/// membership) across TWO arrays. Together the two helpers close the
/// (paired-array well-formedness, paired-array subset) 2-corner face
/// on the `(char, char)` row.
///
/// Panic message carries the axis-provenance-named
/// `"CHAR-PAIR-SUBSET-VIOLATION"` string chosen DISTINCT from every
/// sibling helper's axis vocabulary (`"CHAR-SUBSET-VIOLATION"` on the
/// (char) scalar row-dual SUBSET peer; `"SUBSET-VIOLATION"` on the
/// (u8) row-dual finite-set SUBSET peer; `"STR-SUBSET-VIOLATION"` on
/// the (`&'static str`) row-dual SUBSET peer; `"RANGE-SUBSET-
/// VIOLATION"` on the (u8) range SUBSET peer; `"CHAR-DISJOINTNESS-
/// VIOLATION"` / `"U8-DISJOINTNESS-VIOLATION"` / `"STR-DISJOINTNESS-
/// VIOLATION"` on the DISJOINTNESS-column row peers; `"LEFT column"`
/// / `"RIGHT column"` on the paired-array BIJECTIVITY sibling). The
/// `"CHAR-PAIR-"` prefix disambiguates from the (char) SCALAR row-
/// dual SUBSET peer; the shared `"-SUBSET-VIOLATION"` suffix lets
/// callers grep any row's SUBSET-embedding sibling by the shared
/// suffix alone.
///
/// Adding a new family-wide `[(char, char); N]` paired-array
/// intentionally-closed SUBSET carving of another substrate
/// `[(char, char); M]` paired array to the substrate: pair the
/// declaration with `const _: () =
/// assert_char_pair_array_within_char_pair_finite_set::<N, M>(
/// &Self::FOO_SUB_TABLE, &Self::FOO_SUPER_TABLE);` co-located after
/// the SUBSET-side declaration and the paired-array SUBSET-embedding
/// contract binds at compile time. The rustc-forced arity
/// `[(char, char); N] × [(char, char); M]` composes with this const-
/// eval sweep so cardinality AND SUBSET-embedding are BOTH compile-
/// time theorems on the SAME pair.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_char_pair_array_within_char_pair_finite_set_panics_at_
/// runtime_on_out_of_set_entry` +
/// `assert_char_pair_array_within_char_pair_finite_set_panic_message_
/// names_the_helper_and_char_pair_subset_violation_axis`.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide paired-array
/// SUBSET-embedding contract on `(char, char)` sub-vocabularies
/// becomes a TYPE-LEVEL theorem the substrate carries per (arr,
/// set) `[(char, char); N] × [(char, char); M]` pair rather than a
/// runtime test per pair.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix's (SUBSET-EMBEDDING) column now carries the
/// PRODUCT-ELEMENT `(char, char)` row alongside the three scalar
/// rows at ONE peer const-fn helper per row.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// SUBSET-EMBEDDING proof at declaration site AND the outer-
/// algebra's paired-array partition contract regenerate through
/// the SAME `const _` witness at the ARRAY level.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// CONJOINED-pair membership sweep IS the generative shape — every
/// new `(char, char)` sub-vocabulary paired array whose distinct-
/// value set is an intentionally-closed subset of another substrate
/// paired array adds ONE `const _` line.
pub const fn assert_char_pair_array_within_char_pair_finite_set<const N: usize, const M: usize>(
arr: &[(char, char); N],
set: &[(char, char); M],
) {
// Delegate target-set well-formedness to the sibling paired-
// array BIJECTIVITY helper FIRST. Placed BEFORE the CHAR-PAIR-
// SUBSET-VIOLATION sweep below because a malformed `set` (e.g.
// `[('a', 'x'), ('a', 'y')]` — LEFT-column collision; or
// `[('a', 'x'), ('b', 'x')]` — RIGHT-column collision) is not a
// well-formed finite bijective set of paired-cardinality `M` and
// silently mis-verifies the intended SUBSET contract on any
// `arr` embedded in the distinct-value bijective subset. Routes
// drift on the CALLER'S TARGET-SET SPEC to the SET-side
// well-formedness axis (via the sibling's own panic-name
// prefix) rather than to a downstream CHAR-PAIR-SUBSET-VIOLATION
// symptom on `arr`. A well-formed `set` passes this arm as a no-
// op — the sweep is const-eval-elidable and costs zero at
// rustc-time on the substrate call sites.
assert_char_pair_array_bijective(set);
let mut i = 0;
while i < N {
let mut j = 0;
let mut found = false;
while j < M {
// CONJOINED-pair equality — BOTH columns must match the
// SAME `set[j]` entry. A per-column membership check on
// either column alone (e.g. `arr[i].0 in set.map(|p|
// p.0)` AND separately `arr[i].1 in set.map(|p| p.1)`)
// would silently accept a cross-row aliasing collision
// where `arr[i].0 == set[j1].0` for some `j1` AND
// `arr[i].1 == set[j2].1` for some DIFFERENT `j2` while
// `arr[i]` itself is NOT in `set` (a pair the CONJOINED
// gate rejects).
if arr[i].0 as u32 == set[j].0 as u32 && arr[i].1 as u32 == set[j].1 as u32 {
found = true;
break;
}
j += 1;
}
if !found {
panic!(
"assert_char_pair_array_within_char_pair_finite_set: \
CHAR-PAIR-SUBSET-VIOLATION — the family-wide \
`[(char, char); N]` paired substrate array `arr` \
carries a pair at some position whose (SOURCE, \
DECODED) tuple is NOT a byte-for-byte-equal member \
of the target finite superset paired-array \
partition `set`. The substrate's paired-array \
SUBSET-EMBEDDING contract on `arr` is broken; every \
consumer that expects the paired array's distinct-\
value set of `(SOURCE, DECODED)` tuples to be a \
subset of the target finite superset paired \
partition (`Atom::NAMED_ESCAPE_TABLE ⊂ Atom::\
ESCAPE_TABLE` on the pattern-DISTINCT-from-value \
sub-vocabulary axis of the paired escape-arm SPAN; \
any future typed-paired-subset embedding on the \
substrate's reader-boundary `(char, char)` \
algebras) relies on every array pair staying within \
the target paired superset. Fix at the SUBSET-side \
ARRAY-DECLARATION site (the `arr` under \
verification, NOT the `set` argument specifying the \
target superset) by dropping the offending pair OR \
by extending `set` to cover it — the choice depends \
on whether the drift is an unintended overshoot \
outside the parent superset or an intentional \
extension of the superset paired vocabulary. The \
CONJOINED-pair equality gate distinguishes THIS \
helper from a per-column membership check that \
would silently accept a cross-row aliasing pair \
(`arr[i].0` matches ONE set entry's LEFT column \
while `arr[i].1` matches a DIFFERENT set entry's \
RIGHT column) — the CONJOINED gate rejects the \
pair unless BOTH columns match the SAME `set[j]`"
);
}
i += 1;
}
}
// Compile-time SUBSET-embedding witness — the ONE intentionally-
// closed `[(char, char); N] ⊂ [(char, char); M]` paired sub-
// vocabulary carving on the substrate's Str-payload tokenization
// boundary whose distinct-value set of `(SOURCE, DECODED)` tuples
// is a subset of another family-wide paired substrate array's
// distinct-value set. Pre-lift the SUBSET relation lived only
// implicitly at the composite `Atom::ESCAPE_TABLE`'s declaration
// site (`Self::NAMED_ESCAPE_TABLE[0]`, `Self::NAMED_ESCAPE_TABLE[1]`,
// `Self::NAMED_ESCAPE_TABLE[2]` indexing into the composite's first
// three positions). Post-lift the ARRAY-LEVEL subset embedding
// binds at rustc time — a regression that silently re-inlined the
// SUBSET or SUPERSET side of the relation to a fresh pair breaking
// the subset containment fails at `cargo check` BEFORE any test
// scheduler runs. Sibling to the pre-existing BIJECTIVITY witnesses
// above — those pin (LEFT-column INJECTIVITY ∧ RIGHT-column
// INJECTIVITY) on each individual paired array, this pins
// CONJOINED-pair SUBSET containment across a PAIR of paired arrays.
// Peer to the (char) + (u8) + (`&'static str`) scalar rows' SUBSET-
// embedding witnesses above on the (element-type) axis of the SAME
// (subset-embedding) contract-shape column.
const _: () = assert_char_pair_array_within_char_pair_finite_set::<3, 5>(
&Atom::NAMED_ESCAPE_TABLE,
&Atom::ESCAPE_TABLE,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// any pair of `a` aliases any pair of `b` byte-for-byte through
/// CONJOINED-pair equality on both `(char, char)` columns.
///
/// Row-dual peer to [`assert_char_arrays_disjoint`] +
/// [`assert_u8_arrays_disjoint`] + [`assert_str_arrays_disjoint`] on the
/// (element-type) axis of the (element-type × contract-shape) matrix at
/// the (disjointness) column: where the three SCALAR (char, u8,
/// `&'static str`) siblings close the DISJOINTNESS corner at ONE peer
/// helper per scalar element type, this helper opens the PRODUCT-ELEMENT
/// `(char, char)` row on the same column — extending the
/// (element-type × contract-shape) matrix's (disjointness) column past
/// the three scalar rows onto the paired-array row. Combined with the
/// pre-existing [`assert_char_pair_array_bijective`] (INJECTIVITY axis)
/// and [`assert_char_pair_array_within_char_pair_finite_set`] (SUBSET-
/// EMBEDDING axis), the substrate now closes the (paired-array
/// well-formedness, paired-array subset, paired-array disjointness)
/// 3-corner face on the `(char, char)` row of the (element-type ×
/// contract-shape) matrix at THREE peer const-fn helpers.
///
/// Contract-orthogonal peer to
/// [`assert_char_pair_array_within_char_pair_finite_set`] on the
/// (SUBSET-EMBEDDING, DISJOINTNESS) axis of the (contract-shape) column
/// on the SAME `(char, char)` row: where the SUBSET-EMBEDDING sibling
/// binds `arr ⊆ set` (every `arr` pair IS in `set`), this DISJOINTNESS
/// sibling binds `a ∩ b = ∅` (no `a` pair is in `b`). Together the two
/// helpers close the (paired-array subset, paired-array disjointness)
/// 2-corner face on the `(char, char)` row peer to the same face on
/// each of the (char, u8, `&'static str`) SCALAR rows.
///
/// CONJOINED-pair equality gate: `a[i] == b[j]` iff `a[i].0 == b[j].0
/// AND a[i].1 == b[j].1`. A per-column disjointness check on either
/// column alone (e.g. `a[i].0 ∉ b.map(|p| p.0)` AND separately
/// `a[i].1 ∉ b.map(|p| p.1)`) would REJECT paired arrays whose columns
/// share entries INDIVIDUALLY across rows even when NO CONJOINED pair
/// aliases — a stricter contract than paired-array disjointness. The
/// CONJOINED gate here PERMITS the per-column aliasing corner as
/// disjoint (a pair `('a', 'x')` in `a` and a pair `('a', 'y')` in `b`
/// alias at the LEFT column only — the CONJOINED pairs differ so the
/// paired arrays are correctly disjoint). This is the SAME gate the
/// sibling [`assert_char_pair_array_within_char_pair_finite_set`] uses
/// on its SUBSET arm — the two helpers share ONE product-element
/// equality relation across the (SUBSET, DISJOINTNESS) axis so a
/// caller who understands the gate on ONE arm carries the intuition to
/// the other.
///
/// The invariant is load-bearing for the substrate's Str-payload
/// escape-arm dispatch at [`Atom::decode_str_escape`]: the FIVE
/// non-passthrough escape arms partition into the pattern-DISTINCT-
/// from-value [`Atom::NAMED_ESCAPE_TABLE`] (`[(char, char); 3]`,
/// `'n' → '\n'`, `'t' → '\t'`, `'r' → '\r'`) and the pattern-EQUALS-
/// value self-escape rows (`STR_DELIMITER → STR_DELIMITER`,
/// `STR_ESCAPE_LEAD → STR_ESCAPE_LEAD` — expressed as pairs
/// `[(SELF_ESCAPE_TABLE[0], SELF_ESCAPE_TABLE[0]),
/// (SELF_ESCAPE_TABLE[1], SELF_ESCAPE_TABLE[1])]` at the paired-
/// vocabulary level). The two sub-vocabularies MUST remain disjoint —
/// otherwise a NAMED escape source (`'n'` / `'t'` / `'r'`) would
/// simultaneously ALSO be a SELF-escape source, breaking the
/// two-sub-vocabulary partition of [`Atom::ESCAPE_TABLE`] and
/// silently routing an escape byte through TWO cascading arms of
/// `decode_str_escape` at the same input position (with the earlier-
/// matched arm winning arbitrarily). Post-lift the paired-array
/// DISJOINTNESS of the two sub-vocabularies binds at rustc time via
/// ONE `const _` line — a regression that silently drifted a NAMED
/// escape source to `Atom::STR_DELIMITER` (colliding with the self-
/// escape row's first entry) OR drifted [`Atom::STR_DELIMITER`] to
/// `'n'` (colliding with the NEWLINE named-escape source) fails at
/// `cargo check` BEFORE any test scheduler runs.
///
/// SYMMETRY IN THE NESTED SWEEP: the inner `while j < M` sweep visits
/// every position of `b` per outer `i` and panics at the FIRST cross-
/// array CONJOINED-pair collision (`a[i] == b[j]` on both columns).
/// Because the relation is symmetric and the two-loop sweep visits
/// every `(i, j) ∈ [0, N) × [0, M)` pair, swapping `a` and `b` at the
/// call site produces the SAME verdict — the helper does NOT
/// gratuitously depend on argument order. Row-parallel to the SCALAR
/// siblings' symmetric-nested-sweep posture — the shape of the
/// disjointness relation carries no argument-order preference across
/// the (element-type) axis.
///
/// Adding a new family-wide `[(char, char); N]` paired sub-vocabulary
/// whose distinct-values set must remain disjoint from another substrate
/// `[(char, char); M]` paired array's distinct-values set: pair the
/// declaration with `const _: () =
/// assert_char_pair_arrays_disjoint::<N, M>(&Self::FOO_ARRAY,
/// &Other::BAR_ARRAY);` co-located after the array's declaration and
/// the paired-array DISJOINTNESS contract binds at compile time. The
/// rustc-forced arities `[(char, char); N]` and `[(char, char); M]`
/// compose with this const-eval sweep so BOTH cardinality-pair AND
/// cross-array CONJOINED-pair disjointness are compile-time theorems
/// on the SAME (a, b) paired-array pair.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_char_pair_arrays_disjoint_panics_at_runtime_on_collision`
/// and `assert_char_pair_arrays_disjoint_panic_message_names_the_
/// helper_and_char_pair_disjointness_violation_axis`. The panic site
/// carries the `"CHAR-PAIR-DISJOINTNESS-VIOLATION"` axis-provenance
/// string chosen DISTINCT from every sibling helper's axis vocabulary
/// (`"CHAR-DISJOINTNESS-VIOLATION"` / `"U8-DISJOINTNESS-VIOLATION"` /
/// `"STR-DISJOINTNESS-VIOLATION"` on the three SCALAR row-dual
/// DISJOINTNESS peers; `"CHAR-PAIR-SUBSET-VIOLATION"` on the paired-
/// array SUBSET-embedding sibling; `"LEFT column"` / `"RIGHT column"`
/// on the paired-array BIJECTIVITY sibling). The `"CHAR-PAIR-"` prefix
/// disambiguates from the (char) SCALAR row-dual DISJOINTNESS peer;
/// the shared `"-DISJOINTNESS-VIOLATION"` suffix lets callers grep any
/// row's DISJOINTNESS sibling by `"DISJOINTNESS-VIOLATION"` alone or
/// route to the specific element-type by the axis prefix.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide paired-array
/// cross-array disjointness contract on `(char, char)` sub-
/// vocabularies becomes a TYPE-LEVEL theorem the substrate carries
/// per (a, b) paired-array pair rather than a runtime test the
/// developer must remember to write per pair.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix's (DISJOINTNESS) column now carries the PRODUCT-
/// ELEMENT `(char, char)` row alongside the three SCALAR rows at ONE
/// peer const-fn helper per row. The (element-type ∈ {char, u8,
/// `&'static str`, `(char, char)`} × contract-shape ∈ {disjointness})
/// 4-corner column of the paired-array-contract prism is now closed
/// at FOUR peer const-fn helpers.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// DISJOINTNESS proof at declaration site AND the outer-algebra's
/// two-sub-vocabulary partition contract on `Atom::ESCAPE_TABLE`
/// (pattern-DISTINCT-from-value NAMED rows disjoint from pattern-
/// EQUALS-value SELF rows) regenerate through the SAME `const _`
/// witness at the paired-ARRAY level.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// CONJOINED-pair membership sweep IS the generative shape. Every
/// new `(char, char)` sub-vocabulary paired array whose distinct-
/// value set is an intentionally-disjoint peer of another substrate
/// paired array adds ONE `const _` line.
///
/// Frontier inspiration: Lean 4's `Finset.disjoint_iff_ne` unfolded to
/// `∀ a ∈ s, ∀ b ∈ t, a ≠ b` at the concrete two-array
/// `[(char, char); N] × [(char, char); M]` monomorphic realisation
/// with the CONJOINED-pair `≠` decidable on product `(α × β)` reducing
/// to `a ≠ b ∨ c ≠ d` on `(a, c) ≠ (b, d)` — the substrate primitive
/// here embeds the same product-decidable disjointness relation as a
/// rustc const-eval-time proof obligation at every
/// `assert_char_pair_arrays_disjoint` call site.
pub const fn assert_char_pair_arrays_disjoint<const N: usize, const M: usize>(
a: &[(char, char); N],
b: &[(char, char); M],
) {
let mut i = 0;
while i < N {
let mut j = 0;
while j < M {
// CONJOINED-pair equality — BOTH columns must match the
// SAME `(a[i], b[j])` entry pair. A per-column disjointness
// check on either column alone would REJECT paired arrays
// whose columns share entries INDIVIDUALLY across rows even
// when no CONJOINED pair aliases (a stricter contract than
// paired-array disjointness). The CONJOINED gate permits
// per-column aliasing as disjoint when the pairs themselves
// differ — mirrors the sibling paired-array SUBSET
// helper's CONJOINED gate on the same `(char, char)` row.
if a[i].0 as u32 == b[j].0 as u32 && a[i].1 as u32 == b[j].1 as u32 {
panic!(
"assert_char_pair_arrays_disjoint: CHAR-PAIR-\
DISJOINTNESS-VIOLATION — the two family-wide \
`[(char, char); N]` paired substrate arrays `a` \
and `b` share a CONJOINED-pair entry at some \
(i, j) position pair (BOTH columns of `a[i]` \
byte-for-byte equal BOTH columns of `b[j]`). The \
substrate's CROSS-ARRAY PAIRED-DISJOINTNESS \
contract on the pair is broken; every consumer \
that partitions the two paired arrays' distinct-\
value CONJOINED-pair sets into disjoint sub-\
vocabularies of a shared outer surface (the Str-\
payload escape-arm dispatch through `Atom::decode_\
str_escape` partitioning `Atom::ESCAPE_TABLE` \
into pattern-DISTINCT-from-value `Atom::NAMED_\
ESCAPE_TABLE` rows disjoint from pattern-EQUALS-\
value self-escape rows expressed as `(c, c)` \
pairs; any future typed-disjointness pair on the \
substrate's reader-boundary `(char, char)` \
algebras) relies on the two paired arrays' \
distinct-value CONJOINED-pair sets NOT sharing a \
pair. Fix at WHICHEVER ARRAY-DECLARATION site \
drifted (the symmetric disjointness relation \
carries no built-in axis-provenance role split \
between `a` and `b`) by dropping the offending \
pair from one array OR re-shaping the partition \
to route the shared pair to a single sub-\
vocabulary. The CONJOINED-pair equality gate \
distinguishes THIS helper from a per-column \
disjointness check that would REJECT paired \
arrays whose columns share entries INDIVIDUALLY \
across rows even when no CONJOINED pair aliases \
— the CONJOINED gate permits the per-column \
aliasing corner as disjoint"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time DISJOINTNESS witness — the ONE substrate-pinned
// `[(char, char); N] × [(char, char); M]` paired-array pair whose
// distinct-value CONJOINED-pair sets are intentionally-closed disjoint
// sub-vocabularies of the Str-payload escape-arm dispatch at
// `Atom::decode_str_escape`. The pattern-DISTINCT-from-value NAMED rows
// (`Atom::NAMED_ESCAPE_TABLE`, `[(char, char); 3]`) partition
// `Atom::ESCAPE_TABLE`'s first three positions; the pattern-EQUALS-
// value SELF rows lifted to `(c, c)` pair form (constructed inline
// from `Atom::SELF_ESCAPE_TABLE`) partition `Atom::ESCAPE_TABLE`'s
// remaining two positions. Pre-lift the paired-DISJOINTNESS of the
// two sub-vocabularies lived only implicitly at `Atom::ESCAPE_TABLE`'s
// composite declaration site (positions [0..3] as `NAMED_ESCAPE_TABLE`
// indexings + positions [3..5] as `(SELF[k], SELF[k])` pair
// constructions — the disjointness of the two SLICES holding by
// construction rather than by a checked contract). Post-lift the
// paired-ARRAY-LEVEL disjointness binds at rustc time via ONE `const
// _` line. A regression that silently drifted a NAMED escape source
// (e.g. `NEWLINE_ESCAPE_SOURCE` from `'n'` to `Atom::STR_DELIMITER`,
// colliding with the SELF row's first entry) OR drifted `Atom::STR_
// DELIMITER` to `'n'` (colliding with the NAMED NEWLINE source) fails
// at `cargo check` BEFORE any test scheduler runs. Sibling to the
// pre-existing paired-array BIJECTIVITY witnesses above (which pin
// LEFT-column ∧ RIGHT-column injectivity on each individual paired
// array) and the paired-array SUBSET-EMBEDDING witness (which pins
// `NAMED_ESCAPE_TABLE ⊂ ESCAPE_TABLE` at CONJOINED-pair containment)
// on the `(char, char)` row of the (element-type × contract-shape)
// matrix — the three witnesses together close the (paired-array well-
// formedness, paired-array subset, paired-array disjointness) 3-corner
// face on the paired-array row at ONE peer const-fn helper per corner.
// Row-parallel to the (char) + (u8) + (`&'static str`) SCALAR rows'
// DISJOINTNESS witnesses above on the (element-type) axis of the SAME
// (disjointness) contract-shape column.
const _: () = assert_char_pair_arrays_disjoint::<3, 2>(
&Atom::NAMED_ESCAPE_TABLE,
&[
(Atom::SELF_ESCAPE_TABLE[0], Atom::SELF_ESCAPE_TABLE[0]),
(Atom::SELF_ESCAPE_TABLE[1], Atom::SELF_ESCAPE_TABLE[1]),
],
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the family-wide `[(char, char); N]` paired substrate array `arr`
/// carries a pair at two distinct positions whose `(SOURCE, DECODED)`
/// tuples are byte-for-byte equal. Binds ONE conjunct clause on the
/// `(char, char)` product-element row of the (element-type × contract-
/// shape) matrix at the (pairwise-distinctness) column — CHAR-PAIR-
/// TUPLE-COLLISION — every position of `arr` MUST carry a
/// CONJOINED-pair `(a, b)` byte-for-byte distinct from every other
/// position's pair. Pair equality is CONJOINED across BOTH columns:
/// `arr[i] == arr[j]` iff `arr[i].0 == arr[j].0 AND arr[i].1 ==
/// arr[j].1` — a per-column pairwise-distinct check on either column
/// alone would REJECT paired arrays whose columns share entries
/// INDIVIDUALLY across rows even when no CONJOINED tuple aliases
/// (a stricter contract than tuple-level pairwise-distinctness, which
/// the sibling [`assert_char_pair_array_bijective`] closes as the
/// (column-INDEPENDENT injectivity) axis on the SAME row).
///
/// Contract-strength peer to [`assert_char_pair_array_bijective`] on
/// the (independent-column-injectivity vs tuple-injectivity) axis
/// splitting the (char, char) row's INJECTIVITY column into TWO
/// distinct sub-contracts. Bijectivity is strictly stronger — a
/// bijective paired array (`assert_char_pair_array_bijective`) has
/// LEFT-column pairwise-distinct AND RIGHT-column pairwise-distinct
/// INDEPENDENTLY, which implies tuple-level pairwise-distinctness
/// (if `a[i].0 == a[j].0` fails and `a[i].1 == a[j].1` fails
/// independently, then the tuples cannot collide either). This
/// helper enforces ONLY the CONJOINED-tuple distinctness — a strictly
/// WEAKER contract that permits per-column aliasing across rows as
/// long as no CONJOINED tuple aliases. Mirrors the sibling
/// (char, char) row helpers' CONJOINED-pair gate posture:
/// [`assert_char_pair_array_within_char_pair_finite_set`] and
/// [`assert_char_pair_arrays_disjoint`] BOTH gate on
/// CONJOINED-tuple equality; this helper closes the third
/// CONJOINED-tuple sibling on the SAME (char, char) row.
///
/// Element-type row-parallel to the three SCALAR-element pairwise-
/// distinctness sibling helpers on the (element-type) axis:
/// [`assert_char_array_pairwise_distinct`] (the (char) scalar-element
/// peer), [`assert_str_array_pairwise_distinct`] (the (`&'static str`)
/// scalar-element peer), and [`assert_u8_array_pairwise_distinct`]
/// (the (u8) scalar-element peer). Where the three scalar-element
/// siblings close the INJECTIVITY column on the three SCALAR rows of
/// the (element-type × contract-shape) matrix, this helper closes the
/// TUPLE-level INJECTIVITY corner on the (char, char) PRODUCT-element
/// row — the fourth row of the matrix's element-type axis. Together
/// with [`assert_char_pair_array_bijective`] (the column-INDEPENDENT
/// INJECTIVITY peer on the SAME row) the (char, char) row now closes
/// BOTH INJECTIVITY sub-shapes at ONE const-fn helper each: the
/// stronger column-independent axis at the bijective sibling; the
/// weaker CONJOINED-tuple axis here.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// tokenizer that constructs a `[(char, char); N]` paired array at
/// runtime and wants to verify tuple-level pairwise-distinctness
/// before consuming it — and the panic surfaces normally in that
/// path (pinned by
/// `assert_char_pair_array_pairwise_distinct_panics_at_runtime_on_tuple_collision`
/// and
/// `assert_char_pair_array_pairwise_distinct_panic_message_names_the_helper_and_char_pair_tuple_collision_axis`).
/// The panic message carries a CHAR-PAIR-TUPLE-COLLISION axis-
/// provenance suffix so downstream diagnostics (`cargo check` const-
/// eval error output, test-suite failure reports) route the drift
/// back to THIS helper's tuple-level axis rather than to the
/// sibling bijective helper's column-LABELED axis (LEFT-column vs
/// RIGHT-column) — halving the search space for the operator
/// debugging a drift that surfaces at the tuple axis but is invisible
/// at either column axis alone.
///
/// Adding a new family-wide `[(char, char); N]` paired-array whose
/// distinct-value tuple-set carries a pairwise-distinct-but-NOT-
/// bijective contract: pair the declaration with `const _: () =
/// assert_char_pair_array_pairwise_distinct(&Self::FOO_TABLE);` co-
/// located after the array's declaration and the tuple-level
/// distinctness contract binds at compile time. The rustc-forced
/// arity `[(char, char); N]` composes with this const-eval sweep so
/// cardinality AND tuple-level injectivity are compile-time theorems
/// on the SAME array. A future consumer keyed on tuple-level
/// (rather than column-level) distinctness — a hypothetical (short-
/// form, canonical-form) alias table that permits many-to-one
/// aliasing on either column but requires the paired short↔canonical
/// tuples to be pairwise-distinct — reaches for THIS helper without
/// composing through the strictly stronger bijective sibling.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide tuple-
/// level pairwise-distinctness contract on the `(char, char)`
/// paired substrate vocabulary becomes a TYPE-LEVEL theorem the
/// substrate carries per paired-array declaration rather than a
/// runtime test the developer must remember to write per array.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; a
/// tuple-level distinctness proof at declaration site AND the
/// tuple-level match-arm exhaustiveness at every consumer that
/// enumerates the array's tuples as DISJOINT arms regenerate
/// through the SAME `const _` witness.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// tuple-CONJOINED sweep IS the generative shape. Every new
/// closed-set paired-array vocabulary whose distinct-value tuple-
/// set is intentionally pairwise-distinct-at-the-tuple-level adds
/// ONE `const _` line to get the tuple-level distinctness theorem
/// rather than re-deriving a `HashSet::insert` loop test per array.
///
/// Frontier inspiration: Lean 4's `List.Nodup` on `List (α × β)` at
/// the concrete monomorphic realisation `[(char, char); N]` with the
/// CONJOINED-tuple `≠` decidable on product `(α × β)` reducing to
/// `a ≠ b ∨ c ≠ d` on `(a, c) ≠ (b, d)` — the substrate primitive
/// here embeds the same product-decidable pairwise-distinctness
/// relation as a rustc const-eval-time proof obligation at every
/// `assert_char_pair_array_pairwise_distinct` call site.
pub const fn assert_char_pair_array_pairwise_distinct<const N: usize>(arr: &[(char, char); N]) {
let mut i = 0;
while i < N {
let mut j = i + 1;
while j < N {
// CONJOINED-tuple equality — BOTH columns must match the
// SAME `(arr[i], arr[j])` position pair. A per-column
// pairwise-distinct check on either column alone would
// REJECT paired arrays whose columns share entries
// INDIVIDUALLY across rows even when no CONJOINED tuple
// aliases (a stricter contract than tuple-level pairwise-
// distinctness, which the sibling
// `assert_char_pair_array_bijective` closes as the
// column-INDEPENDENT INJECTIVITY axis on the SAME row).
// The CONJOINED gate is the (char, char) row's WEAKER
// pairwise-distinctness axis — mirrors the sibling
// `assert_char_pair_arrays_disjoint` +
// `assert_char_pair_array_within_char_pair_finite_set`
// CONJOINED-tuple gates on the same row.
if arr[i].0 as u32 == arr[j].0 as u32 && arr[i].1 as u32 == arr[j].1 as u32 {
panic!(
"assert_char_pair_array_pairwise_distinct: CHAR-\
PAIR-TUPLE-COLLISION — family-wide `[(char, \
char); N]` paired substrate array carries a \
duplicate CONJOINED-tuple entry across two \
positions (BOTH columns of `arr[i]` byte-for-\
byte equal BOTH columns of `arr[j]`). The \
substrate's TUPLE-level pairwise-distinctness \
contract on the array is broken; every consumer \
that pattern-matches the array's CONJOINED-\
tuples as DISJOINT arms (any future \
`match (a, b) {{ … }}` outer dispatch on a paired \
vocabulary, any future tuple-keyed cache index \
on a `[(char, char); N]` table) relies on this \
invariant. Fix at the ARRAY-DECLARATION site by \
dropping the duplicate tuple OR re-shaping the \
partition to route the shared tuple to a single \
position. The CONJOINED-tuple equality gate \
distinguishes THIS helper from a per-column \
pairwise-distinct check that would REJECT paired \
arrays whose columns share entries INDIVIDUALLY \
across rows even when no CONJOINED tuple aliases \
— the CONJOINED gate is the (char, char) row's \
WEAKER pairwise-distinctness axis, peer to the \
stricter column-INDEPENDENT INJECTIVITY axis at \
`assert_char_pair_array_bijective`"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time TUPLE-level pairwise-distinctness witnesses — one
// `const _: () = assert_char_pair_array_pairwise_distinct(&…)` per
// family-wide `[(char, char); N]` paired substrate array on the Str-
// payload escape-table product-vocabulary. Each invocation is const-
// evaluated at `cargo check` time; a regression that silently
// collided TWO CONJOINED-tuples across positions fails the build
// rather than the test suite. Sibling to the pre-existing paired-
// array BIJECTIVITY witnesses above (which pin the strictly stronger
// column-INDEPENDENT INJECTIVITY axis — LEFT-column ∧ RIGHT-column
// pairwise-distinct per array); this helper pins the WEAKER
// CONJOINED-tuple INJECTIVITY axis at the SAME two arrays. Both
// axes are compile-time theorems on both arrays post-lift: bijective
// binds the strictly stronger axis (implied on both existing
// arrays); this helper binds the WEAKER tuple-level axis. Row-
// parallel to the three SCALAR-element rows' pairwise-distinct
// witnesses above on the (element-type) axis: (char) closes the
// reader-boundary vocabulary; (`&'static str`) closes the closed-set
// outer-algebras' label / prefix / tag / literal vocabularies; (u8)
// closes the outer-`Sexp` cache-key discriminator vocabulary; and
// this (char, char) product-element sibling closes the paired
// escape-table vocabulary at the TUPLE-level. The dual-axis coverage
// (bijective + pairwise-distinct-tuples) gives downstream consumers
// TWO axis-provenance vocabularies to route regressions through: a
// future consumer keyed on tuple-level (rather than column-level)
// distinctness — a hypothetical (short-form, canonical-form) alias
// table that permits many-to-one aliasing on either column but
// requires paired short↔canonical tuples to be pairwise-distinct —
// reaches for THIS helper's `CHAR-PAIR-TUPLE-COLLISION` panic
// message rather than for the bijective sibling's column-LABELED
// panic (LEFT-column collision vs RIGHT-column collision).
const _: () = assert_char_pair_array_pairwise_distinct(&Atom::NAMED_ESCAPE_TABLE);
const _: () = assert_char_pair_array_pairwise_distinct(&Atom::ESCAPE_TABLE);
/// Compile-time contract verifier — panics at const evaluation time
/// if either column-projection of the family-wide `[(char, char); N]`
/// paired substrate array `pairs` diverges byte-for-byte from its
/// declared peer scalar `[char; N]` array. Binds a JOINT
/// (LEFT_col == left) ∧ (RIGHT_col == right) POSITIONWISE-EQUALITY
/// contract at ONE `const _` line on the (char, char) product-element
/// row of the (element-type × contract-shape) matrix at the
/// (column-projection-equality) column — a NEW column opened past the
/// (INJECTIVITY, SUBSET-EMBEDDING, DISJOINTNESS) triple the four
/// sibling helpers close ([`assert_char_pair_array_bijective`] +
/// [`assert_char_pair_array_pairwise_distinct`] on INJECTIVITY,
/// [`assert_char_pair_array_within_char_pair_finite_set`] on SUBSET-
/// EMBEDDING, [`assert_char_pair_arrays_disjoint`] on DISJOINTNESS).
///
/// Rust's forced `[T; N]` cardinality composes with the const-eval
/// sweep to pin THREE clauses at ONE `const _` line:
/// 1. ARITY: `pairs.len() == left.len() == right.len() == N` — a
/// regression that drifts EITHER peer scalar array's arity away
/// from the paired array's `N` fails-loudly at type-check time
/// (before const eval), so the two clauses BELOW walk a
/// length-parallel sweep unconditionally.
/// 2. LEFT-COLUMN-EQUALITY: `pairs[i].0 == left[i]` for every
/// `i ∈ 0..N` — a regression that drifts ONE paired-table LEFT
/// entry away from the peer scalar SOURCE array (e.g. renames
/// `NEWLINE_ESCAPE_SOURCE` to `LINEFEED_ESCAPE_SOURCE` and
/// updates ONLY the pair entry without updating the scalar
/// declaration, OR vice versa) fails-loudly at const eval.
/// 3. RIGHT-COLUMN-EQUALITY: `pairs[i].1 == right[i]` for every
/// `i ∈ 0..N` — same posture on the RIGHT / DECODED column.
///
/// Currently applied to the (`ESCAPE_TABLE`, `ESCAPE_SOURCES`,
/// `ESCAPE_DECODED`) triple where the paired array is CONSTRUCTED
/// from `NAMED_ESCAPE_TABLE` + `SELF_ESCAPE_TABLE` (see
/// [`Atom::ESCAPE_TABLE`]'s definition) and the two peer scalar
/// arrays are DECLARED INDEPENDENTLY as
/// [`Atom::ESCAPE_SOURCES`](Atom::ESCAPE_SOURCES) +
/// [`Atom::ESCAPE_DECODED`](Atom::ESCAPE_DECODED). Pre-lift the
/// three-way column bond ("`ESCAPE_TABLE`'s LEFT column IS
/// `ESCAPE_SOURCES` AND RIGHT column IS `ESCAPE_DECODED`") lived
/// as PROSE in the peer arrays' docstrings ("the SPAN of the two
/// peer sub-vocabulary source columns") plus as a runtime test that
/// zipped the three arrays; post-lift the bond binds at `cargo
/// check` time — a regression that renames a source or decoded byte
/// on ONE of the three arrays without updating the other two fails
/// the build rather than the test suite. The const-eval panic
/// surfaces the column-divergence at COMPILE time, one invocation
/// stage earlier, catching regressions on `cargo build` /
/// `cargo clippy` runs that skip the test suite.
///
/// Contract-shape peer to the four sibling paired-array verifiers
/// on the (char, char) row: where the sibling
/// [`assert_char_pair_array_bijective`] closes the INJECTIVITY axis
/// (LEFT-column ∧ RIGHT-column pairwise-distinct, INDEPENDENTLY),
/// [`assert_char_pair_array_pairwise_distinct`] closes the WEAKER
/// CONJOINED-tuple INJECTIVITY axis, [`assert_char_pair_array_
/// within_char_pair_finite_set`] closes the SUBSET-EMBEDDING axis,
/// and [`assert_char_pair_arrays_disjoint`] closes the DISJOINTNESS
/// axis, THIS helper opens the fifth (column-projection-EQUALITY)
/// axis — the (LEFT column == left) ∧ (RIGHT column == right) JOINT
/// clause that bonds a paired vocabulary to TWO peer scalar
/// vocabularies. Compound-JOINT posture parallels the pre-existing
/// [`assert_scalar_plus_two_u8_arrays_permute_inclusive_range`] on
/// the (u8) row (three-array joint contract at one witness line);
/// unlike the permutation posture there, this helper's joint
/// contract is POSITIONWISE-EQUALITY (order-sensitive) rather than
/// set-EQUALITY.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// tokenizer that constructs a paired escape table + two peer
/// scalar columns at runtime and wants to verify column-projection
/// equality before consuming them — and the two panic sites (LEFT-
/// column divergence, RIGHT-column divergence) surface normally in
/// that path with column-provenance-preserving panic messages
/// (pinned by the two `_panics_at_runtime_on_left_head_divergence`
/// and `_panics_at_runtime_on_right_head_divergence` tests plus
/// their middle-position and tail-position peers). The two axis-
/// provenance strings `"LEFT-COLUMN-DIVERGENCE"` and
/// `"RIGHT-COLUMN-DIVERGENCE"` are chosen DISTINCT from every
/// sibling helper's axis vocabulary (`"LEFT column"` and
/// `"RIGHT column"` on the paired-array BIJECTIVITY sibling name the
/// COLUMN but the failure MODE is `duplicate SOURCE / DECODED char`;
/// this helper's failure MODE is `divergence from peer scalar
/// array`) so a diagnostic that names the failed axis routes
/// UNAMBIGUOUSLY to (a) this specific paired-array COLUMN-
/// PROJECTION-EQUALITY helper, (b) the failed COLUMN by the
/// `"LEFT-"` and `"RIGHT-"` prefix.
///
/// Adding a new family-wide `[(char, char); N]` paired array
/// declared alongside TWO peer scalar `[char; N]` arrays whose
/// LEFT + RIGHT columns are meant to project to the peer arrays'
/// contents: pair the declarations with `const _: () =
/// assert_char_pair_array_columns_equal_char_arrays(&Self::FOO_
/// TABLE, &Self::FOO_LEFT, &Self::FOO_RIGHT);` and the three-way
/// column bond binds at compile time WITHOUT a runtime zip loop.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the three-way column bond
/// on the paired-array + peer-scalar-columns vocabulary becomes
/// a TYPE-LEVEL theorem the substrate carries per declaration
/// triple rather than a runtime zip loop the developer must
/// remember to write per triple.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs;
/// the column-projection-equality proof at declaration site AND
/// the peer-array outer-dispatch consumers regenerate through
/// the SAME `const _` witness.
/// - THEORY.md §VI.1 — generation over composition; the two-column
/// positionwise-equality sweep IS the generative shape. Every
/// new closed-set paired-array declared alongside peer scalar
/// columns adds ONE `const _` line to get the three-way bond
/// theorem rather than re-deriving a runtime zip loop per triple.
pub const fn assert_char_pair_array_columns_equal_char_arrays<const N: usize>(
pairs: &[(char, char); N],
left: &[char; N],
right: &[char; N],
) {
let mut i = 0;
while i < N {
if pairs[i].0 as u32 != left[i] as u32 {
panic!(
"assert_char_pair_array_columns_equal_char_arrays: \
LEFT-COLUMN-DIVERGENCE — family-wide `[(char, \
char); N]` paired substrate array's LEFT column \
projection carries an entry at some position that \
does NOT byte-for-byte equal the peer scalar \
`[char; N]` array's entry at the SAME position. \
The substrate's LEFT-column POSITIONWISE-EQUALITY \
contract on the (paired, peer-scalar) column-\
projection bond is broken; every consumer that \
reads the paired array's LEFT column and the peer \
scalar SOURCE array as INTERCHANGEABLE (any \
outer-tokenizer `Sexp` dispatch that pattern-\
matches on `Atom::ESCAPE_SOURCES` while a peer \
attestation code path reads `Atom::ESCAPE_TABLE`'s \
LEFT column, any future `[char; N]` peer-column \
dual projection that assumes the two are equal at \
every position) relies on this invariant. Fix at \
one of the THREE declaration sites (`pairs`, \
`left`, or the peer scalar RIGHT column's \
declaration if the drift is a cross-column rename) \
by reconciling the entry across the three arrays. \
The LEFT-column-divergence gate distinguishes THIS \
helper from the sibling `assert_char_pair_array_\
bijective` (which surfaces LEFT-column DUPLICATE-\
SOURCE failures, not LEFT-column-vs-peer-scalar \
DIVERGENCE failures) and from the sibling `assert_\
char_pair_array_within_char_pair_finite_set` \
(which surfaces CONJOINED-tuple SUBSET-VIOLATION \
failures, not per-column POSITIONWISE-EQUALITY \
failures)"
);
}
if pairs[i].1 as u32 != right[i] as u32 {
panic!(
"assert_char_pair_array_columns_equal_char_arrays: \
RIGHT-COLUMN-DIVERGENCE — family-wide `[(char, \
char); N]` paired substrate array's RIGHT column \
projection carries an entry at some position that \
does NOT byte-for-byte equal the peer scalar \
`[char; N]` array's entry at the SAME position. \
The substrate's RIGHT-column POSITIONWISE-EQUALITY \
contract on the (paired, peer-scalar) column-\
projection bond is broken; every consumer that \
reads the paired array's RIGHT column and the peer \
scalar DECODED array as INTERCHANGEABLE (any \
outer-tokenizer `Sexp` dispatch that pattern-\
matches on `Atom::ESCAPE_DECODED` while a peer \
attestation code path reads `Atom::ESCAPE_TABLE`'s \
RIGHT column, any future `[char; N]` peer-column \
dual projection that assumes the two are equal at \
every position) relies on this invariant. Fix at \
one of the THREE declaration sites (`pairs`, \
`right`, or the peer scalar LEFT column's \
declaration if the drift is a cross-column rename) \
by reconciling the entry across the three arrays"
);
}
i += 1;
}
}
// Compile-time column-projection-EQUALITY witness — one `const _: ()
// = assert_char_pair_array_columns_equal_char_arrays(&…, &…, &…)`
// binding the (ESCAPE_TABLE, ESCAPE_SOURCES, ESCAPE_DECODED) three-
// way column bond on the substrate's Str-payload escape-table
// vocabulary. `Atom::ESCAPE_TABLE` (`[(char, char); 5]`) is
// CONSTRUCTED from `NAMED_ESCAPE_TABLE[0..=2]` + two SELF-diagonal
// pairs `(SELF_ESCAPE_TABLE[0], SELF_ESCAPE_TABLE[0])` +
// `(SELF_ESCAPE_TABLE[1], SELF_ESCAPE_TABLE[1])`, whose LEFT +
// RIGHT column projections match `Atom::ESCAPE_SOURCES` +
// `Atom::ESCAPE_DECODED` position-for-position by declaration
// intent — this const-eval witness binds that intent as a compile-
// time theorem so a regression that renames a source or decoded
// byte on ONE of the three arrays without updating the other two
// fails the build. Sibling to the `_pairwise_distinct` + `_bijective`
// witnesses above on the SAME paired array — the FOUR const-eval
// sweeps enforce complementary axes of the same substrate table at
// FOUR stages of the toolchain, so a build that skips tests still
// catches column-projection drift here, and a build that runs tests
// catches it a second time as a safety net if the const-eval sweep
// is ever silently dropped.
const _: () = assert_char_pair_array_columns_equal_char_arrays(
&Atom::ESCAPE_TABLE,
&Atom::ESCAPE_SOURCES,
&Atom::ESCAPE_DECODED,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the family-wide `[(char, char); N]` paired substrate array `arr`
/// carries a character that appears in BOTH its LEFT column projection
/// AND its RIGHT column projection (across ANY position pair). Binds
/// ONE conjunct clause on the `(char, char)` product-element row of the
/// (element-type × contract-shape) matrix at the
/// (cross-column-disjointness) column — CROSS-COLUMN-COLLISION — the
/// set of characters appearing as LEFT entries MUST be DISJOINT from
/// the set of characters appearing as RIGHT entries. Formally:
/// `∀ i, j ∈ 0..N : arr[i].0 as u32 != arr[j].1 as u32` — including
/// the diagonal `i == j` case (a `('a', 'a')` self-mapping pair
/// FAILS this contract even though it satisfies BOTH the SELF-arm
/// identity-relation shape AND the sibling
/// [`assert_char_pair_array_bijective`] per-column injectivity check).
///
/// Contract-shape orthogonality with the FOUR sibling paired-array
/// verifiers on the SAME row:
/// * [`assert_char_pair_array_bijective`] closes the per-column
/// INJECTIVITY axis (LEFT-column ∧ RIGHT-column pairwise-distinct,
/// INDEPENDENTLY) — a table like `[('a', 'x'), ('a', 'y')]` fails
/// BIJECTIVITY (LEFT duplicated) but passes CROSS-COLUMN-DISJOINT
/// (LEFT = {'a'}, RIGHT = {'x', 'y'}, disjoint). The two axes are
/// INDEPENDENT: neither implies the other.
/// * [`assert_char_pair_array_pairwise_distinct`] closes the WEAKER
/// CONJOINED-tuple INJECTIVITY axis — a table like
/// `[('a', 'a')]` passes CONJOINED-tuple pairwise-distinctness
/// (only one tuple) but FAILS CROSS-COLUMN-DISJOINT (LEFT[0] ==
/// RIGHT[0] on the diagonal).
/// * [`assert_char_pair_array_within_char_pair_finite_set`] closes
/// the SUBSET-EMBEDDING axis — orthogonal to cross-column
/// disjointness (a table can be a subset of a well-formed set and
/// still violate cross-column disjointness if the set itself does).
/// * [`assert_char_pair_arrays_disjoint`] closes the BETWEEN-ARRAY
/// DISJOINTNESS axis (two arrays share no CONJOINED tuple) — this
/// helper closes the WITHIN-ARRAY CROSS-COLUMN DISJOINTNESS axis
/// (one array's LEFT column shares no CHARACTER with its RIGHT
/// column). The two axes are DUAL: BETWEEN-ARRAY vs WITHIN-ARRAY,
/// CONJOINED-tuple vs CROSS-COLUMN-CHARACTER.
///
/// The invariant is load-bearing for the substrate's
/// pattern-DISTINCT-from-value sub-vocabulary at
/// [`Atom::NAMED_ESCAPE_TABLE`] (`[(char, char); 3]`): the three
/// named-escape rows `('n', '\n')`, `('t', '\t')`, `('r', '\r')` are
/// pattern-DISTINCT-from-value by algebra design (the printable ASCII
/// SOURCE column and the control-character DECODED column MUST NOT
/// overlap — a regression that added a pair like `('n', 'r')` or
/// `('a', 'a')` would silently collapse the pattern-DISTINCT-from-value
/// axis by routing a SOURCE character back to itself OR to another
/// SOURCE character, making the two sub-vocabularies
/// (pattern-distinct at [`Atom::NAMED_ESCAPE_TABLE`] +
/// pattern-equals at [`Atom::SELF_ESCAPE_TABLE`]) share membership).
/// The SHAPE ASYMMETRY between the two peer arrays (`[(char, char); N]`
/// vs `[char; N]`) already encodes the identity-relation asymmetry in
/// the TYPE — but a `[(char, char); N]` on the DISTINCT sub-vocabulary
/// side can silently drift a pair onto the diagonal while retaining
/// its paired shape. Pre-lift, the cross-column disjointness of
/// `NAMED_ESCAPE_TABLE` lived ONLY as prose in the substrate's escape-
/// table docstrings ("the THREE pattern-DISTINCT-from-value named-
/// escape rows") plus as an implicit consequence of the ASCII-letter
/// vs control-character byte-range partition. Post-lift the cross-
/// column disjointness binds at `cargo check` time — a regression
/// that adds a `('a', 'a')` diagonal pair, a `('n', 'r')` cross-row
/// SOURCE-to-SOURCE aliasing pair, or any pair drifting a character
/// across the LEFT / RIGHT partition fails the build rather than the
/// test suite.
///
/// Applies ONLY to the pattern-DISTINCT-from-value sub-vocabulary of
/// the escape-table family. [`Atom::ESCAPE_TABLE`] (`[(char, char); 5]`)
/// INTENTIONALLY violates cross-column disjointness on its two SELF
/// arms (the tail two positions `(STR_DELIMITER, STR_DELIMITER)` +
/// `(STR_ESCAPE_LEAD, STR_ESCAPE_LEAD)` are diagonal self-mappings by
/// design). No witness is co-located on `Atom::ESCAPE_TABLE` — the
/// SHAPE ASYMMETRY between the two escape-table sub-vocabularies IS
/// the axis distinguishing them, and this helper's contract holds
/// ONLY on the DISTINCT side.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// tokenizer that constructs a paired vocabulary at runtime and wants
/// to verify cross-column disjointness before consuming it — and the
/// panic surfaces normally in that path (pinned by
/// `assert_char_pair_array_columns_cross_disjoint_panics_at_runtime_
/// on_diagonal_collision` and its off-diagonal peers). The axis-
/// provenance string `"CROSS-COLUMN-COLLISION"` is chosen DISTINCT
/// from every sibling helper's axis vocabulary (`"CHAR-PAIR-TUPLE-
/// COLLISION"` on `_pairwise_distinct`, `"LEFT column"` / `"RIGHT
/// column"` on `_bijective`, `"CHAR-PAIR-SUBSET-VIOLATION"` on
/// `_within_char_pair_finite_set`, `"CHAR-PAIR-DISJOINTNESS-
/// VIOLATION"` on `_arrays_disjoint`, `"LEFT-COLUMN-DIVERGENCE"` /
/// `"RIGHT-COLUMN-DIVERGENCE"` on `_columns_equal_char_arrays`) so a
/// diagnostic that names the failed axis routes UNAMBIGUOUSLY to
/// this specific cross-column-disjointness helper rather than to a
/// sibling paired-array verifier.
///
/// Adding a new family-wide `[(char, char); N]` paired array on a
/// pattern-DISTINCT-from-value sub-vocabulary (e.g. a hypothetical
/// (short-form, long-form) alias table where short and long forms
/// live in disjoint character partitions, or a `(bracket-open,
/// bracket-close)` table where open and close characters MUST NOT
/// alias): pair the declaration with `const _: () = assert_char_
/// pair_array_columns_cross_disjoint(&Self::FOO_TABLE);` co-located
/// immediately after the array's declaration and the cross-column
/// disjointness contract binds at compile time WITHOUT a runtime
/// LEFT.iter().any(RIGHT.contains) sweep.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the WITHIN-ARRAY CROSS-
/// COLUMN disjointness contract becomes a TYPE-LEVEL theorem the
/// substrate carries per pattern-DISTINCT-from-value paired-array
/// declaration rather than a runtime membership sweep the developer
/// must remember to write per array.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// cross-column disjointness proof at declaration site AND the
/// escape-table consumers that route SOURCE-column characters
/// THROUGH `decode_str_escape` to DECODED-column characters (and
/// rely on that route being one-way) regenerate through the SAME
/// `const _` witness.
/// - THEORY.md §VI.1 — generation over composition; the doubly-nested
/// `while` cross-column sweep IS the generative shape. Every new
/// pattern-DISTINCT-from-value closed-set paired-array adds ONE
/// `const _` line to get the cross-column disjointness theorem
/// rather than re-deriving a `HashSet::intersection` runtime test
/// per array.
pub const fn assert_char_pair_array_columns_cross_disjoint<const N: usize>(
arr: &[(char, char); N],
) {
let mut i = 0;
while i < N {
let mut j = 0;
while j < N {
if arr[i].0 as u32 == arr[j].1 as u32 {
panic!(
"assert_char_pair_array_columns_cross_disjoint: \
CROSS-COLUMN-COLLISION — family-wide `[(char, \
char); N]` paired substrate array carries a \
character appearing in BOTH the LEFT column at \
some position `i` AND the RIGHT column at some \
position `j` (possibly `i == j`, the diagonal \
self-mapping case). The substrate's WITHIN-ARRAY \
CROSS-COLUMN DISJOINTNESS contract on the array \
is broken; every consumer that treats the paired \
array as a pattern-DISTINCT-from-value sub-\
vocabulary (any escape-table decode path that \
assumes SOURCE bytes and DECODED bytes live in \
disjoint character partitions so `decode_str_\
escape` is a strictly ONE-WAY mapping, any \
future `(bracket-open, bracket-close)` paired \
vocabulary that assumes open and close characters \
alias with neither each other nor a peer role) \
relies on this invariant. Fix at the ARRAY-\
DECLARATION site by moving the diagonal or \
cross-row aliased pair to the peer SELF-arm \
vocabulary (`Atom::SELF_ESCAPE_TABLE` on the \
escape-table family) OR by re-shaping the pair \
to route the shared character to a single column. \
The CROSS-COLUMN-COLLISION axis is DISTINCT from \
the sibling `_bijective` per-column INJECTIVITY \
axis (a table like `[('a', 'x'), ('a', 'y')]` \
fails `_bijective` on the LEFT-column-duplicate \
arm but PASSES this helper because LEFT = {{'a'}} \
and RIGHT = {{'x', 'y'}} are disjoint) and from \
the sibling `_pairwise_distinct` CONJOINED-tuple \
INJECTIVITY axis (a table like `[('a', 'a')]` \
passes `_pairwise_distinct` on the singleton but \
FAILS this helper on the diagonal `arr[0].0 == \
arr[0].1` — the two axes cross-check different \
failure modes on the SAME paired vocabulary)"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time WITHIN-ARRAY CROSS-COLUMN disjointness witness — one
// `const _: () = assert_char_pair_array_columns_cross_disjoint(&…)`
// binding the pattern-DISTINCT-from-value sub-vocabulary's cross-
// column character-set disjointness at `cargo check` time on the
// substrate's escape-table family. Applied to
// `Atom::NAMED_ESCAPE_TABLE` (`[(char, char); 3]` — the three named-
// escape rows `('n', '\n')`, `('t', '\t')`, `('r', '\r')`); the LEFT
// column projection = {'n', 't', 'r'} (printable ASCII) and the RIGHT
// column projection = {'\n', '\t', '\r'} (control characters) are
// disjoint by algebra design. A regression that added a `('n', 'r')`
// SOURCE-to-SOURCE aliasing pair, a `('a', 'a')` diagonal self-
// mapping pair, or any pair drifting a character across the LEFT /
// RIGHT partition fails the build rather than the test suite.
// Deliberately NOT applied to `Atom::ESCAPE_TABLE` — that array
// composes `NAMED_ESCAPE_TABLE` with two SELF arms at the tail
// (`(STR_DELIMITER, STR_DELIMITER)` + `(STR_ESCAPE_LEAD, STR_ESCAPE_
// LEAD)`), which INTENTIONALLY violate cross-column disjointness on
// the diagonal by algebra design. The SHAPE ASYMMETRY between the
// pattern-DISTINCT-from-value (`NAMED_ESCAPE_TABLE`) and the pattern-
// EQUALS-value (`SELF_ESCAPE_TABLE`) sub-vocabularies is the axis
// distinguishing them, and this helper's contract holds ONLY on the
// DISTINCT side of that partition. Sibling to the `_bijective` +
// `_pairwise_distinct` witnesses above on the SAME paired array — the
// three witnesses close complementary INJECTIVITY axes (per-column,
// per-tuple, per-CROSS-column) at `cargo check` time.
const _: () = assert_char_pair_array_columns_cross_disjoint(&Atom::NAMED_ESCAPE_TABLE);
/// Compile-time contract verifier — panics at const evaluation time if
/// the family-wide `[(char, char); N]` paired substrate array `arr` is
/// NOT byte-for-byte equal to the CONCATENATION of the peer paired
/// array `head` (contributing the FIRST `K` positions of `arr`
/// verbatim) followed by the DIAGONAL-EMBEDDING of the peer scalar
/// `[char; M]` array `tail_diag` (contributing the REMAINING `M = N -
/// K` positions as `(tail_diag[j], tail_diag[j])` at position `K + j`).
/// Binds ONE compound (SEGMENTED-CONCATENATION × DIAGONAL-EMBEDDING)
/// contract clause on the `(char, char)` product-element row of the
/// (element-type × contract-shape) matrix at a fresh
/// (concat-with-diagonal-tail) column — an ORDERING-SENSITIVE
/// SEGMENTED-POSITIONWISE contract joining the pre-existing
/// (pairwise-distinct), (bijective), (subset-embedding),
/// (disjointness), and (column-projection-equality) columns on the
/// SAME paired-array row.
///
/// Cardinality precondition: `K + M == N` — the caller passes the
/// three const parameters explicitly (`N`, `K`, `M`), and the helper's
/// FIRST arm fires at const-eval if the three fail to sum. A caller
/// who supplies mismatched arities (e.g. `<5, 3, 3>` — `K + M == 6 ≠
/// N == 5`) fails-loudly at the CARDINALITY-MISMATCH panic BEFORE the
/// sweep begins, so a mistyped ARITY doesn't degenerate into a silent
/// truncation of the paired array. Pinned by
/// `assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_cardinality_mismatch`.
///
/// Failure axes — the helper partitions its rejection surface into
/// FIVE disjoint arms, each with a DISTINCT axis-provenance prefix on
/// the panic message so downstream diagnostics route the drift back
/// to the specific SEGMENT and COLUMN that diverged:
/// 1. `CARDINALITY-MISMATCH` — `K + M != N`.
/// 2. `HEAD-SEGMENT-LEFT-DIVERGENCE` — some `i ∈ [0, K)` where
/// `arr[i].0 != head[i].0`.
/// 3. `HEAD-SEGMENT-RIGHT-DIVERGENCE` — some `i ∈ [0, K)` where
/// `arr[i].1 != head[i].1`.
/// 4. `DIAGONAL-TAIL-SEGMENT-LEFT-DIVERGENCE` — some `j ∈ [0, M)`
/// where `arr[K + j].0 != tail_diag[j]`.
/// 5. `DIAGONAL-TAIL-SEGMENT-RIGHT-DIVERGENCE` — some `j ∈ [0, M)`
/// where `arr[K + j].1 != tail_diag[j]`.
///
/// Applied to the substrate's ([`Atom::ESCAPE_TABLE`],
/// [`Atom::NAMED_ESCAPE_TABLE`], [`Atom::SELF_ESCAPE_TABLE`]) triple
/// at the module-level `const _: () = assert_char_pair_array_is_
/// concatenation_of_char_pair_array_and_char_array_diagonal::<5, 3,
/// 2>(&Atom::ESCAPE_TABLE, &Atom::NAMED_ESCAPE_TABLE,
/// &Atom::SELF_ESCAPE_TABLE);` witness below the helper. Pre-lift,
/// the identity `Atom::ESCAPE_TABLE == Atom::NAMED_ESCAPE_TABLE ++
/// diagonal(Atom::SELF_ESCAPE_TABLE)` lived ONLY implicitly at
/// `Atom::ESCAPE_TABLE`'s declaration site (positions `[0..3]`
/// indexing `Self::NAMED_ESCAPE_TABLE[0]`, `[1]`, `[2]`; positions
/// `[3..5]` materializing `(Self::SELF_ESCAPE_TABLE[0], Self::SELF_
/// ESCAPE_TABLE[0])` + `(Self::SELF_ESCAPE_TABLE[1], Self::SELF_
/// ESCAPE_TABLE[1])`). Post-lift, that identity binds at `cargo
/// check` time — a regression that reorders `Atom::ESCAPE_TABLE`'s
/// segments, drifts one entry across the three arrays, or changes
/// the diagonal-embedding shape at the tail fails the build rather
/// than the test suite. The five prior paired-array witnesses on
/// `Atom::ESCAPE_TABLE` bind INDIVIDUAL axes (pairwise-distinct,
/// bijective) OR CROSS-ROW column-projection bonds
/// (columns-equal-peer-scalars), but NONE bind the SEGMENTED
/// composite-construction identity that this helper closes.
///
/// Contract-strength peer to [`assert_char_pair_array_columns_equal_
/// char_arrays`] on the (segmented-cross-row-bond vs full-cross-row-
/// bond) axis: where the sibling binds the FULL two-column bond
/// against TWO peer scalar arrays at EVERY position, this helper
/// binds the SEGMENTED composite-construction bond against a peer
/// PAIRED array (head) and a peer SCALAR array (diagonal tail) split
/// at position `K`. The two helpers together close the
/// (paired-vs-peer, cross-row-projection) 2-dimensional surface on
/// the `(char, char)` row at ONE `const _` line per compound-bond
/// theorem — the full-column peer binds every position at the
/// (char, char) row of a paired array against TWO scalar peer
/// vocabularies; THIS peer binds the head segment against a paired
/// vocabulary and the diagonal tail against a scalar vocabulary
/// (embedded diagonally). Row-parallel to the SCALAR-row helpers on
/// the (element-type) axis — where those close INJECTIVITY /
/// COVERING / PERMUTATION on the scalar rows, this closes the
/// SEGMENTED-CONCATENATION corner on the PRODUCT-element row.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// tokenizer that constructs a `[(char, char); N]` paired array at
/// runtime and wants to verify SEGMENTED-CONCATENATION structure
/// before consuming it — and the panic surfaces normally in that
/// path. Every panic site names the helper AND identifies the failed
/// AXIS distinctly so downstream diagnostics route regressions back
/// to (a) the helper by string search on
/// `"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"`
/// and (b) the specific segment/column by axis-prefix.
///
/// Adding a new paired substrate array declared as CONCATENATION of a
/// peer paired vocabulary with a DIAGONAL-embedded peer scalar
/// vocabulary: pair the declaration with `const _: () = assert_char_
/// pair_array_is_concatenation_of_char_pair_array_and_char_array_
/// diagonal::<N, K, M>(&Self::FOO_TABLE, &Self::FOO_HEAD,
/// &Self::FOO_DIAG_TAIL);` co-located after the composite's
/// declaration and the compound identity binds at compile time
/// WITHOUT a runtime concat-and-zip loop.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the SEGMENTED composite-
/// construction identity becomes a TYPE-LEVEL theorem carried per
/// declaration triple rather than a runtime concat-and-zip loop
/// the developer must remember to write per triple.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs;
/// the (head-segment, diagonal-tail-segment) composition proof at
/// declaration site AND the peer-vocabulary consumers regenerate
/// through the SAME `const _` witness.
/// - THEORY.md §VI.1 — generation over composition; the SEGMENTED
/// concat-and-diagonal-embed sweep IS the generative shape. Every
/// new paired-array declared as a segmented concat with a
/// diagonal-embedded scalar tail adds ONE `const _` line to get
/// the compound theorem.
pub const fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal<
const N: usize,
const K: usize,
const M: usize,
>(
arr: &[(char, char); N],
head: &[(char, char); K],
tail_diag: &[char; M],
) {
if K + M != N {
panic!(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal: \
CARDINALITY-MISMATCH — the three const parameters `N`, \
`K`, `M` must satisfy `K + M == N` so the peer paired \
`head` (contributing positions `[0..K)` of the composite \
`arr`) followed by the peer scalar `tail_diag` (embedded \
diagonally as `(tail_diag[j], tail_diag[j])` at positions \
`[K..N)`) exactly cover `arr`'s `N` positions. Fix at the \
`const _` witness's turbofish by reconciling the three \
arities against the composite's declared arity. The \
CARDINALITY-MISMATCH gate distinguishes THIS failure from \
every content-drift arm — a mistyped ARITY on the caller \
side fails HERE before any per-position sweep begins, so \
a subtle arity slip doesn't silently degenerate into a \
truncated segment sweep."
);
}
let mut i = 0;
while i < K {
if arr[i].0 as u32 != head[i].0 as u32 {
panic!(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal: \
HEAD-SEGMENT-LEFT-DIVERGENCE — the composite paired \
array `arr` carries a LEFT-column entry at some \
position in `[0, K)` (the HEAD segment) that does NOT \
byte-for-byte equal the peer paired `head` array's \
LEFT-column entry at the SAME position. The \
substrate's SEGMENTED-CONCATENATION contract on the \
(composite, head-segment) HEAD-arm LEFT column is \
broken; every consumer that reads `arr[0..K)` and the \
peer `head` array as INTERCHANGEABLE (any outer-\
dispatch pattern-matcher on the head sub-vocabulary \
that expects the composite's HEAD segment to project \
verbatim to the peer paired vocabulary's LEFT column) \
relies on this invariant. Fix at one of the two \
declaration sites (`arr[0..K)` or `head`) by \
reconciling the entry across the two arrays."
);
}
if arr[i].1 as u32 != head[i].1 as u32 {
panic!(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal: \
HEAD-SEGMENT-RIGHT-DIVERGENCE — the composite paired \
array `arr` carries a RIGHT-column entry at some \
position in `[0, K)` (the HEAD segment) that does NOT \
byte-for-byte equal the peer paired `head` array's \
RIGHT-column entry at the SAME position. The \
substrate's SEGMENTED-CONCATENATION contract on the \
(composite, head-segment) HEAD-arm RIGHT column is \
broken; every consumer that reads the composite's \
head-segment RIGHT column as INTERCHANGEABLE with the \
peer paired vocabulary's RIGHT column relies on this \
invariant. Fix at one of the two declaration sites \
(`arr[0..K)` or `head`) by reconciling the entry."
);
}
i += 1;
}
let mut j = 0;
while j < M {
if arr[K + j].0 as u32 != tail_diag[j] as u32 {
panic!(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal: \
DIAGONAL-TAIL-SEGMENT-LEFT-DIVERGENCE — the composite \
paired array `arr` carries a LEFT-column entry at \
some position in `[K, N)` (the DIAGONAL TAIL segment) \
that does NOT byte-for-byte equal the peer scalar \
`tail_diag` array's entry at the SAME diagonal-\
embedded position. The substrate's DIAGONAL-EMBEDDING \
contract on the (composite, tail-segment) TAIL-arm \
LEFT column is broken; every consumer that reads \
`arr[K..N)` and the peer scalar `tail_diag` array as \
diagonally interchangeable (any outer-dispatch \
pattern-matcher on the tail sub-vocabulary that \
expects `arr[K + j]` to be `(tail_diag[j], \
tail_diag[j])`) relies on this invariant. Fix at one \
of the two declaration sites (`arr[K..N)` or \
`tail_diag`) by reconciling the entry."
);
}
if arr[K + j].1 as u32 != tail_diag[j] as u32 {
panic!(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal: \
DIAGONAL-TAIL-SEGMENT-RIGHT-DIVERGENCE — the \
composite paired array `arr` carries a RIGHT-column \
entry at some position in `[K, N)` (the DIAGONAL TAIL \
segment) that does NOT byte-for-byte equal the peer \
scalar `tail_diag` array's entry at the SAME \
diagonal-embedded position. The substrate's DIAGONAL-\
EMBEDDING contract on the (composite, tail-segment) \
TAIL-arm RIGHT column is broken; every consumer that \
reads the composite's tail-segment RIGHT column as \
diagonally interchangeable with `tail_diag[j]` relies \
on this invariant. Fix at one of the two declaration \
sites (`arr[K..N)` or `tail_diag`) by reconciling the \
entry."
);
}
j += 1;
}
}
// Compile-time SEGMENTED-CONCATENATION-with-DIAGONAL-TAIL witness —
// one `const _: () = assert_char_pair_array_is_concatenation_of_char_
// pair_array_and_char_array_diagonal::<5, 3, 2>(&…, &…, &…)` binding
// the (`Atom::ESCAPE_TABLE`, `Atom::NAMED_ESCAPE_TABLE`,
// `Atom::SELF_ESCAPE_TABLE`) three-way composite-construction bond on
// the substrate's Str-payload escape-table vocabulary.
// `Atom::ESCAPE_TABLE` (`[(char, char); 5]`) is CONSTRUCTED as
// `NAMED_ESCAPE_TABLE[0..=2]` (the HEAD segment) followed by two
// SELF-diagonal pairs `(SELF_ESCAPE_TABLE[0], SELF_ESCAPE_TABLE[0])` +
// `(SELF_ESCAPE_TABLE[1], SELF_ESCAPE_TABLE[1])` (the DIAGONAL TAIL
// segment). Pre-lift, the SEGMENTED composite identity lived ONLY as
// an implicit declaration-site expression that a refactor could
// silently drift by reordering the HEAD entries, drifting one entry
// across the three arrays, or changing the diagonal-embedding shape
// at the tail — the pre-existing `_within_char_pair_finite_set`,
// `_arrays_disjoint`, `_bijective`, `_pairwise_distinct`, and
// `_columns_equal_char_arrays` witnesses each bind ADJACENT axes but
// NONE bind the composite-construction structural identity. Post-
// lift, this const-eval witness binds that identity as a compile-
// time theorem so a regression that renames a source or decoded byte
// on ONE of the three arrays without updating the other two, OR
// reorders the HEAD segment's positions, OR breaks the diagonal-
// embedding at the TAIL, fails the build rather than the test suite.
// SIXTH witness on the SAME paired array in complementary posture to
// the FIVE prior const-eval sweeps — the SIX sweeps enforce
// complementary axes of the same substrate table at SIX stages of
// the toolchain, so a build that skips tests still catches
// composite-construction drift here.
const _: () =
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<5, 3, 2>(
&Atom::ESCAPE_TABLE,
&Atom::NAMED_ESCAPE_TABLE,
&Atom::SELF_ESCAPE_TABLE,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the sub-slice `full[START..START + M)` of the family-wide `[(char,
/// char); N]` paired substrate array `full` is NOT byte-for-byte equal
/// to the peer `[(char, char); M]` paired sub-array `sub` at the
/// offset-matched positions. Binds ONE compound (SLICE × PAIRED-
/// POSITIONWISE-EQUALITY) contract on the `(char, char)` product-
/// element row of the (element-type × contract-shape) matrix at the
/// (SUB-SLICE ARRAY-image) column — opens the FOURTH element-type row
/// of that column peer to the pre-existing (u8) sibling
/// [`assert_u8_array_slice_equals_u8_array`], (char) sibling
/// [`assert_char_array_slice_equals_char_array`], and (str) sibling
/// [`assert_str_array_slice_equals_str_array`]. Together the four
/// helpers close the (SUB-SLICE ARRAY-image) column across the FULL
/// (u8, char, str, (char, char)) element-type row set of the
/// (element-type × contract-shape) matrix.
///
/// Bounds preconditions: `START ≤ N` (inclusive upper bound —
/// `START == N` combined with `M == 0` is the LEGAL empty-slice-at-
/// right-endpoint corner) AND `M ≤ N - START` (inclusive upper bound —
/// `M == N - START` is the LEGAL exact-fit-to-right-endpoint corner).
/// The two bounds gates fire IN ORDER — `START` is validated FIRST so
/// the peer `M` gate can safely evaluate `N - START` without `usize`
/// underflow. A caller-side turbofish arity slip fails-loudly on the
/// specific bounds axis it violated BEFORE the positionwise sweep
/// reads `full[START + i]`, so a bounds slip doesn't silently
/// degenerate into a subtraction wrap-around OR a panic deeper in
/// `full[START + i]` bounds-checking.
///
/// Failure axes — the helper partitions its rejection surface into
/// FOUR disjoint arms, each with a DISTINCT axis-provenance prefix on
/// the panic message so downstream diagnostics route the drift back
/// to the specific gate (and, on the CONTENT arms, the specific
/// COLUMN of the paired sub-slice) that diverged:
/// 1. `START-OUT-OF-BOUNDS` — `START > N`.
/// 2. `SLICE-LENGTH-OUT-OF-BOUNDS` — `M > N - START` (the peer
/// `START` gate above guarantees `N - START` never underflows).
/// 3. `CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN-VIOLATION` — some
/// `i ∈ [0..M)` where `full[START + i].0 != sub[i].0` (LEFT
/// column of the paired positionwise sweep).
/// 4. `CHAR-PAIR-SLICE-EQUALS-ARRAY-RIGHT-COLUMN-VIOLATION` — some
/// `i ∈ [0..M)` where `full[START + i].1 != sub[i].1` (RIGHT
/// column of the paired positionwise sweep).
///
/// The two CONTENT arms split by COLUMN in the SAME style as the
/// sibling (char, char)-row [`assert_char_pair_array_columns_equal_
/// char_arrays`] helper's `LEFT-COLUMN-DIVERGENCE` /
/// `RIGHT-COLUMN-DIVERGENCE` split, so a diagnostic that names the
/// failed axis routes UNAMBIGUOUSLY to (a) this specific (char, char)-
/// row SLICE-EQUALS-ARRAY helper by string search on the axis substring
/// `-CHAR-PAIR-SLICE-EQUALS-ARRAY-` (distinguishing it from the sibling
/// `-CHAR-SLICE-EQUALS-ARRAY-` (char) row axis and the plain `-SLICE-
/// EQUALS-ARRAY-` (u8) row axis) and (b) the failed COLUMN by the
/// `-LEFT-COLUMN-` / `-RIGHT-COLUMN-` infix. The shared `-SLICE-EQUALS-
/// ARRAY-VIOLATION` suffix lets callers grep any of the FOUR element-
/// type variants by ONE substring.
///
/// Applied to the substrate's (`Atom::ESCAPE_TABLE`,
/// `Atom::NAMED_ESCAPE_TABLE`) pair at ONE module-level `const _: () =
/// assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 0>(&
/// Atom::ESCAPE_TABLE, &Atom::NAMED_ESCAPE_TABLE);` witness below the
/// helper. `Atom::ESCAPE_TABLE[0..3]` (`[(char, char); 3]` HEAD
/// segment) is byte-for-byte equal to `Atom::NAMED_ESCAPE_TABLE`
/// verbatim by declaration intent — the outer `ESCAPE_TABLE` array's
/// first three initializer slots each spell an entry drawn directly
/// from `NAMED_ESCAPE_TABLE`'s corresponding slot. Pre-lift, this
/// HEAD-segment positionwise-composition identity was bound TRANSITIVELY
/// through the sibling [`assert_char_pair_array_is_concatenation_of_
/// char_pair_array_and_char_array_diagonal`]`::<5, 3, 2>` witness on the
/// same three-array triple — that sibling binds the FULL composite
/// `ESCAPE_TABLE == NAMED_ESCAPE_TABLE ++ diagonal(SELF_ESCAPE_TABLE)`
/// so the HEAD is transitively bound alongside the DIAGONAL TAIL.
/// Post-lift, the HEAD-segment identity binds INDEPENDENTLY on its
/// OWN axis at ONE additional `const _` line — a regression that
/// silently broke the diagonal-tail binding (e.g. by swapping the
/// diagonal embedding to an anti-diagonal `(SELF[1], SELF[0])`)
/// would trip the sibling witness's `DIAGONAL-TAIL-*` arm alone;
/// this new witness continues to guarantee the HEAD-segment identity
/// on the CHAR-PAIR-SLICE-EQUALS-ARRAY-* axis regardless of the
/// tail's shape, so a HEAD-only drift (e.g. reordering the three
/// NAMED entries in ESCAPE_TABLE's initializer while leaving
/// NAMED_ESCAPE_TABLE's order intact) trips THIS witness's LEFT-
/// COLUMN / RIGHT-COLUMN axis on its OWN axis-provenance vocabulary.
/// The two witnesses partition the drift-detection surface by SEGMENT
/// (HEAD vs DIAGONAL TAIL) and by AXIS-PROVENANCE (SLICE-EQUALS-ARRAY
/// vs SEGMENTED-CONCATENATION-with-DIAGONAL-TAIL), catching each
/// SEGMENT's drift on the axis best suited to route the fix back to
/// the SPECIFIC declaration site at fault.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// tokenizer that constructs a paired sub-array at runtime and wants
/// to verify SLICE-EQUALS-ARRAY structure before consuming it — and
/// the panic surfaces normally in that path (pinned by
/// `assert_char_pair_array_slice_equals_char_pair_array_panics_at_
/// runtime_on_left_column_drift`,
/// `assert_char_pair_array_slice_equals_char_pair_array_panics_at_
/// runtime_on_right_column_drift`,
/// `assert_char_pair_array_slice_equals_char_pair_array_panics_at_
/// runtime_on_start_out_of_bounds`,
/// `assert_char_pair_array_slice_equals_char_pair_array_panics_at_
/// runtime_on_slice_length_out_of_bounds`, and the two axis-
/// provenance pins on the LEFT-COLUMN + RIGHT-COLUMN axes).
///
/// Adding a new family-wide `[(char, char); N]` substrate array whose
/// sub-slice is byte-for-byte equal to a peer paired sub-vocabulary's
/// canonical `[(char, char); M]` listing: pair the declaration with
/// `const _: () = assert_char_pair_array_slice_equals_char_pair_array::
/// <N, M, START>(&Self::FOO_TABLE, &Self::FOO_SUB_TABLE);` co-located
/// after the composite's declaration and the compound identity binds
/// at compile time.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the SLICE-EQUALS-ARRAY
/// positionwise-composition contract on the `(char, char)` paired
/// vocabulary becomes a TYPE-LEVEL theorem the substrate carries
/// per (container, sub-carving) pair rather than a runtime iterator
/// sweep the developer must remember to write per pair.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the (SUB-SLICE ARRAY-image) column
/// at ALL FOUR element-type rows — the (u8), (char), (str), and
/// `(char, char)` rows each ship a peer const-fn helper. The FOUR
/// helpers close the SUB-SLICE ARRAY-image column of the matrix.
/// - THEORY.md §VI.1 — generation over composition; the paired
/// positionwise sweep IS the generative shape. Every new paired
/// composite declared as a positionwise-composition against a peer
/// paired sub-vocabulary adds ONE `const _` line to get the
/// compound theorem rather than re-deriving a runtime
/// `full[START + i] == sub[i]` per-position sweep.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// SUB-SLICE positionwise-composition proof at declaration site AND
/// the peer-sub-vocabulary consumers that read the composite's sub-
/// slice regenerate through the SAME `const _` witness.
pub const fn assert_char_pair_array_slice_equals_char_pair_array<
const N: usize,
const M: usize,
const START: usize,
>(
full: &[(char, char); N],
sub: &[(char, char); M],
) {
if START > N {
panic!(
"assert_char_pair_array_slice_equals_char_pair_array: \
START-OUT-OF-BOUNDS — the const parameter `START` sits \
OUTSIDE the outer array's valid position range `[0..N]` \
(inclusive upper bound: `START == N` combined with `M == \
0` is the LEGAL empty-slice-at-right-endpoint corner). \
Fix at the `const _` witness's turbofish by reconciling \
`START` against the outer array's declared arity `N`. \
The START-OUT-OF-BOUNDS gate fires FIRST — a mistyped \
`START` on the caller side fails HERE before the peer \
`SLICE-LENGTH-OUT-OF-BOUNDS` gate reads `N - START` \
(which would underflow `usize` had this gate not caught \
the slip), so a subtle bounds slip doesn't silently \
degenerate into a subtraction wrap-around OR a panic \
deeper in `full[START + i]` bounds-checking."
);
}
if M > N - START {
panic!(
"assert_char_pair_array_slice_equals_char_pair_array: \
SLICE-LENGTH-OUT-OF-BOUNDS — the peer sub-array's arity \
`M` exceeds the outer array's tail cardinality `N - \
START`, so the positionwise sweep `full[START + i]` for \
`i ∈ [0..M)` would overrun the outer array's valid \
position range `[0..N)` at some `i ∈ [N - START..M)`. \
Fix at the `const _` witness's turbofish by reconciling \
`M` against the outer array's tail cardinality `N - \
START` OR by narrowing `START` to leave a longer tail. \
The peer `START-OUT-OF-BOUNDS` gate above guarantees \
`START ≤ N` so `N - START` never underflows `usize` at \
this gate. The LEGAL exact-fit corner `M == N - START` \
(the sub-array reaches EXACTLY to the outer array's \
right endpoint) is accepted; the STRICT `M > N - START` \
slip is what this gate rejects."
);
}
let mut i = 0;
while i < M {
if full[START + i].0 as u32 != sub[i].0 as u32 {
panic!(
"assert_char_pair_array_slice_equals_char_pair_array: \
CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN-VIOLATION — \
the outer `[(char, char); N]` paired array `full` \
carries a LEFT-column entry at some position `START + \
i` (for `i ∈ [0..M)`) that does NOT byte-equal the \
peer `[(char, char); M]` paired sub-array `sub` at \
the offset-matched position `i`. The substrate's \
(SLICE × PAIRED-POSITIONWISE-EQUALITY) contract on \
the LEFT column of the sub-slice `full[START..START + \
M) == sub[..]` is broken; every consumer that reads \
`full[START..START + M)`'s LEFT column as a \
positionwise-aligned copy of the peer paired sub-\
vocabulary's LEFT column (the substrate's Str-payload \
escape-table HEAD segment `Atom::ESCAPE_TABLE[0..3] \
== Atom::NAMED_ESCAPE_TABLE` — a regression that \
reordered ESCAPE_TABLE's first three initializer \
entries away from NAMED_ESCAPE_TABLE's canonical \
order without updating NAMED_ESCAPE_TABLE trips \
HERE on the LEFT column; any future container-array \
paired sub-slice byte-for-byte equal to a peer \
paired sub-vocabulary's canonical `[(char, char); \
M]` listing) relies on this invariant. Fix at the \
ARRAY-DECLARATION site (the drifted `full[START + \
i].0` slot inside the slice segment) OR at the peer \
paired sub-array's arm listing — the choice depends \
on whether the drift is an unintended slot reorder \
in the outer array's slice OR in the sub-carving's \
own listing. The LEFT-COLUMN-* axis prefix routes \
the fix specifically to the LEFT column of the \
paired sweep — a RIGHT-column drift would trip the \
peer RIGHT-COLUMN-* axis arm below on its OWN \
distinct axis-provenance vocabulary."
);
}
if full[START + i].1 as u32 != sub[i].1 as u32 {
panic!(
"assert_char_pair_array_slice_equals_char_pair_array: \
CHAR-PAIR-SLICE-EQUALS-ARRAY-RIGHT-COLUMN-VIOLATION \
— the outer `[(char, char); N]` paired array `full` \
carries a RIGHT-column entry at some position `START \
+ i` (for `i ∈ [0..M)`) that does NOT byte-equal the \
peer `[(char, char); M]` paired sub-array `sub` at \
the offset-matched position `i`. The substrate's \
(SLICE × PAIRED-POSITIONWISE-EQUALITY) contract on \
the RIGHT column of the sub-slice `full[START..START \
+ M) == sub[..]` is broken; every consumer that \
reads `full[START..START + M)`'s RIGHT column as a \
positionwise-aligned copy of the peer paired sub-\
vocabulary's RIGHT column (the substrate's Str-\
payload escape-table HEAD segment `Atom::ESCAPE_\
TABLE[0..3] == Atom::NAMED_ESCAPE_TABLE` — a \
regression that drifted a DECODED byte across \
ESCAPE_TABLE and NAMED_ESCAPE_TABLE without updating \
the other trips HERE on the RIGHT column; any \
future container-array paired sub-slice byte-for-\
byte equal to a peer paired sub-vocabulary's \
canonical `[(char, char); M]` listing) relies on \
this invariant. Fix at the ARRAY-DECLARATION site \
(the drifted `full[START + i].1` slot inside the \
slice segment) OR at the peer paired sub-array's \
arm listing — the choice depends on whether the \
drift is an unintended slot rewrite in the outer \
array's slice OR in the sub-carving's own listing. \
The RIGHT-COLUMN-* axis prefix routes the fix \
specifically to the RIGHT column of the paired \
sweep — a LEFT-column drift would trip the peer \
LEFT-COLUMN-* axis arm above on its OWN distinct \
axis-provenance vocabulary."
);
}
i += 1;
}
}
// Compile-time SLICE-EQUALS-ARRAY witness — the ONE `(container, sub-
// carving)` pair on the substrate whose ARRAY-LEVEL structure composes
// a paired container-array sub-slice byte-for-byte identical to a
// peer paired sub-carving's canonical `[(char, char); M]` listing.
// `Atom::ESCAPE_TABLE[0..3]` (the three-slot NAMED-escape HEAD segment
// of the outer five-slot Str-payload escape-table array) is byte-for-
// byte equal to `Atom::NAMED_ESCAPE_TABLE` verbatim — the outer
// ESCAPE_TABLE array's first three initializer slots each spell an
// entry drawn directly from NAMED_ESCAPE_TABLE's corresponding slot.
// Pre-lift, this HEAD-segment positionwise-composition identity was
// bound TRANSITIVELY through the sibling `assert_char_pair_array_is_
// concatenation_of_char_pair_array_and_char_array_diagonal::<5, 3, 2>`
// witness at line ~3909 above (that sibling binds the FULL composite
// `ESCAPE_TABLE == NAMED_ESCAPE_TABLE ++ diagonal(SELF_ESCAPE_TABLE)`
// so the HEAD segment is bound alongside the DIAGONAL TAIL through a
// single composite-construction proof); post-lift, the HEAD segment
// binds INDEPENDENTLY on the (SLICE × PAIRED-POSITIONWISE-EQUALITY)
// axis at ONE additional `const _` line, routing any HEAD-only drift
// (e.g. reordering ESCAPE_TABLE's first three initializer entries
// while leaving NAMED_ESCAPE_TABLE's order intact) through the
// CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN / -RIGHT-COLUMN axis-
// provenance vocabulary rather than the sibling's `HEAD-SEGMENT-
// LEFT-DIVERGENCE` / `HEAD-SEGMENT-RIGHT-DIVERGENCE` axis-
// provenance vocabulary. The two witnesses partition the drift-
// detection surface by SEGMENT and AXIS-PROVENANCE.
//
// Sibling posture to the FOUR (str)-row per-position witnesses on
// `crate::error::SexpShape::LABELS` in `error.rs` (four
// `assert_str_array_slice_equals_str_array::<12, {1,3,4,6,8,12},
// {0,1,7,8}>` witnesses that positionally decompose the twelve-slot
// LABELS parent array against its four sub-carvings' LABELS arrays)
// and to the TWO singleton + ONE four-slot (u8)-row witnesses on
// `SexpShape::HASH_DISCRIMINATORS` in this file. Those siblings each
// carry the sub-carving-projection SLICE-EQUALS-ARRAY sweep at the
// (u8) row and the (str) row of the (SUB-SLICE ARRAY-image) column;
// this witness opens the SAME sweep at the `(char, char)` product-
// element row on the SAME column. Together the (u8, char, str, (char,
// char)) FOUR-row column closure carries the (SUB-SLICE ARRAY-image)
// column of the (element-type × contract-shape) matrix across the
// FULL element-type row set the substrate declares family-wide
// arrays for at rustc time.
const _: () = assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 0>(
&Atom::ESCAPE_TABLE,
&Atom::NAMED_ESCAPE_TABLE,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the family-wide `[char; N]` scalar substrate array `arr` is NOT byte-
/// for-byte equal to the CONCATENATION of the SELECTED COLUMN of the
/// peer paired `[(char, char); K]` array `head_table` (contributing the
/// FIRST `K` positions of `arr` verbatim as either
/// `head_table[i].0` — LEFT column when `take_right_column == false` —
/// or `head_table[i].1` — RIGHT column when `take_right_column == true`)
/// followed by the peer scalar `[char; M]` array `tail` (contributing
/// the REMAINING `M = N - K` positions verbatim at position `K + j`).
/// Binds ONE compound (SEGMENTED-CONCATENATION × PAIRED-COLUMN-
/// PROJECTION) contract clause on the (char) scalar-element row of the
/// (element-type × contract-shape) matrix at a fresh (concat-through-
/// paired-column-projection) column — an ORDERING-SENSITIVE SEGMENTED-
/// POSITIONWISE contract joining the pre-existing (pairwise-distinct),
/// (arrays-disjoint), and (within-char-finite-set) columns on the SAME
/// (char) scalar-element row.
///
/// Cardinality precondition: `K + M == N` — the caller passes the
/// three const parameters explicitly (`N`, `K`, `M`), and the helper's
/// FIRST arm fires at const-eval if the three fail to sum. A caller
/// who supplies mismatched arities (e.g. `<5, 3, 3>` — `K + M == 6 ≠
/// N == 5`) fails-loudly at the CARDINALITY-MISMATCH panic BEFORE the
/// sweep begins, so a mistyped ARITY doesn't degenerate into a silent
/// truncation of the scalar composite array. Sibling-shape to the
/// paired-row helper [`assert_char_pair_array_is_concatenation_of_
/// char_pair_array_and_char_array_diagonal`]'s `CARDINALITY-MISMATCH`
/// pre-arm on the SAME cardinality axis.
///
/// Failure axes — the helper partitions its rejection surface into
/// FOUR disjoint arms, each with a DISTINCT axis-provenance prefix on
/// the panic message so downstream diagnostics route the drift back
/// to the specific SEGMENT (and, on the HEAD arm, the specific
/// COLUMN) that diverged:
/// 1. `CARDINALITY-MISMATCH` — `K + M != N`.
/// 2. `HEAD-SEGMENT-LEFT-COLUMN-DIVERGENCE` — `take_right_column ==
/// false` AND some `i ∈ [0, K)` where `arr[i] != head_table[i].0`.
/// 3. `HEAD-SEGMENT-RIGHT-COLUMN-DIVERGENCE` — `take_right_column ==
/// true` AND some `i ∈ [0, K)` where `arr[i] != head_table[i].1`.
/// 4. `TAIL-SEGMENT-DIVERGENCE` — some `j ∈ [0, M)` where
/// `arr[K + j] != tail[j]` (INDEPENDENT of `take_right_column`
/// since the tail is a scalar `[char; M]` array projected verbatim,
/// not through a paired column).
///
/// Applied to the substrate's ([`Atom::ESCAPE_SOURCES`],
/// [`Atom::NAMED_ESCAPE_TABLE`], [`Atom::SELF_ESCAPE_TABLE`]) triple
/// (LEFT-column projection) AND the ([`Atom::ESCAPE_DECODED`],
/// [`Atom::NAMED_ESCAPE_TABLE`], [`Atom::SELF_ESCAPE_TABLE`]) triple
/// (RIGHT-column projection) at TWO module-level `const _: () =
/// assert_char_array_is_concatenation_of_char_pair_array_column_and_
/// char_array::<5, 3, 2>(&…, &Atom::NAMED_ESCAPE_TABLE,
/// &Atom::SELF_ESCAPE_TABLE, take_right_column);` witnesses below
/// the helper. Pre-lift, the composition law
/// ```ignore
/// ESCAPE_SOURCES == [NAMED_ESCAPE_TABLE[0].0, NAMED_ESCAPE_TABLE[1].0,
/// NAMED_ESCAPE_TABLE[2].0, SELF_ESCAPE_TABLE[0],
/// SELF_ESCAPE_TABLE[1]]
/// ESCAPE_DECODED == [NAMED_ESCAPE_TABLE[0].1, NAMED_ESCAPE_TABLE[1].1,
/// NAMED_ESCAPE_TABLE[2].1, SELF_ESCAPE_TABLE[0],
/// SELF_ESCAPE_TABLE[1]]
/// ```
/// lived ONLY as PROSE at [`Atom::ESCAPE_SOURCES`]'s and
/// [`Atom::ESCAPE_DECODED`]'s docstrings (each explicitly names the
/// "NAMED-column prefix + SELF-column suffix" partition) plus as an
/// implicit transitive consequence of the pre-existing
/// (`_columns_equal_char_arrays` on `ESCAPE_TABLE` against the two
/// scalar peer columns) + (`_is_concatenation_of_char_pair_array_and_
/// char_array_diagonal` on `ESCAPE_TABLE` against `NAMED_ESCAPE_TABLE`
/// and diagonal-embedded `SELF_ESCAPE_TABLE`) witness pair. Neither
/// pre-existing witness DIRECTLY binds the scalar-projection identity
/// on `ESCAPE_SOURCES` and `ESCAPE_DECODED` at the char-array level
/// — the two scalar arrays could be independently mutated (e.g.
/// reorder `ESCAPE_SOURCES`'s five entries so its LEFT-column is no
/// longer NAMED-source-prefix + SELF-suffix in the canonical order)
/// while both prior witnesses continue to hold on the paired
/// `ESCAPE_TABLE`. Post-lift, that scalar-projection identity binds
/// at `cargo check` time — a regression that reorders EITHER of the
/// two scalar arrays' entries away from the "NAMED-column-prefix +
/// SELF-suffix" partition, drifts one entry across NAMED_ESCAPE_TABLE
/// and its scalar-column projection, or breaks the SELF-suffix
/// verbatim-embedding at the tail, fails the build rather than the
/// test suite.
///
/// Contract-strength peer to [`assert_char_pair_array_is_
/// concatenation_of_char_pair_array_and_char_array_diagonal`] on the
/// (scalar-vs-paired composite element type) axis: where the sibling
/// binds the paired composite's SEGMENTED-CONCATENATION identity
/// against a paired HEAD and a DIAGONAL-EMBEDDED scalar TAIL at the
/// (char, char) row, this helper binds the SCALAR composite's
/// SEGMENTED-CONCATENATION identity against a SELECTED COLUMN of a
/// paired HEAD and a VERBATIM scalar TAIL at the (char) row. The two
/// helpers together close the CROSS-ROW SEGMENTED-CONCATENATION
/// surface across the (char, char) × (char) element-type product:
/// * `[(char, char); N] == [(char, char); K] ++ diagonal([char; M])`
/// at the paired-row diagonal-tail helper (existing);
/// * `[char; N] == col(paired [(char, char); K]) ++ [char; M]` at
/// the scalar-row column-projection helper (this one).
///
/// Both helpers compose against the SAME
/// ([`Atom::NAMED_ESCAPE_TABLE`], [`Atom::SELF_ESCAPE_TABLE`]) peer
/// pair — the paired-row helper reads `NAMED_ESCAPE_TABLE`'s BOTH
/// columns verbatim into `ESCAPE_TABLE[0..3]` + a diagonal embedding
/// of `SELF_ESCAPE_TABLE` at `ESCAPE_TABLE[3..5]`; this scalar-row
/// helper reads ONE column of `NAMED_ESCAPE_TABLE` into `ESCAPE_
/// SOURCES[0..3]` / `ESCAPE_DECODED[0..3]` + `SELF_ESCAPE_TABLE`
/// verbatim into positions `[3..5]`. The two-witness closure over
/// `take_right_column ∈ {false, true}` bonds the (LEFT, RIGHT)
/// scalar-column projection pair at ONE const-eval sweep per column,
/// binding TWO substrate composition laws through the SAME primitive.
///
/// The `take_right_column: bool` parameter routes the head-segment
/// sweep to the corresponding column of the paired `head_table`:
/// * `false` selects LEFT (`head_table[i].0`) — the pattern-SOURCE
/// column (the byte the reader sees BEFORE decoding an escape).
/// * `true` selects RIGHT (`head_table[i].1`) — the pattern-DECODED
/// column (the byte the reader emits AFTER decoding an escape).
///
/// The runtime bool composes with const-eval so BOTH substrate
/// witnesses (LEFT for `ESCAPE_SOURCES`, RIGHT for `ESCAPE_DECODED`)
/// share ONE primitive definition — halving the per-helper source
/// surface while keeping the per-column panic message DISTINCT via
/// the two `HEAD-SEGMENT-LEFT-COLUMN-DIVERGENCE` /
/// `HEAD-SEGMENT-RIGHT-COLUMN-DIVERGENCE` axes.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — e.g. a REPL / LSP
/// tokenizer that constructs a scalar `[char; N]` composite from a
/// paired-column projection AND a scalar peer tail at runtime and
/// wants to verify SEGMENTED-CONCATENATION structure before consuming
/// it. Every panic site names the helper AND identifies the failed
/// AXIS distinctly so downstream diagnostics route regressions back
/// to (a) the helper by string search on
/// `"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"`
/// and (b) the specific segment/column by axis-prefix. The four axis-
/// provenance strings (`CARDINALITY-MISMATCH`, `HEAD-SEGMENT-LEFT-
/// COLUMN-DIVERGENCE`, `HEAD-SEGMENT-RIGHT-COLUMN-DIVERGENCE`, `TAIL-
/// SEGMENT-DIVERGENCE`) are chosen DISTINCT from every sibling
/// helper's axis vocabulary (`HEAD-SEGMENT-LEFT-DIVERGENCE` /
/// `HEAD-SEGMENT-RIGHT-DIVERGENCE` / `DIAGONAL-TAIL-SEGMENT-LEFT-
/// DIVERGENCE` / `DIAGONAL-TAIL-SEGMENT-RIGHT-DIVERGENCE` on the
/// paired-row diagonal-tail sibling; `LEFT-COLUMN-DIVERGENCE` /
/// `RIGHT-COLUMN-DIVERGENCE` on the paired-row `_columns_equal_char_
/// arrays` sibling) so a diagnostic that names the failed axis routes
/// UNAMBIGUOUSLY to (a) this specific (char) scalar-row
/// column-projection concatenation helper, (b) the failed SEGMENT
/// (HEAD vs TAIL), (c) the failed COLUMN on the HEAD segment (LEFT
/// vs RIGHT). The `-COLUMN-` infix distinguishes this helper's HEAD
/// arms from the sibling paired-row diagonal-tail helper's HEAD arms
/// on any downstream substring search.
///
/// Adding a new scalar `[char; N]` substrate array declared as
/// CONCATENATION of a SELECTED COLUMN of a peer paired `[(char,
/// char); K]` vocabulary with a peer scalar `[char; M]` tail (e.g. a
/// future extension to `Atom::decode_str_escape` whose SOURCE or
/// DECODED SPAN grows through a new NAMED-column-prefix + SELF-suffix
/// partition): pair the declaration with `const _: () = assert_char_
/// array_is_concatenation_of_char_pair_array_column_and_char_array::
/// <N, K, M>(&Self::FOO_SPAN, &Self::FOO_TABLE, &Self::FOO_TAIL,
/// take_right_column);` co-located after the composite's
/// declaration and the compound identity binds at compile time
/// WITHOUT a runtime concat-and-project loop.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the SEGMENTED composite-
/// construction identity on the CROSS-ROW (paired → scalar) column-
/// projection axis becomes a TYPE-LEVEL theorem carried per
/// declaration triple rather than a runtime concat-and-project loop
/// the developer must remember to write per triple.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) matrix now carries the CROSS-ROW (paired-column ⊕
/// scalar-tail → scalar-composite) segmented-concatenation corner
/// at ONE peer const-fn helper. Combined with the pre-existing
/// (char, char)-row diagonal-tail sibling, the two helpers close
/// the CROSS-ROW SEGMENTED-CONCATENATION face of the substrate's
/// Str-payload escape-table product-vocabulary.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// (paired-column-head-segment, scalar-tail-segment) composition
/// proof at declaration site AND the peer-vocabulary consumers
/// regenerate through the SAME `const _` witness at the (char)
/// scalar row.
/// - THEORY.md §VI.1 — generation over composition; the paired-
/// column-project + scalar-verbatim-copy sweep IS the generative
/// shape. Every new scalar-composite declared as a segmented
/// concatenation-through-column-projection adds ONE `const _` line
/// to get the compound theorem.
///
/// Frontier inspiration: MLIR's typed IR-rewriter pattern of
/// projecting a wider tuple-typed operation into its per-column
/// scalar residual through a rewrite pass. Where MLIR routes the
/// projection through a Pass-driven rewrite that fires at IR
/// compilation, this helper routes the projection through a rustc
/// const-eval-time proof obligation at every scalar-composite
/// declaration site — the composition law binds as a type-level
/// theorem at `cargo check` rather than as an IR-rewrite-time check
/// deferred to a compilation stage the substrate's `pub const`
/// declarations never enter.
pub const fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array<
const N: usize,
const K: usize,
const M: usize,
>(
arr: &[char; N],
head_table: &[(char, char); K],
tail: &[char; M],
take_right_column: bool,
) {
if K + M != N {
panic!(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array: \
CARDINALITY-MISMATCH — the three const parameters `N`, \
`K`, `M` must satisfy `K + M == N` so the SELECTED column \
projection of the peer paired `head_table` (contributing \
positions `[0..K)` of the composite scalar `arr`) followed \
by the peer scalar `tail` (contributing positions `[K..N)` \
of `arr` verbatim) exactly cover `arr`'s `N` positions. \
Fix at the `const _` witness's turbofish by reconciling \
the three arities against the composite's declared arity. \
The CARDINALITY-MISMATCH gate distinguishes THIS failure \
from every content-drift arm — a mistyped ARITY on the \
caller side fails HERE before any per-position sweep \
begins, so a subtle arity slip doesn't silently degenerate \
into a truncated segment sweep."
);
}
let mut i = 0;
while i < K {
if take_right_column {
if arr[i] as u32 != head_table[i].1 as u32 {
panic!(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array: \
HEAD-SEGMENT-RIGHT-COLUMN-DIVERGENCE — the \
composite scalar array `arr` carries an entry at \
some position in `[0, K)` (the HEAD segment) that \
does NOT byte-for-byte equal the peer paired \
`head_table` array's RIGHT-column entry at the \
SAME position (i.e. `arr[i] != head_table[i].1`). \
The substrate's SEGMENTED-CONCATENATION-through-\
PAIRED-COLUMN-PROJECTION contract on the \
(composite scalar, head-segment) HEAD-arm RIGHT \
column is broken; every consumer that reads \
`arr[0..K)` and the RIGHT-column projection of \
`head_table` as INTERCHANGEABLE (any outer-\
dispatch pattern-matcher on the head sub-\
vocabulary that expects the composite's HEAD \
segment to project verbatim to the peer paired \
vocabulary's RIGHT column) relies on this \
invariant. Fix at one of the two declaration \
sites (`arr[0..K)` or `head_table`) by reconciling \
the entry across the two arrays."
);
}
} else if arr[i] as u32 != head_table[i].0 as u32 {
panic!(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array: \
HEAD-SEGMENT-LEFT-COLUMN-DIVERGENCE — the composite \
scalar array `arr` carries an entry at some position \
in `[0, K)` (the HEAD segment) that does NOT byte-for-\
byte equal the peer paired `head_table` array's LEFT-\
column entry at the SAME position (i.e. `arr[i] != \
head_table[i].0`). The substrate's SEGMENTED-\
CONCATENATION-through-PAIRED-COLUMN-PROJECTION \
contract on the (composite scalar, head-segment) \
HEAD-arm LEFT column is broken; every consumer that \
reads `arr[0..K)` and the LEFT-column projection of \
`head_table` as INTERCHANGEABLE (any outer-dispatch \
pattern-matcher on the head sub-vocabulary that \
expects the composite's HEAD segment to project \
verbatim to the peer paired vocabulary's LEFT column) \
relies on this invariant. Fix at one of the two \
declaration sites (`arr[0..K)` or `head_table`) by \
reconciling the entry across the two arrays."
);
}
i += 1;
}
let mut j = 0;
while j < M {
if arr[K + j] as u32 != tail[j] as u32 {
panic!(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array: \
TAIL-SEGMENT-DIVERGENCE — the composite scalar array \
`arr` carries an entry at some position in `[K, N)` \
(the TAIL segment) that does NOT byte-for-byte equal \
the peer scalar `tail` array's entry at the SAME \
position offset (i.e. `arr[K + j] != tail[j]`). The \
substrate's SEGMENTED-CONCATENATION-through-PAIRED-\
COLUMN-PROJECTION contract on the (composite scalar, \
tail-segment) TAIL-arm is broken; every consumer that \
reads `arr[K..N)` and the peer scalar `tail` array as \
verbatim-interchangeable relies on this invariant. \
Fix at one of the two declaration sites (`arr[K..N)` \
or `tail`) by reconciling the entry. The TAIL-SEGMENT \
arm is INDEPENDENT of `take_right_column` because the \
tail is a scalar array projected verbatim into the \
composite rather than routed through a paired-column \
projection at the head."
);
}
j += 1;
}
}
// Compile-time SEGMENTED-CONCATENATION-through-PAIRED-COLUMN-PROJECTION
// witnesses — two `const _: () = assert_char_array_is_concatenation_
// of_char_pair_array_column_and_char_array::<5, 3, 2>(&…, &Atom::
// NAMED_ESCAPE_TABLE, &Atom::SELF_ESCAPE_TABLE, take_right_column)`
// lines binding the (`Atom::ESCAPE_SOURCES`, `Atom::NAMED_ESCAPE_TABLE`,
// `Atom::SELF_ESCAPE_TABLE`) LEFT-column-projection triple AND the
// (`Atom::ESCAPE_DECODED`, `Atom::NAMED_ESCAPE_TABLE`,
// `Atom::SELF_ESCAPE_TABLE`) RIGHT-column-projection triple on the
// substrate's Str-payload escape-table product-vocabulary at ONE
// const-eval sweep per scalar-column projection. `Atom::ESCAPE_SOURCES`
// (`[char; 5]`) is CONSTRUCTED as `NAMED_ESCAPE_TABLE`'s LEFT-column
// projection at positions `[0..3]` followed by `SELF_ESCAPE_TABLE`
// verbatim at positions `[3..5]`; `Atom::ESCAPE_DECODED` (`[char; 5]`)
// is CONSTRUCTED as `NAMED_ESCAPE_TABLE`'s RIGHT-column projection at
// positions `[0..3]` followed by `SELF_ESCAPE_TABLE` verbatim at
// positions `[3..5]` (SELF's pattern-EQUALS-value property collapses
// the SELF-column-projection into SELF-verbatim on BOTH scalar
// composite arrays). Pre-lift, the two scalar-projection identities
// lived ONLY as PROSE at [`Atom::ESCAPE_SOURCES`]'s and
// [`Atom::ESCAPE_DECODED`]'s docstrings AND as implicit transitive
// consequences of the pre-existing (`_columns_equal_char_arrays` on
// `ESCAPE_TABLE` against the two scalar peer columns) +
// (`_is_concatenation_of_char_pair_array_and_char_array_diagonal` on
// `ESCAPE_TABLE` against `NAMED_ESCAPE_TABLE` and diagonal-embedded
// `SELF_ESCAPE_TABLE`) witness pair — neither pre-existing witness
// DIRECTLY binds the scalar-projection identity on the two `[char; 5]`
// scalar composite arrays at the char-array level. Post-lift, the two
// scalar-projection identities bind at `cargo check` time — a
// regression that reorders EITHER scalar composite's five entries so
// its NAMED-column-prefix + SELF-suffix partition breaks, drifts one
// entry across NAMED_ESCAPE_TABLE and its scalar-column projection, or
// silently drops a SELF-suffix entry from EITHER scalar composite,
// fails the build rather than the test suite. Sibling to the pre-
// existing (`_pairwise_distinct` on `ESCAPE_SOURCES` +
// `_pairwise_distinct` on `ESCAPE_DECODED` +
// `_within_char_finite_set` on `ESCAPE_SOURCES` +
// `_within_char_finite_set` on `ESCAPE_DECODED`) witnesses above on
// the SAME two scalar arrays — the four prior witnesses bind SET-level
// axes (INJECTIVITY, SUBSET-EMBEDDING) at the scalar-composite level
// without pinning the SEGMENTED-CONCATENATION structural identity;
// these two new witnesses close that structural identity as compile-
// time theorems on the SAME two scalar arrays. The four SET-level
// axes on the two scalar arrays combine with the two SEGMENTED-
// CONCATENATION axes here to give downstream consumers a SIX-witness
// closure on each scalar composite (four SET-level axes plus the
// SEGMENTED structural axis routing through EITHER the LEFT-column or
// RIGHT-column projection of the peer paired vocabulary).
const _: () = assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<5, 3, 2>(
&Atom::ESCAPE_SOURCES,
&Atom::NAMED_ESCAPE_TABLE,
&Atom::SELF_ESCAPE_TABLE,
false,
);
const _: () = assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<5, 3, 2>(
&Atom::ESCAPE_DECODED,
&Atom::NAMED_ESCAPE_TABLE,
&Atom::SELF_ESCAPE_TABLE,
true,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the distinct-values set of `arr` does not equal exactly the inclusive
/// range `{LO..=HI}` on the substrate's `u8` cache-key vocabulary. Binds
/// TWO conjunct clauses at ONE `const _` line:
/// 1. RANGE-BOUND: every entry lies within `[LO, HI]` — no byte
/// outside the target partition. A regression that drifts ONE
/// entry above `HI` or below `LO` (e.g. lifts a fresh entry at
/// `7u8` on a `{0..=6}` array) fails-loudly at const-eval.
/// 2. FULL-COVERAGE: every byte in `[LO..=HI]` appears at least once
/// in `arr` — no byte inside the target partition missing. A
/// regression that silently unifies two entries onto ONE byte,
/// leaving another byte in the range unreached (e.g. drops the
/// `Nil` arm's `0u8` from `SexpShape::HASH_DISCRIMINATORS` in
/// favour of a redundant `1u8`), fails-loudly at const-eval too.
///
/// The RANGE-COVERAGE contract is a NON-INJECTIVE peer of the
/// pre-existing pairwise-DISTINCTNESS contract
/// ([`assert_u8_array_pairwise_distinct`]) on the SAME `u8` cache-key
/// vocabulary: where distinctness is the INJECTIVITY axis (every entry
/// unique), range-coverage is the SURJECTIVITY-onto-a-range axis (every
/// range byte reached, entries CAN duplicate). Applied to arrays where
/// duplicates are load-bearing by construction — [`SexpShape::
/// HASH_DISCRIMINATORS`](crate::error::SexpShape::HASH_DISCRIMINATORS)
/// (`[u8; 12]` covering `{0..=6}` with SIX atomic-shape arms all
/// collapsing to the outer Atom marker byte `1u8`) is the archetype
/// case, intentionally omitted from the distinctness sweep per the
/// twelve-shape → seven-byte collapse rule documented on the
/// pairwise-distinct helper above; this range-coverage helper binds
/// the outer-partition contract at compile time despite the six-fold
/// collapse.
///
/// The invariant is load-bearing for the outer-`Sexp` cache-key
/// algebra's SPAN across the shape-level projection surface. The
/// twelve-arm sweep of `SexpShape::HASH_DISCRIMINATORS` MUST cover
/// exactly the outer discriminator space `{0..=6}` — no byte outside
/// (a `7u8` drift would introduce an unreachable cache slot for
/// [`crate::macro_expand::Expander::cache`]), no byte inside missing
/// (a `2u8` drop would silently unhash every `Sexp::List(_)` through
/// whatever cache slot the drift routes to). Every future family-wide
/// `[u8; N]` array whose distinct-value set is an intentionally-
/// closed inclusive range participates in the SAME compile-time
/// guarantee via one `const _` line.
///
/// Adding a new family-wide `[u8; N]` range-covering array to the
/// substrate: pair the declaration with `const _: () =
/// assert_u8_array_covers_inclusive_range::<N, LO, HI>(&Self::FOO_
/// ARRAY);` co-located after the array's declaration and the range-
/// coverage contract binds at compile time. The rustc-forced arity
/// `[u8; N]` composes with this const-eval sweep so cardinality AND
/// range-bound AND full-coverage are ALL compile-time theorems on the
/// SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_array_covers_inclusive_range_panics_at_runtime_on_
/// out_of_range_entry` + `assert_u8_array_covers_inclusive_range_
/// panics_at_runtime_on_missing_range_byte`. Both panic sites carry
/// axis-provenance strings so downstream diagnostics (`cargo check`
/// const-eval error output, test-suite failure reports) route the
/// drift back to the failed axis (RANGE-BOUND vs. FULL-COVERAGE) by
/// string search — halving the search space for the operator
/// debugging the drift.
///
/// Cross-argument constraint: `LO <= HI` is required — a caller who
/// passes `LO > HI` fails-loudly at the first `LO..=HI` sweep step
/// (the `while cur <= HI` guard rejects immediately) with a
/// well-defined "empty range" outcome that is nonetheless surfaced as
/// a full-coverage failure since `arr` must then be empty (`N == 0`).
/// The three-parameter shape `(N, LO, HI)` composes rustc's forced
/// arity `[u8; N]` with the two const-parameter bounds so ALL THREE
/// invariants (cardinality, min-bound, max-bound) are compile-time
/// theorems on the SAME `const _` line.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide range-
/// coverage contract on the `u8` cache-key vocabulary becomes a
/// TYPE-LEVEL theorem the substrate carries per array declaration
/// rather than a runtime test the developer must remember to write
/// per array (one range-bound sweep + one full-coverage sweep).
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the range-coverage arrays on the typed algebra makes
/// attestation-key drift a compile error rather than a silent
/// BLAKE3 mis-hash on any consumer keyed on `Hash for Sexp`. A
/// regression that drops a byte from the outer partition (or adds
/// an out-of-range byte) fails the build before it can silently
/// invalidate a cached expansion or a Sekiban audit-trail metric
/// keyed on the outer discriminator space.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// range-and-coverage sweep IS the generative shape. Every new
/// closed-set discriminator array whose distinct-value set is an
/// intentionally-closed inclusive range adds ONE `const _` line to
/// get the range-coverage theorem rather than re-deriving two
/// per-array runtime iterator sweeps (one for the range bound, one
/// for the coverage completeness).
///
/// Element-type sibling posture to the four pre-existing const-fn
/// contract verifiers ([`assert_char_array_pairwise_distinct`],
/// [`assert_str_array_pairwise_distinct`],
/// [`assert_u8_array_pairwise_distinct`],
/// [`assert_char_pair_array_bijective`]): where the four
/// distinctness/bijectivity helpers close the INJECTIVITY axis of the
/// substrate's typed-array vocabulary, this range-coverage helper
/// opens the SURJECTIVITY-onto-a-range axis on the SAME `u8` cache-key
/// element type — extending the family-wide contract-verifier surface
/// past the closed-set distinctness axis onto the closed-set covering
/// axis.
pub const fn assert_u8_array_covers_inclusive_range<const N: usize, const LO: u8, const HI: u8>(
arr: &[u8; N],
) {
let mut i = 0;
while i < N {
if arr[i] < LO || arr[i] > HI {
panic!(
"assert_u8_array_covers_inclusive_range: family-wide \
u8 array carries an OUT-OF-RANGE entry at some \
position — the entry's byte lies outside the target \
inclusive range `[LO, HI]`. The substrate's RANGE-\
BOUND contract on the array is broken; every \
consumer that expects the array's entries to \
partition an outer cache-key space (Hash for Sexp's \
outer discriminator space, StructuralKind / \
AtomKind / QuoteForm sub-carving spaces) relies on \
the entries staying within the target range",
);
}
i += 1;
}
let mut cur = LO;
loop {
let mut k = 0;
let mut found = false;
while k < N {
if arr[k] == cur {
found = true;
break;
}
k += 1;
}
if !found {
panic!(
"assert_u8_array_covers_inclusive_range: family-wide \
u8 array is MISSING a byte from the target inclusive \
range `[LO, HI]` — every byte in the range must \
appear at least once in the array. The substrate's \
FULL-COVERAGE contract on the array is broken; every \
consumer that expects the array's distinct-value set \
to span the target range (SexpShape's twelve-shape → \
seven-byte outer collapse across `{{0..=6}}`, the \
sub-carvings' partition-span contracts) relies on \
every range byte being reached",
);
}
if cur == HI {
break;
}
cur += 1;
}
}
// Compile-time range-coverage witnesses — one `const _: () =
// assert_u8_array_covers_inclusive_range::<N, LO, HI>(&…)` per
// family-wide `[u8; N]` hash-discriminator array on the substrate's
// closed-set outer algebras whose distinct-value set is an
// intentionally-closed inclusive range AND WHOSE JOINT (INJECTIVITY,
// SURJECTIVITY, ARITY) CONTRACT DOES NOT BIND THROUGH THE STRONGER
// COMPOUND `assert_u8_array_permutes_inclusive_range` HELPER BELOW.
// Each invocation is const-evaluated at `cargo check` time; a
// regression that silently drifts an entry above HI, below LO, OR
// silently drops a range byte from the distinct-value set fails the
// build rather than the test suite. Sibling to the runtime
// `_span_outer_partition_*` / `_covers_*` tests at `error.rs`'s
// tests module — the two enforce the same theorem at TWO stages of
// the toolchain, so a build that skips tests still catches the
// regression here, and a build that runs tests catches it a second
// time as a safety net if the const-eval sweep is ever silently
// dropped. The three permutation-shaped sub-carvings
// (`AtomKind::HASH_DISCRIMINATORS`, `QuoteForm::HASH_DISCRIMINATORS`,
// `UnquoteForm::HASH_DISCRIMINATORS`) bind SURJECTIVITY-onto-a-range
// through the stronger compound `assert_u8_array_permutes_inclusive_
// range` helper below — the compound helper composes injectivity ∧
// surjectivity ∧ arity-cardinality-match at ONE `const _` line per
// array, halving the per-array witness surface at strictly stronger
// contract strength. Only `SexpShape::HASH_DISCRIMINATORS` remains
// on this single-axis SURJECTIVITY sweep because its intentionally-
// non-injective twelve-shape → seven-byte collapse means DISTINCTNESS
// DOES NOT hold (the six atomic-shape arms all collapse to `1u8`)
// yet range-coverage of `{0..=6}` DOES hold (every outer byte
// reached) — it CANNOT bind a permutation contract on any range
// corner. `StructuralKind::HASH_DISCRIMINATORS` covers the non-
// inclusive-range partition `{0, 2}` (gap at `1u8` where the
// atomic-carve outer marker lives, per the outer-`Sexp` carve
// semantics) — intentionally OMITTED from this range-coverage sweep
// since its distinct-value set is not a contiguous inclusive range;
// it binds SURJECTIVITY through the sibling non-contiguous-corner
// helper `assert_u8_array_covers_finite_set` below.
const _: () = assert_u8_array_covers_inclusive_range::<12, 0, 6>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `arr` falls OUTSIDE the inclusive range `[LO, HI]` on
/// the substrate's `u8` cache-key vocabulary. Binds ONE conjunct clause
/// at ONE `const _` line:
///
/// * RANGE-SUBSET-VIOLATION: every entry in `arr` lies in `[LO..=HI]` —
/// the array's distinct-value set is a SUBSET of the target inclusive
/// range. A regression that drifts ONE entry to a byte OUTSIDE the
/// range (e.g. lifts a `[u8; 2]` sub-carve of the outer-`Sexp` cache-
/// key `[0..=6]` partition to `[0u8, 7u8]`, drifting past the outer-
/// discriminator space's upper endpoint) fails-loudly at const-eval.
///
/// Contract-strength peer to [`assert_u8_array_covers_inclusive_range`]
/// on the (equality-vs-subset) axis: where `_covers_inclusive_range`
/// binds `arr`'s distinct-value set FULLY COVERS `[LO..=HI]` (every
/// entry is in the range AND every range byte is reached — the RANGE-
/// BOUND arm ∧ the FULL-COVERAGE arm), this helper binds ONLY the
/// RANGE-BOUND arm read in isolation (`arr ⊆ [LO..=HI]` without the
/// FULL-COVERAGE clause) — a strictly WEAKER contract for arrays
/// intentionally covering only a PROPER SUBSET of the target range.
///
/// Contiguity-axis peer to [`assert_u8_array_within_u8_finite_set`]:
/// where the finite-set SUBSET-only sibling binds `arr ⊆ set` at the
/// non-contiguous-finite-set corner (`set` is any `[u8; M]` —
/// contiguous, gapped, singleton, or scattered), this helper binds
/// `arr ⊆ [LO..=HI]` at the contiguous-range corner (target super-
/// set is a contiguous inclusive range parameterised by the `LO/HI`
/// const generics rather than a runtime-provided literal array). The
/// two helpers together close the (equality-vs-subset) × (contiguity)
/// 2×2 = 4-corner face of the substrate's `u8` array vocabulary at
/// compile time: (equality, contiguous) at
/// [`assert_u8_array_covers_inclusive_range`], (equality, finite-
/// set) at [`assert_u8_array_covers_finite_set`], (subset,
/// contiguous) at THIS helper, (subset, finite-set) at
/// [`assert_u8_array_within_u8_finite_set`]. Prefer the tighter
/// [`assert_u8_array_covers_inclusive_range`] when the array's
/// distinct-value set intentionally EQUALS the target range; this
/// helper is for the strictly-weaker SUBSET corner where `arr`
/// covers only a PROPER SUBSET of `[LO..=HI]`. Prefer
/// [`assert_u8_array_within_u8_finite_set`] when the target super-
/// set is NON-contiguous — this range-based helper cannot express
/// gaps within the target.
///
/// The invariant is load-bearing for the substrate's OUTER-`Sexp`
/// cache-key partition-embedding contract on the ONE outer discri-
/// minator array whose parent-range embedding is NOT ALREADY compile-
/// time-enforced through a tighter contract:
/// [`crate::error::StructuralKind::HASH_DISCRIMINATORS`] (`[u8; 2]`
/// = `[0, 2]`, the non-contiguous two-of-seven structural-residual
/// sub-carving covering `{0, 2}` with a gap at `1u8` where the
/// atomic-carve outer marker lives) MUST be a SUBSET of `[0..=6]`
/// (the outer-`Sexp` cache-key discriminator space defined by
/// [`crate::error::SexpShape::HASH_DISCRIMINATORS`]'s twelve-shape
/// → seven-byte collapse). Pre-lift the array bound SURJECTIVITY
/// through
/// `assert_u8_array_permutes_finite_set::<2, 2>(&StructuralKind::HASH_DISCRIMINATORS, &[0u8, 2u8])`
/// — this compound witness binds a permutation of the FINITE-SET
/// `{0, 2}` but leaves the OUTER-RANGE embedding UNCONSTRAINED at
/// compile time. A coordinated regression that drifted BOTH
/// `StructuralKind::LIST_HASH_DISCRIMINATOR` from `2u8` to (say)
/// `8u8` AND updated the finite-set literal from `&[0u8, 2u8]` to
/// `&[0u8, 8u8]` in lockstep at the `_permutes_finite_set` call site
/// would pass the finite-set-permutation witness (the drifted pair
/// is a permutation of the drifted set) but VIOLATE the outer-
/// `[0..=6]` partition semantic — `8u8` falls OUTSIDE the twelve-
/// shape SexpShape hash arm's reach. Post-lift the ARRAY-LEVEL
/// RANGE-SUBSET witness catches the coordinated finite-set drift
/// at const-eval time; the panic message routes operator attention
/// to the ARRAY-DECLARATION site as the drift origin. The runtime
/// per-role scalar alias-chain pins in `error.rs`'s test module
/// survive as sibling checks (a distinct failure mode: a drift
/// that KEPT the byte within `[0..=6]` but ROUTED to the wrong
/// per-role outer marker still passes the ARRAY-level range-
/// subset check but fails the per-role scalar pin) — together the
/// two pins bind the outer-partition embedding at TWO stages of
/// the toolchain.
///
/// The three OTHER family-wide outer-`Sexp` discriminator arrays
/// (`SexpShape`, `QuoteForm`, `UnquoteForm`) are intentionally
/// OMITTED from this range-SUBSET sweep because their outer-
/// `[0..=6]` embedding is ALREADY compile-time-enforced through
/// TIGHTER contracts on their respective sub-ranges:
/// [`crate::error::SexpShape::HASH_DISCRIMINATORS`] covers `[0..=6]`
/// exactly via [`assert_u8_array_covers_inclusive_range::<12, 0, 6>`]
/// (equality tighter than subset — the covers witness implies the
/// subset witness); [`QuoteForm::HASH_DISCRIMINATORS`] permutes
/// `[3..=6]` via [`assert_u8_array_permutes_inclusive_range::<4, 3, 6>`]
/// (a permutation of `[3..=6]` — which is a subset of `[0..=6]` by
/// numeric inclusion — implies `⊆ [0..=6]`);
/// [`crate::error::UnquoteForm::HASH_DISCRIMINATORS`] permutes
/// `[5..=6]` via [`assert_u8_array_permutes_inclusive_range::<2, 5, 6>`]
/// (same, doubly transitive through QuoteForm's parent-range
/// containment). Adding redundant SUBSET-of-`[0..=6]` witnesses on
/// those three would double-bind claims strictly weaker than what
/// the tighter permutes / covers contracts already prove.
///
/// Every future family-wide `[u8; N]` typed-range-subset carving on
/// the substrate's closed-set outer algebras whose target-superset
/// IS a contiguous inclusive range (e.g. any further intentionally-
/// closed sub-carving of the `[0..=6]` outer-`Sexp` partition whose
/// distinct-value set is intentionally NON-CONTIGUOUS within the
/// target range) participates in the SAME compile-time guarantee
/// via one `const _` line.
///
/// Adding a new family-wide `[u8; N]` range-embedded array to the
/// substrate: pair the declaration with `const _: () =
/// assert_u8_array_within_inclusive_range::<N, LO, HI>(&Self::
/// FOO_ARRAY);` co-located after the array's declaration and the
/// RANGE-SUBSET contract binds at compile time. The rustc-forced
/// arity `[u8; N]` composes with this const-eval sweep so both
/// cardinality-N AND every-entry-in-range are compile-time theorems
/// on the SAME array.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_array_within_inclusive_range_panics_at_runtime_on_entry_above_hi`,
/// `assert_u8_array_within_inclusive_range_panics_at_runtime_on_entry_below_lo`,
/// `assert_u8_array_within_inclusive_range_panics_at_runtime_on_terminal_out_of_range_entry`,
/// and
/// `assert_u8_array_within_inclusive_range_panic_message_names_the_helper_and_range_subset_violation_axis`.
/// The panic site carries the axis-provenance string
/// `"RANGE-SUBSET-VIOLATION"` chosen DISTINCT from every sibling
/// helper's axis vocabulary (`"duplicate"` on the ARRAY-side pairwise-
/// distinct sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the
/// covers-finite-set sibling; `"OUT-OF-RANGE"` / `"MISSING"` on the
/// covers-inclusive-range sibling; `"SUBSET-VIOLATION"` on the finite-
/// set SUBSET-only sibling; `"ARITY-MISMATCH"` on both `_permutes_*`
/// compound helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on the SET-side
/// well-formedness sibling) so a diagnostic that names the failed
/// axis routes UNAMBIGUOUSLY to THIS specific range SUBSET-embedding
/// helper. The `"RANGE-"` prefix disambiguates from the finite-set
/// peer's bare `"SUBSET-VIOLATION"`; the `"-VIOLATION"` suffix is
/// shared with the finite-set peer so callers can grep either
/// SUBSET-embedding sibling by `"VIOLATION"` alone or route to the
/// specific contiguity corner by the `"RANGE-"` / bare-`"SUBSET-"`
/// disambiguator prefix.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide range-
/// subset-embedding contract on the `u8` cache-key vocabulary
/// becomes a TYPE-LEVEL theorem the substrate carries per
/// (array, range) pair rather than a transitively-implied claim
/// the developer must trust to hold across sibling witnesses
/// drifting in lockstep.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key `[0..=6]` partition is the `intent_hash` composition
/// axis — binding the range-subset embedding on the typed algebra
/// makes a coordinated drift outside the parent range a compile
/// error rather than a silent BLAKE3 mis-hash on any
/// `Expander::cache` consumer keyed on the sub-carving.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// range-membership-only sweep IS the generative shape. Every new
/// closed-set discriminator array whose distinct-value set is an
/// intentional SUBSET of a contiguous inclusive range on the
/// substrate adds ONE `const _` line to get the range-subset-
/// embedding theorem rather than re-deriving a per-embedding
/// runtime iterator sweep at each call site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs;
/// the RANGE-SUBSET embedding proof at declaration site AND the
/// parent [`assert_u8_array_covers_inclusive_range`] proof on the
/// parent-range-covering array regenerate through the SAME
/// `const _` witness at the SUBSET-embedded array level.
///
/// Frontier inspiration: Lean 4's `Set.Icc` (closed interval) combined
/// with `Set.subset_Icc_iff` giving the equivalence `s ⊆ Icc a b ↔
/// ∀ x ∈ s, a ≤ x ∧ x ≤ b` — the substrate primitive here embeds
/// the same interval-subset relation as a rustc const-eval-time proof
/// obligation at every `assert_u8_array_within_inclusive_range` call
/// site rather than as a Lean tactic invocation deferred to
/// `elab_command`. TLA+'s `\A x \in S : LO <= x /\ x <= HI` first-
/// class quantified-interval-subset relation composes similarly at
/// TLC model-checking time. Coq's `Included A (Ensembles.Included U
/// (fun x => LO <= x <= HI))` predicate encodes the same per-element
/// containment. Translation through pleme-io primitives: the RANGE-
/// SUBSET embedding predicate binds through ONE forward sweep
/// (`LO ≤ arr[i] ≤ HI`) at const-eval time on a rustc-forced-arity
/// `[u8; N]` × two `u8` const generics — no `Ord` / `Eq` / `Hash`
/// supertrait bound, no allocation, no set carrier.
///
/// # Panics
///
/// Panics if any `arr[i]` satisfies `arr[i] < LO || arr[i] > HI`.
pub const fn assert_u8_array_within_inclusive_range<const N: usize, const LO: u8, const HI: u8>(
arr: &[u8; N],
) {
let mut i = 0;
while i < N {
if arr[i] < LO || arr[i] > HI {
panic!(
"assert_u8_array_within_inclusive_range: RANGE-\
SUBSET-VIOLATION — the family-wide u8 array `arr` \
carries an entry at some position whose byte falls \
OUTSIDE the target inclusive range `[LO, HI]`. The \
substrate's RANGE-SUBSET-EMBEDDING contract on the \
array is broken; every consumer that expects the \
array's distinct-value set to embed within the \
target inclusive range (`StructuralKind::HASH_\
DISCRIMINATORS ⊂ [0..=6]` on the outer-`Sexp` \
cache-key partition; any future typed-range-subset \
embedding on the substrate's closed-set outer \
algebras) relies on every array entry staying \
inside the target range. Fix at the ARRAY-\
DECLARATION site (the `arr` under verification, \
NOT the `LO`/`HI` const parameters specifying the \
target range) by dropping the offending entry OR \
by widening `[LO..=HI]` to cover it — the choice \
depends on whether the drift is an unintended \
overshoot outside the parent range or an \
intentional extension of the range vocabulary"
);
}
i += 1;
}
}
// Compile-time RANGE-SUBSET-embedding witness — the ONE family-wide
// `[u8; N]` HASH_DISCRIMINATORS array on the substrate whose distinct-
// value set is an intentionally-closed PROPER SUBSET of a contiguous
// inclusive range NOT ALREADY BOUND by a TIGHTER `_covers_inclusive_
// range` / `_permutes_inclusive_range` witness on a sub-range:
// `StructuralKind::HASH_DISCRIMINATORS` (`[u8; 2]` = `[0, 2]`, the
// non-contiguous two-of-seven structural-residual sub-carving covering
// `{0, 2}` with a gap at `1u8` where the atomic-carve outer marker
// lives) MUST be a SUBSET of `[0..=6]` (the outer-`Sexp` cache-key
// discriminator space defined by `SexpShape::HASH_DISCRIMINATORS`'s
// twelve-shape → seven-byte collapse). Pre-lift the array bound
// SURJECTIVITY through `assert_u8_array_permutes_finite_set::<2, 2>(
// &StructuralKind::HASH_DISCRIMINATORS, &[0u8, 2u8])` (module-level
// `const _` further down in this file) — this compound witness binds
// a permutation of the FINITE-SET `{0, 2}` but leaves the OUTER-RANGE
// embedding UNCONSTRAINED at compile time. A coordinated regression
// that drifted BOTH `StructuralKind::LIST_HASH_DISCRIMINATOR` from
// `2u8` to (say) `8u8` AND updated the finite-set literal from
// `&[0u8, 2u8]` to `&[0u8, 8u8]` at the `_permutes_finite_set` call
// site would pass the finite-set-permutation witness (the drifted
// pair is a permutation of the drifted set) but VIOLATE the outer-
// `Sexp` `[0..=6]` partition semantic every `Hash for Sexp` consumer
// relies on. Post-lift this ARRAY-LEVEL RANGE-SUBSET witness catches
// the coordinated finite-set drift at const-eval time — the panic
// message routes operator attention to the ARRAY-DECLARATION site
// as the drift origin. The three OTHER family-wide outer-`Sexp`
// discriminator arrays (`SexpShape`, `QuoteForm`, `UnquoteForm`) are
// intentionally OMITTED from this range-SUBSET sweep because their
// outer-`[0..=6]` embedding is ALREADY compile-time-enforced through
// TIGHTER contracts on their respective sub-ranges (SexpShape covers
// `[0..=6]` exactly; QuoteForm permutes `[3..=6]`; UnquoteForm
// permutes `[5..=6]`) — adding redundant SUBSET-of-`[0..=6]`
// witnesses on those three would double-bind claims strictly weaker
// than what the tighter permutes / covers contracts already prove.
const _: () = assert_u8_array_within_inclusive_range::<2, 0, 6>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
);
/// Compile-time WELL-FORMEDNESS contract verifier on a caller-provided
/// TARGET-SET spec `set` — panics at const evaluation time (or at
/// runtime for dynamic callers) with the axis-provenance-named
/// `"SET-NOT-PAIRWISE-DISTINCT"` message iff `set` carries a duplicate
/// entry across two positions.
///
/// Closes the pre-existing caller-side WELL-FORMEDNESS gap on the
/// finite-set corner of the substrate's `u8` cache-key contract
/// lattice: pre-lift, both [`assert_u8_array_covers_finite_set`] and
/// [`assert_u8_array_permutes_finite_set`] documented (but did NOT
/// enforce) the pairwise-distinctness of the caller-provided target
/// `set` spec as a well-formedness *precondition* — a malformed set
/// (e.g. `[0u8, 2u8, 2u8]` at `M = 3`) silently passed BOTH covers-
/// helper arms on any `arr` that partitioned the DISTINCT-value subset
/// `{0, 2}` (post-lift `assert_u8_array_covers_finite_set` calls into
/// this helper as its FIRST arm; a malformed set now fails-loudly at
/// const-eval with a SET-side panic message BEFORE the OUT-OF-SET /
/// SET-BYTE-MISSING arms fire). The pigeonhole invariants both
/// downstream covers/permutes helpers rely on (`N == M` in the
/// permutation helper forces exact-set-partitioning) assume `set`
/// is well-formed AS a mathematical finite set; this helper turns
/// that assumption into a compile-time theorem the substrate
/// carries per call site rather than a docstring-level responsibility
/// the operator must remember to keep in lockstep across every
/// finite-set-covering call site.
///
/// Element-type sibling posture to [`assert_u8_array_pairwise_distinct`]:
/// the ARRAY sibling closes pairwise-distinctness on the ARRAY side of
/// the finite-set-coverage / permutation-of-finite-set compound
/// contracts (`arr` MUST be pairwise-distinct for the SURJECTIVITY
/// arm of the permutation helper to imply full-set-coverage by
/// pigeonhole); this SET sibling closes pairwise-distinctness on the
/// caller-provided TARGET-SET spec side (the SET spec MUST itself be
/// pairwise-distinct as a mathematical set — a `[u8; M]` literal that
/// silently duplicates a byte is not really a set of cardinality `M`
/// but of cardinality `< M`, and every downstream pigeonhole argument
/// gets a phantom-`M` inflating the arity check). The two helpers
/// together close BOTH sides of the pairwise-distinctness axis on
/// the finite-set-coverage compound tier: `arr` (the array under
/// verification) AND `set` (the caller-provided target-set spec).
///
/// The invariant is load-bearing for `StructuralKind::HASH_DISCRIMINATORS`'
/// permutation-of-finite-set witness at
/// [`assert_u8_array_permutes_finite_set`]'s module-level `const _`
/// invocation — the caller passes `&[0u8, 2u8]` as the target-set
/// spec; a regression at the CALL SITE that silently duplicated a
/// byte (e.g. `&[0u8, 0u8]` or `&[2u8, 2u8]`) would render the
/// permutation contract unsound: the pigeonhole `N == M` arity check
/// would still hold on the substrate's `[u8; 2]` array but the
/// intended set-cardinality is really `1`, so a permutation of
/// `{0, 2}` (via `arr = [0u8, 2u8]`) would silently mis-verify as
/// a permutation of `{0}` or `{2}`. Post-lift the well-formedness
/// check at the top of the compound helper's delegation chain
/// catches the SET-side drift at const-eval time with a message
/// routing operator attention to the CALLER'S SPEC rather than to
/// a downstream symptom.
///
/// Panic-message provenance: the axis-name string
/// `"SET-NOT-PAIRWISE-DISTINCT"` is chosen DISTINCT from every
/// sibling helper's axis-provenance vocabulary (`"duplicate"` on
/// [`assert_u8_array_pairwise_distinct`]'s ARRAY-side sweep;
/// `"OUT-OF-RANGE"` / `"MISSING"` on
/// [`assert_u8_array_covers_inclusive_range`];
/// `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on
/// [`assert_u8_array_covers_finite_set`];
/// `"ARITY-MISMATCH"` on the two compound `_permutes_*` helpers)
/// so a diagnostic that names the failed axis routes UNAMBIGUOUSLY
/// to (a) this specific SET-side well-formedness helper, and (b)
/// the CALLER'S TARGET-SET SPEC as the drift site rather than the
/// downstream `arr` under verification. The two-element prefix
/// `"SET-"` is shared with the sibling covers-finite-set arm's
/// `"SET-BYTE-MISSING"` — both are SET-side drifts, disambiguated
/// by the trailing `"NOT-PAIRWISE-DISTINCT"` vs. `"BYTE-MISSING"`
/// noun to disambiguate the specific SET-side axis.
///
/// Adding a new family-wide `[u8; N]` finite-set-covering array to
/// the substrate: no new call site needed at this level — every
/// invocation of [`assert_u8_array_covers_finite_set`] or
/// [`assert_u8_array_permutes_finite_set`] delegates through this
/// helper as its FIRST arm, so the well-formedness contract on the
/// caller-provided target-set spec binds at compile time as a side-
/// effect of the primary covers/permutes contract. Callers CAN also
/// invoke this helper directly at runtime to verify a dynamically-
/// constructed target-set spec's well-formedness before passing it
/// into the covers/permutes helpers — pinned by the negative
/// runtime pins (`_panics_at_runtime_on_binary_collision`,
/// `_panics_at_runtime_on_non_adjacent_collision`,
/// `_panics_at_runtime_on_terminal_collision`).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the caller-side target-set
/// well-formedness contract becomes a TYPE-LEVEL theorem the
/// substrate carries per call site rather than a docstring-level
/// responsibility the developer must remember to keep in lockstep
/// with every downstream covers/permutes invocation.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// set-well-formedness proof at the CALLER's site AND the covers/
/// permutes helpers' downstream pigeonhole arguments regenerate
/// through the SAME `const _` witness at each call site.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// set-pairwise-distinct sweep IS the generative shape. Every
/// downstream call to `assert_u8_array_covers_finite_set` or
/// `assert_u8_array_permutes_finite_set` now composes the set-
/// well-formedness precondition through the delegation chain
/// rather than the developer re-deriving a per-call-site
/// pairwise-distinct sweep on the target-set literal.
///
/// Compound sibling posture to the constituent
/// [`assert_u8_array_pairwise_distinct`] on the (verifier-target-
/// side) axis: the two helpers close the pairwise-distinctness axis
/// on the TWO complementary sides of the finite-set-coverage
/// compound tier — ARRAY side (`arr` in the covers/permutes
/// helpers) and SET side (`set` in the covers/permutes helpers).
/// Every intentionally-closed finite-set-covering `[u8; N]` array
/// on the substrate now binds pairwise-distinctness on BOTH the
/// ARRAY under verification AND the caller-provided target-set
/// spec at compile time.
pub const fn assert_u8_finite_set_pairwise_distinct<const M: usize>(set: &[u8; M]) {
let mut i = 0;
while i < M {
let mut j = i + 1;
while j < M {
if set[i] == set[j] {
panic!(
"assert_u8_finite_set_pairwise_distinct: SET-NOT-\
PAIRWISE-DISTINCT — the caller-provided target \
FINITE-SET spec `set` for a downstream `assert_u8_\
array_covers_finite_set` / `assert_u8_array_\
permutes_finite_set` invocation carries a DUPLICATE \
entry across two positions. A mathematical finite \
set carries each element at most once, so a `[u8; \
M]` literal with `M` positions but fewer than `M` \
DISTINCT values is not a well-formed finite set of \
cardinality `M` — every downstream pigeonhole \
argument (`N == M` arity check in the permutation \
helper; SET-BYTE-MISSING coverage arm in the \
covers helper) gets a PHANTOM-`M` inflating the \
effective cardinality and silently mis-verifies \
the intended finite-set-coverage / permutation \
contract. Fix at the SET-DECLARATION site (the \
`&[...]` literal passed as the `set` argument, NOT \
the `arr` argument being verified) by removing the \
duplicate byte from the target-set spec"
);
}
j += 1;
}
i += 1;
}
}
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `arr` is NOT a member of `set` on the substrate's `u8`
/// cache-key vocabulary. Binds ONE conjunct clause at ONE `const _`
/// line:
///
/// * SUBSET-VIOLATION: every entry in `arr` appears in `set` — the
/// array's distinct-value set is a SUBSET of the target finite
/// partition `set`. A regression that drifts ONE entry to a byte
/// NOT in the set (e.g. lifts a fresh `7u8` entry into
/// `UnquoteForm::HASH_DISCRIMINATORS`, drifting the two-of-four
/// substitution-subset carving OUTSIDE its parent superset
/// `QuoteForm::HASH_DISCRIMINATORS = [3, 4, 5, 6]`) fails-loudly
/// at const-eval.
///
/// SET-side well-formedness delegation: [`assert_u8_finite_set_pairwise_distinct`]
/// is called at the top of the helper — a malformed `set` (e.g.
/// `[0u8, 2u8, 2u8]`) is not a well-formed finite set of cardinality
/// `M` and would silently mis-verify the intended subset contract on
/// any `arr` embedded in the DISTINCT-value subset. Placed FIRST so
/// drift on the CALLER'S TARGET-SET SPEC routes to the SET-side
/// well-formedness axis rather than to a downstream SUBSET-VIOLATION
/// symptom on `arr`. A well-formed `set` passes this arm as a no-op —
/// const-eval-elidable at rustc-time on the substrate call site.
///
/// Contract-strength peer to [`assert_u8_array_covers_finite_set`] on
/// the (equality-vs-subset) axis: where `_covers_finite_set` binds
/// arr's distinct-value set EQUALS `set` (arr's entries ⊆ set AND
/// set ⊆ arr's entries — the OUT-OF-SET arm ∧ the SET-BYTE-MISSING
/// arm), this helper binds ONLY arr ⊆ set (the OUT-OF-SET arm read
/// in isolation without the SET-BYTE-MISSING arm) — a strictly
/// WEAKER contract for arrays that intentionally cover only a
/// PROPER SUBSET of the target partition rather than the whole
/// partition. The RANGE analog of this SUBSET-only helper is the
/// RANGE-BOUND arm of [`assert_u8_array_covers_inclusive_range`]
/// read in isolation (arr ⊆ `[LO..=HI]` without the FULL-COVERAGE
/// clause) — no substrate call site currently exercises the range
/// analog on its own because every substrate range-family array
/// either fully covers its assigned range (the three permutation-
/// shaped `_permutes_inclusive_range` arrays: `AtomKind`,
/// `QuoteForm`, `UnquoteForm`) or fully covers it non-injectively
/// (`SexpShape::HASH_DISCRIMINATORS`). The finite-set analog of this
/// SUBSET-only helper is exactly the primitive this lift adds.
///
/// The invariant is load-bearing for the outer-`Sexp` cache-key
/// algebra's SUBSTITUTION-SUBSET embedding.
/// [`crate::error::UnquoteForm::HASH_DISCRIMINATORS`] (`[u8; 2]` —
/// the two-of-four substitution-subset carving covering `Unquote`
/// / `UnquoteSplice`) MUST be a SUBSET of
/// [`QuoteForm::HASH_DISCRIMINATORS`] (`[u8; 4]` — the four-arm
/// quote-family superset carving covering `Quote` / `Quasiquote` /
/// `Unquote` / `UnquoteSplice`). Pre-lift the subset embedding was
/// pinned ONLY at runtime via
/// `unquote_form_per_role_hash_discriminators_alias_quote_form_per_role_hash_discriminators_byte_for_byte`
/// (in `error.rs`, checking per-role scalar byte-equality between
/// the two `pub(crate) const UnquoteForm::*_HASH_DISCRIMINATOR`
/// constants and their `QuoteForm::*_HASH_DISCRIMINATOR`
/// namesakes) — the theorem held only after `cargo test` scheduled
/// the pin. Post-lift the ARRAY-LEVEL subset containment binds at
/// rustc time — a regression that re-inlined either UnquoteForm
/// per-role alias to a fresh literal byte NOT in the QuoteForm
/// superset (e.g. `7u8`) fails at `cargo check` BEFORE any test
/// scheduler runs. The runtime per-role scalar alias-chain pin
/// survives as a sibling check (a distinct failure mode: a drift
/// that KEPT the byte in the superset but ROUTED the alias to the
/// WRONG QuoteForm arm still passes the ARRAY-level subset check
/// but fails the scalar per-role pin) — together the two pins
/// bind the substitution-subset embedding at TWO stages of the
/// toolchain, const-time on the ARRAYS and test-time on the per-
/// role scalar aliases.
///
/// Every future family-wide `[u8; N]` typed-subset carving on the
/// substrate's closed-set outer algebras (a hypothetical
/// name-punctuation-subset of a keyword vocabulary, a strict
/// numeric-vs-string atomic-payload subset of `AtomKind`, or any
/// further sub-carving of the `{0..=6}` outer-`Sexp` cache-key
/// partition) participates in the SAME compile-time guarantee via
/// one `const _` line.
///
/// Adding a new family-wide `[u8; N]` subset-embedded array to the
/// substrate: pair the declaration with `const _: () =
/// assert_u8_array_within_u8_finite_set::<N, M>(&Self::FOO_ARRAY,
/// &Other::SUPERSET_ARRAY);` co-located after the array's
/// declaration and the SUBSET contract binds at compile time. The
/// rustc-forced arities `[u8; N]` and `[u8; M]` compose with this
/// const-eval sweep so BOTH cardinality-pair AND every-entry-in-
/// superset are compile-time theorems on the SAME (subset, superset)
/// array pair. Prefer [`assert_u8_array_covers_finite_set`] when
/// the array's distinct-value set is intentionally EQUAL to the
/// target partition; this helper is for the strictly-weaker SUBSET
/// corner where `arr` covers only a PROPER SUBSET of `set`.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_array_within_u8_finite_set_panics_at_runtime_on_out_of_set_entry`
/// and
/// `assert_u8_array_within_u8_finite_set_panic_message_names_the_helper_and_subset_violation_axis`.
/// The panic site carries the `"SUBSET-VIOLATION"` axis-provenance
/// string chosen DISTINCT from every sibling helper's axis
/// vocabulary (`"duplicate"` on the ARRAY-side pairwise-distinct
/// sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the
/// covers-finite-set sibling; `"OUT-OF-RANGE"` / `"MISSING"` on
/// the covers-inclusive-range sibling; `"ARITY-MISMATCH"` on both
/// `_permutes_*` compound helpers; `"SET-NOT-PAIRWISE-DISTINCT"`
/// on the SET-side well-formedness sibling) so a diagnostic that
/// names the failed axis routes UNAMBIGUOUSLY to THIS specific
/// SUBSET-embedding helper.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide subset-
/// embedding contract on the `u8` cache-key vocabulary becomes a
/// TYPE-LEVEL theorem the substrate carries per (subset, superset)
/// array pair rather than a runtime test the developer must
/// remember to write per embedding.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the subset-embedding arrays on the typed algebra
/// makes a substitution-subset drift outside the parent superset
/// a compile error rather than a silent BLAKE3 mis-hash on any
/// `Expander::cache` consumer keyed on the subset carving.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// set-membership-only sweep IS the generative shape. Every new
/// closed-set discriminator array whose distinct-value set is an
/// intentional SUBSET of another substrate array adds ONE
/// `const _` line to get the subset-embedding theorem rather
/// than re-deriving a per-embedding runtime iterator sweep at
/// each call site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs;
/// the SUBSET-embedding proof at declaration site AND the per-
/// role scalar alias-chain composition through
/// `UnquoteForm::V_HASH_DISCRIMINATOR = QuoteForm::V_HASH_DISCRIMINATOR`
/// regenerate through the SAME `const _` witness at the ARRAY
/// level.
///
/// Frontier inspiration: Lean 4's `Finset.instHasSubsetFinset :
/// (⊆) : Finset α → Finset α → Prop` as a decidable relation on
/// `Finset α` combined with `Finset.subset_iff` unfolding the
/// relation to per-element membership — the substrate primitive
/// here embeds the same subset relation as a rustc const-eval-time
/// proof obligation at every `assert_u8_array_within_u8_finite_set`
/// call site rather than as a Lean tactic invocation deferred to
/// `elab_command`. TLA+'s `S \subseteq T` first-class relation on
/// specification sets composes similarly at TLC model-checking
/// time. Coq's `Ensembles.Included : Ensemble U -> Ensemble U ->
/// Prop` capturing the same per-element containment predicate.
/// Translation through pleme-io primitives: the SUBSET-embedding
/// predicate binds through ONE forward sweep (`arr[i] in set`) at
/// const-eval time on a rustc-forced-arity `[u8; N]` × `[u8; M]`
/// pair — no `Ord` / `Eq` / `Hash` supertrait bound, no
/// `HashSet`-shape carrier, no allocation. The delegation-first
/// ordering (SET-well-formedness before SUBSET-VIOLATION) matches
/// Lean's `Finset`-forward reasoning: prove the SET is well-formed
/// AS a finite set, then reason about arrays embedded in it.
pub const fn assert_u8_array_within_u8_finite_set<const N: usize, const M: usize>(
arr: &[u8; N],
set: &[u8; M],
) {
// Delegate target-set well-formedness to the sibling SET-side
// pairwise-distinctness helper FIRST. Placed BEFORE the SUBSET-
// VIOLATION sweep below because a malformed `set` (e.g. `[0u8,
// 2u8, 2u8]`) is not a well-formed finite set of cardinality
// `M` and silently mis-verifies the intended subset contract on
// any `arr` embedded in the DISTINCT-value subset. Routes drift
// on the CALLER'S TARGET-SET SPEC to the SET-side well-formedness
// axis rather than to a downstream SUBSET-VIOLATION symptom on
// `arr`. A well-formed `set` passes this arm as a no-op — the
// sweep is const-eval-elidable and costs zero at rustc-time on
// the one substrate call site.
assert_u8_finite_set_pairwise_distinct(set);
let mut i = 0;
while i < N {
let mut j = 0;
let mut found = false;
while j < M {
if arr[i] == set[j] {
found = true;
break;
}
j += 1;
}
if !found {
panic!(
"assert_u8_array_within_u8_finite_set: SUBSET-\
VIOLATION — the family-wide u8 array `arr` carries \
an entry at some position whose byte is NOT a \
member of the target finite superset partition \
`set`. The substrate's SUBSET-EMBEDDING contract \
on the array is broken; every consumer that \
expects the array's distinct-value set to be a \
subset of the target finite partition \
(`UnquoteForm::HASH_DISCRIMINATORS ⊂ \
QuoteForm::HASH_DISCRIMINATORS` on the outer-\
`Sexp` cache-key substitution-subset carving; any \
future typed-subset embedding on the substrate's \
closed-set outer algebras) relies on every array \
entry staying within the target superset. Fix at \
the ARRAY-DECLARATION site (the `arr` under \
verification, NOT the `set` argument specifying \
the target superset) by dropping the offending \
entry OR by extending `set` to cover it — the \
choice depends on whether the drift is an \
unintended overshoot outside the parent superset \
or an intentional extension of the superset \
vocabulary"
);
}
i += 1;
}
}
// Compile-time SUBSET-embedding witness — the ONE family-wide
// `[u8; N]` HASH_DISCRIMINATORS array on the substrate whose
// distinct-value set is an intentionally-closed PROPER SUBSET of
// another substrate array's distinct-value set:
// `UnquoteForm::HASH_DISCRIMINATORS` (`[u8; 2]` = `[5, 6]`, the
// two-of-four substitution-subset carving covering
// `Unquote` / `UnquoteSplice`) MUST be a SUBSET of
// `QuoteForm::HASH_DISCRIMINATORS` (`[u8; 4]` = `[3, 4, 5, 6]`, the
// four-arm quote-family superset carving covering
// `Quote` / `Quasiquote` / `Unquote` / `UnquoteSplice`). Pre-lift
// the subset embedding was pinned ONLY at runtime via the per-role
// alias-chain check
// `unquote_form_per_role_hash_discriminators_alias_quote_form_per_role_hash_discriminators_byte_for_byte`
// (in `error.rs`, checking scalar-per-role byte-equality between
// the two `UnquoteForm::*_HASH_DISCRIMINATOR` constants and their
// `QuoteForm::*_HASH_DISCRIMINATOR` namesakes). Post-lift the
// ARRAY-LEVEL subset embedding binds at rustc time via ONE
// `const _` witness on the two arrays directly; a drift that
// re-inlined either UnquoteForm alias to a fresh literal byte NOT
// in the QuoteForm superset (e.g. `7u8`) would fail at `cargo
// check` BEFORE any test scheduler runs. The runtime per-role
// alias-chain pin survives as a sibling check for the scalar
// aliases (a distinct failure mode: a drift that KEPT the byte in
// the superset but ROUTED the alias to the WRONG QuoteForm arm
// still passes the ARRAY-level subset check but fails the scalar
// per-role pin); together with this const witness the
// substitution-subset embedding theorem is enforced at BOTH stages
// of the toolchain — const-time on the ARRAYS, test-time on the
// scalar per-role aliases.
const _: () = assert_u8_array_within_u8_finite_set::<2, 4>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
// Compile-time TIGHTENING witness — the (u8)-row analog of the
// (str)-row three-witness SUB-AS-SLICE cluster in `error.rs`
// (`assert_str_array_slice_equals_str_array::<4, 2, 2>` on the
// `UnquoteForm::{LABELS, MARKERS, IAC_FORGE_TAGS} ⊂
// QuoteForm::{LABELS, PREFIXES, IAC_FORGE_TAGS}` sub-carve). The
// pre-existing SUBSET-embedding witness above binds `UnquoteForm::
// HASH_DISCRIMINATORS ⊂ QuoteForm::HASH_DISCRIMINATORS` at the SET
// level (`{5, 6} ⊂ {3, 4, 5, 6}`); this witness tightens the
// binding to POSITIONWISE SLICE-EQUALS on the SAME sub-carve —
// `QuoteForm::HASH_DISCRIMINATORS[2..4] == UnquoteForm::HASH_
// DISCRIMINATORS[..]` byte-for-byte in canonical slot order.
//
// Two failure axes survive the SET-level SUBSET witness above that
// this POSITIONWISE witness rejects at rustc time:
// 1. Sub-array SLOT REORDER: a regression that swaps
// `UnquoteForm::HASH_DISCRIMINATORS` from `[UNQUOTE_HASH_
// DISCRIMINATOR, SPLICE_HASH_DISCRIMINATOR]` (`[5, 6]`) to
// `[SPLICE_HASH_DISCRIMINATOR, UNQUOTE_HASH_DISCRIMINATOR]`
// (`[6, 5]`) preserves the SUBSET witness (both bytes still
// appear in the superset) — but silently misaligns every
// consumer indexing the sub-array by slot ordinal (the
// `UnquoteForm::hash_discriminator` per-variant projection at
// `error.rs`'s `UnquoteForm` inherent impl, the runtime
// partition test
// `unquote_form_hash_discriminators_align_with_quote_form_
// hash_discriminators_by_projection`).
// 2. Superset SLOT REORDER that leaves sub-array bytes still
// present but at different positions: a regression that
// reorders `QuoteForm::HASH_DISCRIMINATORS` from `[3, 4, 5,
// 6]` to any permutation that leaves `{5, 6}` non-contiguous
// or non-tail (e.g. `[5, 3, 6, 4]`) preserves the SUBSET
// witness (both sub-array bytes still appear in the superset,
// just at scattered non-`[2..4)` positions) — but the sub-
// carving no longer sits at the tail of the superset's four-
// arm declaration listing, breaking the compositional
// invariant that `QuoteForm::HASH_DISCRIMINATORS[2..4] ==
// UnquoteForm::HASH_DISCRIMINATORS` presumes.
//
// Sibling posture: the (str)-row tightening cluster at `error.rs`
// (three `assert_str_array_slice_equals_str_array::<4, 2, 2>`
// witnesses on the `LABELS` / `MARKERS↔PREFIXES` / `IAC_FORGE_TAGS`
// vocabulary triple) closes the SLICE-EQUALS column on the SAME
// (UnquoteForm ⊂ QuoteForm) 2-of-4 sub-carve at the STR element-
// type row; this witness closes the SAME column at the U8 element-
// type row. Together the four-witness cluster (three str + one u8)
// exhausts the (element-type × vocabulary-axis) matrix of the
// substitution-subset carving at the SLICE-EQUALS positionwise-
// composition contract.
//
// Composition with the sibling FULL-ARRAY LITERAL witnesses at
// lines 6961..=6976 below: those two witnesses independently pin
// `QuoteForm::HASH_DISCRIMINATORS == [3u8, 4, 5, 6]` and
// `UnquoteForm::HASH_DISCRIMINATORS == [5u8, 6]` against their
// literal byte listings. This SLICE-EQUALS witness composes with
// them — a drift on EITHER array's literal listing fails first at
// the peer FULL-ARRAY witness; a drift on the sub-carving's
// contiguous-tail placement inside the superset that leaves BOTH
// literal listings intact (e.g. a fifth quote-family variant
// landing at an interior position of `QuoteForm::HASH_DISCRIMINATORS`
// shifting UNQUOTE/UNQUOTE_SPLICE off `[2..4)`) fails HERE at the
// SUB-AS-SLICE witness. Sibling to the JOINT permutation witness
// `assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4,
// 0, 6>` at line 7029 — that witness binds the outer partition
// `{0..=6} = {OUTER} ⊕ StructuralKind::HASH_DISCRIMINATORS ⊕
// QuoteForm::HASH_DISCRIMINATORS` as a bijection; this witness
// binds the sub-carving `UnquoteForm::HASH_DISCRIMINATORS` to a
// SPECIFIC contiguous slice of that quote-family carving.
const _: () = assert_u8_array_slice_equals_u8_array::<4, 2, 2>(
&QuoteForm::HASH_DISCRIMINATORS,
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the distinct-values sets of `a` and `b` share any byte on the
/// substrate's `u8` cache-key vocabulary. Binds ONE conjunct clause:
/// U8-DISJOINTNESS-VIOLATION — no entry in `a` may appear as an entry
/// in `b` (symmetric across the two array arguments).
///
/// Row-dual peer to [`assert_char_arrays_disjoint`] on the (element-
/// type) axis of the (subset, disjointness) 2-corner face of the
/// (contract-shape) axis: where the (char) sibling closes the reader-
/// boundary `char` disjointness corner at compile time, this (u8)
/// sibling closes the outer-`Sexp` cache-key `u8` disjointness corner
/// on the SAME element-type row. Together the two helpers close the
/// (element-type × contract-shape) 2×2 = 4-corner face at ONE peer
/// const-fn helper per corner rather than at a per-pair runtime
/// iterator sweep per call site. Contract-orthogonal peer to
/// [`assert_u8_array_within_u8_finite_set`] on the (subset-vs-
/// disjointness) axis of the (contract-shape) axis on the SAME (u8)
/// row: where the SUBSET-EMBEDDING sibling binds `arr ⊆ set`, this
/// DISJOINTNESS sibling binds `a ∩ b = ∅` on the SAME element type.
///
/// The disjointness relation is SYMMETRIC (unlike the SUBSET-EMBEDDING
/// relation, which distinguishes `arr` from `set`) so the two
/// arguments carry NO axis-provenance role split — either drift site
/// (a byte in `a` that aliases a byte in `b`, OR a byte in `b` that
/// aliases a byte in `a`) surfaces at the U8-DISJOINTNESS-VIOLATION
/// panic with the OFFENDING arm named by BOTH position indices
/// (`a[i]` AND `b[j]`) rather than by only one side of the pair.
///
/// SYMMETRY IN THE NESTED SWEEP: the inner `while j < M` sweep visits
/// every position of `b` per outer `i` and panics at the FIRST
/// cross-array collision (`a[i] == b[j]`). Because the relation is
/// symmetric and the two-loop sweep visits every `(i, j) ∈ [0, N) ×
/// [0, M)` pair, swapping `a` and `b` at the call site produces the
/// SAME verdict — the helper does NOT gratuitously depend on argument
/// order. A future call site that intends to name a SPECIFIC drift
/// side can still route its own preferred first-mention by picking
/// the argument order that serves its diagnostic story; the helper
/// itself carries no such preference.
///
/// The invariant is load-bearing for the outer-`Sexp` cache-key
/// algebra's JOINT PARTITION contract at [`Hash for Sexp`]: the
/// outer-`Sexp` discriminator space `{0..=6}` MUST partition across
/// the three closed-set sub-carvings ([`crate::error::StructuralKind::HASH_DISCRIMINATORS`]
/// at `{0, 2}`, [`AtomKind::OUTER_HASH_DISCRIMINATOR`] scalar at `{1}`,
/// [`QuoteForm::HASH_DISCRIMINATORS`] at `{3, 4, 5, 6}`) with NO
/// overlap — otherwise two structurally-distinct outer-`Sexp` variants
/// would silently mis-hash through the same cache-key byte and the
/// substrate's `Expander::cache` would leak macro-expansion hits
/// across carvings. Pre-lift the substrate carried these array-vs-
/// array disjointness relations at runtime tests
/// (`structural_kind_hash_discriminator_disjoint_from_atom_outer_carve_byte_and_quote_form_hash_discriminator_partition`
/// on the (StructuralKind, QuoteForm) pair;
/// `unquote_form_hash_discriminator_partitions_disjointly_from_non_substitution_carvings`
/// on the (UnquoteForm, StructuralKind) pair); post-lift the ARRAY-
/// LEVEL disjointness of the pinned pairs binds at rustc time via one
/// `const _` line per pair. A regression that silently drifted
/// `StructuralKind::LIST_HASH_DISCRIMINATOR` from `2u8` to `3u8`
/// (colliding with `QuoteForm::QUOTE_HASH_DISCRIMINATOR`), or drifted
/// `QuoteForm::QUOTE_HASH_DISCRIMINATOR` from `3u8` to `0u8`
/// (colliding with `StructuralKind::NIL_HASH_DISCRIMINATOR`), fails at
/// `cargo check` BEFORE any test scheduler runs. Sibling to the
/// pairwise-distinctness witnesses above — those pin INJECTIVITY on
/// each individual `[u8; N]` HASH_DISCRIMINATORS array, this pins
/// DISJOINTNESS across PAIRS of arrays on the SAME outer-`Sexp`
/// cache-key byte space.
///
/// Adding a new family-wide `[u8; N]` sub-vocabulary whose distinct-
/// values set must remain disjoint from another substrate `[u8; M]`
/// array's distinct-values set: pair the declaration with `const _:
/// () = assert_u8_arrays_disjoint::<N, M>(&Self::FOO_ARRAY,
/// &Other::BAR_ARRAY);` co-located after the array's declaration and
/// the DISJOINTNESS contract binds at compile time. The rustc-forced
/// arities `[u8; N]` and `[u8; M]` compose with this const-eval
/// sweep so BOTH cardinality-pair AND cross-array disjointness are
/// compile-time theorems on the SAME (a, b) u8-array pair.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_arrays_disjoint_panics_at_runtime_on_collision` and
/// `assert_u8_arrays_disjoint_panic_message_names_the_helper_and_u8_disjointness_violation_axis`.
/// The panic site carries the `"U8-DISJOINTNESS-VIOLATION"` axis-
/// provenance string chosen DISTINCT from every sibling helper's axis
/// vocabulary (`"duplicate"` on the ARRAY-side pairwise-distinct
/// sibling; `"CHAR-DISJOINTNESS-VIOLATION"` on the (char) row-dual
/// DISJOINTNESS sibling; `"CHAR-SUBSET-VIOLATION"` on the (char)
/// SUBSET-embedding sibling; `"SUBSET-VIOLATION"` on the (u8) finite-
/// set SUBSET-only sibling; `"RANGE-SUBSET-VIOLATION"` on the (u8)
/// range SUBSET-only sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"`
/// on the (u8) covers-finite-set sibling; `"OUT-OF-RANGE"` /
/// `"MISSING"` on the (u8) covers-inclusive-range sibling;
/// `"ARITY-MISMATCH"` on both (u8) `_permutes_*` compound helpers;
/// `"SET-NOT-PAIRWISE-DISTINCT"` on the (u8) SET-side well-formedness
/// sibling) so a diagnostic that names the failed axis routes
/// UNAMBIGUOUSLY to THIS specific u8 DISJOINTNESS helper. The `"U8-"`
/// prefix disambiguates from the (char) DISJOINTNESS sibling; the
/// shared `"-VIOLATION"` suffix lets callers grep either row's
/// DISJOINTNESS or SUBSET-embedding sibling by `"VIOLATION"` alone or
/// route to the specific contract-shape by the axis stem
/// (`"DISJOINTNESS"` vs `"SUBSET"`).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide cross-array
/// disjointness contract on the outer-`Sexp` cache-key `u8`
/// vocabulary becomes a TYPE-LEVEL theorem the substrate carries
/// per (a, b) u8-array pair rather than a runtime test the
/// developer must remember to write per pair.
/// - THEORY.md §III — the typescape; the (element-type × contract-
/// shape) 2×2 = 4-corner matrix is now closed at ONE peer const-fn
/// helper per corner — [`assert_char_array_within_char_finite_set`]
/// on the (char, subset) corner, [`assert_char_arrays_disjoint`] on
/// the (char, disjointness) corner,
/// [`assert_u8_array_within_u8_finite_set`] on the (u8, subset)
/// corner, and this helper on the (u8, disjointness) corner.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the substrate's `intent_hash` composition
/// axis — binding the ARRAY-vs-ARRAY disjointness pairs at compile
/// time makes a joint-partition-overlap drift a compile error
/// rather than a silent BLAKE3 mis-hash on any `Expander::cache` or
/// `Sekiban` audit-trail metric keyed on the outer discriminator
/// space.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// cross-array membership sweep IS the generative shape. Every new
/// closed-set `u8` sub-vocabulary array whose distinct-values set is
/// an intentionally-disjoint peer of another substrate `u8` array
/// adds ONE `const _` line to get the disjointness theorem rather
/// than re-deriving a per-pair runtime iterator sweep at each call
/// site.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// DISJOINTNESS proof at declaration site AND the outer-`Sexp`
/// cache-key JOINT PARTITION contract regenerate through the SAME
/// `const _` witnesses at the ARRAY level.
///
/// Frontier inspiration: Lean 4's `Finset.Disjoint : Finset α →
/// Finset α → Prop` as a decidable relation on `Finset α` combined
/// with `Finset.disjoint_iff_ne`'s characterisation `∀ a ∈ s, ∀ b ∈
/// t, a ≠ b` — this substrate primitive embeds the same disjointness
/// relation as a rustc const-eval-time proof obligation at every
/// `assert_u8_arrays_disjoint` call site rather than as a Lean tactic
/// invocation deferred to `elab_command`. Coq's `Ensembles.Disjoint :
/// Ensemble U -> Ensemble U -> Prop` captures the same relation as a
/// Prop-level predicate. Translation through pleme-io primitives: the
/// DISJOINTNESS predicate binds through the same nested `(i, j)`
/// sweep as the (char) row-dual peer, monomorphised to the concrete
/// `[u8; N] × [u8; M]` element-type realisation — no `Ord` / `Eq` /
/// `Hash` supertrait bound, no `HashSet`-shape carrier, no allocation.
pub const fn assert_u8_arrays_disjoint<const N: usize, const M: usize>(a: &[u8; N], b: &[u8; M]) {
let mut i = 0;
while i < N {
let mut j = 0;
while j < M {
if a[i] == b[j] {
panic!(
"assert_u8_arrays_disjoint: U8-DISJOINTNESS-\
VIOLATION — the two family-wide u8 arrays `a` \
and `b` share an entry at some (i, j) position \
pair. The substrate's CROSS-ARRAY DISJOINTNESS \
contract on the pair is broken; every consumer \
that partitions the two arrays' distinct-values \
sets into disjoint sub-vocabularies of the outer-\
`Sexp` cache-key `u8` algebra (the outer-`Sexp` \
joint-partition contract at `Hash for Sexp`: \
`StructuralKind::HASH_DISCRIMINATORS` at `{{0, 2}}` \
disjoint from `QuoteForm::HASH_DISCRIMINATORS` at \
`{{3, 4, 5, 6}}` disjoint from `UnquoteForm::HASH_\
DISCRIMINATORS` at `{{5, 6}}` on the non-parent \
carvings; any future typed-disjointness pair on \
the substrate's outer-`Sexp` cache-key `u8` \
algebras) relies on the two arrays' distinct-\
values sets NOT sharing a byte. Fix at WHICHEVER \
ARRAY-DECLARATION site drifted (the symmetric \
disjointness relation carries no built-in axis-\
provenance role split between `a` and `b`) by \
dropping the offending entry from one array OR \
re-shaping the partition to route the shared \
entry to a single sub-vocabulary"
);
}
j += 1;
}
i += 1;
}
}
// Compile-time DISJOINTNESS witnesses — the TWO substrate-pinned
// (a, b) `[u8; N] × [u8; M]` pairs whose distinct-values sets are
// intentionally-closed disjoint sub-vocabularies of the outer-`Sexp`
// cache-key `u8` algebra. Pre-lift the two disjointness relations
// lived only as runtime tests
// (`structural_kind_hash_discriminator_disjoint_from_atom_outer_carve_byte_and_quote_form_hash_discriminator_partition`
// on pair 1, sweeping `StructuralKind::hash_discriminator`'s `{0, 2}`
// against `QuoteForm::hash_discriminator`'s `{3, 4, 5, 6}` through
// per-variant `Vec<u8>` collection into a HashSet-shape overlap
// check; `unquote_form_hash_discriminator_partitions_disjointly_from_non_substitution_carvings`
// on pair 2, sweeping `UnquoteForm::hash_discriminator`'s `{5, 6}`
// against `StructuralKind::hash_discriminator`'s `{0, 2}` through the
// same HashSet-shape `is_disjoint` check); post-lift the ARRAY-LEVEL
// disjointness of the pinned pairs binds at rustc time via one
// `const _` line per pair. A regression that silently drifted
// `StructuralKind::LIST_HASH_DISCRIMINATOR` from `2u8` to `3u8`
// (colliding with `QuoteForm::QUOTE_HASH_DISCRIMINATOR`), or drifted
// `QuoteForm::QUOTE_HASH_DISCRIMINATOR` from `3u8` to `0u8`
// (colliding with `StructuralKind::NIL_HASH_DISCRIMINATOR`), or
// drifted `UnquoteForm::UNQUOTE_HASH_DISCRIMINATOR` from `5u8` to
// `2u8` (colliding with `StructuralKind::LIST_HASH_DISCRIMINATOR`)
// fails at `cargo check` BEFORE any test scheduler runs.
//
// Note on pair 2 (`UnquoteForm::HD` vs `StructuralKind::HD`): the
// disjointness is FORMALLY IMPLIED by pair 1 (`StructuralKind::HD` vs
// `QuoteForm::HD`) composed with the pre-existing SUBSET-embedding
// witness `assert_u8_array_within_u8_finite_set::<2, 4>(&UnquoteForm::HD,
// &QuoteForm::HD)` (transitivity of subset-through-disjoint: `X ⊂ Y ∧
// Y ∩ Z = ∅ ⇒ X ∩ Z = ∅`). Post-lift the direct pair-2 witness pins
// the substitution-subset drift mode DIRECTLY at rustc time rather
// than through a two-hop const-time inference — a drift that broke
// the pair-2 disjointness EITHER by drifting `UnquoteForm::HD` out of
// the parent superset OR by drifting `StructuralKind::HD` into the
// parent superset surfaces at THIS witness with the exact drifting
// arm identified. The redundant witness stays intentional: it mirrors
// the runtime pin's structure (a direct-per-pair check rather than a
// composed-through-parent check) so the runtime-vs-const witness
// pairs stay in one-to-one correspondence and a runtime pin has an
// EXACT const-time peer without pair-mapping ambiguity.
const _: () = assert_u8_arrays_disjoint::<2, 4>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
const _: () = assert_u8_arrays_disjoint::<2, 2>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// the distinct-values set of `arr` does not equal exactly the distinct-
/// values set of `set` on the substrate's `u8` cache-key vocabulary.
/// Binds TWO conjunct clauses at ONE `const _` line:
/// 1. OUT-OF-SET: every entry in `arr` appears in `set` — no byte
/// outside the target finite partition. A regression that drifts
/// ONE entry to a byte NOT in the set (e.g. lifts a fresh entry at
/// `3u8` on a `{0, 2}` array) fails-loudly at const-eval.
/// 2. SET-BYTE-MISSING: every byte in `set` appears at least once in
/// `arr` — no byte inside the target finite partition missing. A
/// regression that silently unifies two entries onto ONE byte,
/// leaving another set byte unreached (e.g. drops the `Nil` arm's
/// `0u8` from `StructuralKind::HASH_DISCRIMINATORS` in favour of
/// a redundant `2u8`), fails-loudly at const-eval too.
///
/// Generalises [`assert_u8_array_covers_inclusive_range`] along the
/// (contiguity) axis: where the range helper closes the SURJECTIVITY
/// axis at the contiguous corner (the target partition is an inclusive
/// `[LO, HI]` range), this finite-set helper closes the SURJECTIVITY
/// axis at the arbitrary-finite-set corner (the target partition is
/// any `[u8; M]` — contiguous, gapped, singleton, or scattered). The
/// contiguous-range helper stays as the tighter idiom for arrays whose
/// distinct-value set happens to be a contiguous inclusive range; this
/// finite-set helper binds the arrays whose distinct-value set is
/// NON-contiguous and therefore cannot be expressed as `[LO..=HI]`.
///
/// The invariant is load-bearing for the outer-`Sexp` cache-key
/// algebra's SPAN across the structural-residual sub-carve.
/// [`crate::error::StructuralKind::HASH_DISCRIMINATORS`] (`[u8; 2]`
/// covering `{0, 2}` with a gap at `1u8` where the atomic-carve outer
/// marker lives) is the archetype non-contiguous case — its
/// distinct-value set is a two-element finite set that is NOT a
/// contiguous inclusive range, so the range helper cannot bind. This
/// finite-set helper binds the structural-residual sub-carve's
/// surjectivity contract at compile time despite the intentional
/// gap: a regression that drops the `Nil` arm's `0u8` (or the `List`
/// arm's `2u8`) — or lifts a fresh `1u8` colliding with the outer-
/// carve atomic marker byte — fails the build. Every future family-
/// wide `[u8; N]` array whose distinct-value set is an intentionally-
/// closed FINITE (possibly non-contiguous) partition participates in
/// the SAME compile-time guarantee via one `const _` line.
///
/// Adding a new family-wide `[u8; N]` finite-set-covering array to
/// the substrate: pair the declaration with `const _: () =
/// assert_u8_array_covers_finite_set::<N, M>(&Self::FOO_ARRAY,
/// &[…the M target-set bytes…]);` co-located after the array's
/// declaration and the finite-set-coverage contract binds at compile
/// time. The rustc-forced arity `[u8; N]` composes with this
/// const-eval sweep so cardinality AND every-entry-in-set AND
/// every-set-byte-reached are ALL compile-time theorems on the SAME
/// array. Prefer the tighter [`assert_u8_array_covers_inclusive_range`]
/// when the target set IS a contiguous inclusive range — this helper
/// is the fallback for the non-contiguous corner.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_array_covers_finite_set_panics_at_runtime_on_
/// out_of_set_entry` + `assert_u8_array_covers_finite_set_panics_at_
/// runtime_on_missing_set_byte`. Both panic sites carry axis-provenance
/// strings ("OUT-OF-SET" vs. "SET-BYTE-MISSING") so downstream
/// diagnostics (`cargo check` const-eval error output, test-suite
/// failure reports) route the drift back to the failed axis by string
/// search — halving the search space for the operator debugging the
/// drift. The two axis-provenance strings are chosen DISTINCT from
/// the sibling [`assert_u8_array_covers_inclusive_range`]'s
/// ("OUT-OF-RANGE" vs. "MISSING") so a diagnostic that names the
/// failed axis routes UNAMBIGUOUSLY to the failed HELPER too.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide finite-set-
/// coverage contract on the `u8` cache-key vocabulary becomes a
/// TYPE-LEVEL theorem the substrate carries per array declaration
/// rather than a runtime test the developer must remember to write
/// per non-contiguous partition.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the finite-set-covering arrays on the typed algebra makes
/// attestation-key drift a compile error rather than a silent
/// BLAKE3 mis-hash on any consumer keyed on `Hash for Sexp`. A
/// regression that drops a byte from the structural-residual
/// sub-carve (or drifts an entry into the atomic-carve gap at `1u8`)
/// fails the build before it can silently invalidate a cached
/// expansion or a Sekiban audit-trail metric keyed on the outer
/// discriminator space.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// set-membership + set-coverage sweep IS the generative shape.
/// Every new closed-set discriminator array whose distinct-value set
/// is an intentionally-closed finite (possibly non-contiguous)
/// partition adds ONE `const _` line to get the finite-set-coverage
/// theorem rather than re-deriving two per-array runtime iterator
/// sweeps (one for the set-membership bound, one for the set-
/// coverage completeness).
///
/// Contiguity-axis sibling posture to
/// [`assert_u8_array_covers_inclusive_range`]: the two helpers close
/// the SURJECTIVITY axis of the substrate's typed `u8` array
/// vocabulary at the TWO complementary corners of the (contiguity)
/// axis. Combined with the four pre-existing const-fn contract
/// verifiers ([`assert_char_array_pairwise_distinct`],
/// [`assert_str_array_pairwise_distinct`],
/// [`assert_u8_array_pairwise_distinct`],
/// [`assert_char_pair_array_bijective`]) closing the INJECTIVITY axis,
/// the substrate now carries a complete `(injectivity, surjectivity)`
/// compile-time cache-key contract lattice: every family-wide `[u8; N]`
/// discriminator array binds AT LEAST ONE axis, and the four
/// intentionally-injective + range-covering arrays
/// (`AtomKind`, `QuoteForm`, `UnquoteForm` HASH_DISCRIMINATORS +
/// `SexpShape::HASH_DISCRIMINATORS` on the range-only arm) bind BOTH
/// axes.
pub const fn assert_u8_array_covers_finite_set<const N: usize, const M: usize>(
arr: &[u8; N],
set: &[u8; M],
) {
// Delegate target-set well-formedness to the sibling SET-side
// pairwise-distinctness helper FIRST. Placed BEFORE the OUT-OF-SET
// and SET-BYTE-MISSING sweeps below because a malformed `set`
// (e.g. `[0u8, 2u8, 2u8]`) inflates the effective cardinality
// used by the SET-BYTE-MISSING sweep with a PHANTOM-`M` and
// silently mis-verifies the intended finite-set-coverage contract.
// Routes drift on the CALLER'S TARGET-SET SPEC to the SET-side
// well-formedness axis rather than to a downstream OUT-OF-SET /
// SET-BYTE-MISSING symptom on `arr`. A well-formed `set` passes
// this arm as a no-op — the sweep is const-eval-elidable and
// costs zero at rustc-time on a substrate with only one such
// call site.
assert_u8_finite_set_pairwise_distinct(set);
let mut i = 0;
while i < N {
let mut j = 0;
let mut found = false;
while j < M {
if arr[i] == set[j] {
found = true;
break;
}
j += 1;
}
if !found {
panic!(
"assert_u8_array_covers_finite_set: family-wide u8 \
array carries an OUT-OF-SET entry at some position — \
the entry's byte is absent from the target finite \
partition `set`. The substrate's SET-MEMBERSHIP \
contract on the array is broken; every consumer that \
expects the array's entries to partition an outer \
cache-key space (Hash for Sexp's outer discriminator \
space, StructuralKind's non-contiguous sub-carving of \
`{{0, 2}}` around the atomic-carve gap at `1u8`) \
relies on the entries staying within the target set",
);
}
i += 1;
}
let mut j = 0;
while j < M {
let mut k = 0;
let mut found = false;
while k < N {
if arr[k] == set[j] {
found = true;
break;
}
k += 1;
}
if !found {
panic!(
"assert_u8_array_covers_finite_set: family-wide u8 \
array is SET-BYTE-MISSING a byte from the target \
finite partition `set` — every byte in the set must \
appear at least once in the array. The substrate's \
FULL-COVERAGE contract on the array is broken; every \
consumer that expects the array's distinct-value set \
to span the target finite partition (StructuralKind's \
`{{0, 2}}` two-arm sub-carve, any future non-\
contiguous partition-span contract) relies on every \
set byte being reached",
);
}
j += 1;
}
}
// Compile-time finite-set-coverage on family-wide `[u8; N]` hash-
// discriminator arrays no longer surfaces at this level as DIRECT
// witnesses — the ONE family-wide `[u8; N]` HASH_DISCRIMINATORS array
// whose distinct-value set is an intentionally-closed non-contiguous
// finite partition (`StructuralKind::HASH_DISCRIMINATORS` (`[u8; 2]`)
// covering `{0, 2}` with the load-bearing gap at `1u8` where the
// atomic-carve outer marker byte lives) now binds SURJECTIVITY through
// the stronger COMPOUND (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY)
// `assert_u8_array_permutes_finite_set` helper defined below, which
// delegates through THIS helper for the SET-MEMBERSHIP + FULL-
// COVERAGE arms — the helper is now purely a delegation target.
// Binding the compound witness makes the (StructuralKind sub-carve,
// atomic-carve marker byte) disjointness a compile-time theorem: a
// regression that lifted a fresh `1u8` entry into
// `StructuralKind::HASH_DISCRIMINATORS` would silently collide with
// `AtomKind::OUTER_HASH_DISCRIMINATOR = 1u8` on the outer-`Sexp`
// cache-key partition and fail the build at the compound helper's
// delegation call to THIS helper's `"OUT-OF-SET"` arm rather than
// surfacing as a silent BLAKE3 mis-hash on any consumer keyed on
// `Hash for Sexp`.
//
// Adding a new family-wide `[u8; N]` non-contiguous-finite-set-covering
// HASH_DISCRIMINATORS array: prefer the compound
// `assert_u8_array_permutes_finite_set` helper below which binds
// INJECTIVITY ∧ SURJECTIVITY ∧ ARITY at ONE `const _` line if the
// array is a PERMUTATION of the target set; fall back to a DIRECT
// `const _: () = assert_u8_array_covers_finite_set::<N, M>(&Self::
// FOO_ARRAY, &[…set…]);` witness at this level ONLY for an array with
// a LOOSER contract (e.g. an intentionally-non-injective mapping onto
// the target set — no substrate array currently exercises this
// posture). Sibling to the runtime `_span_*` / `_covers_*` tests at
// `error.rs`'s tests module — those enforce the same theorem at
// `cargo test` time through direct runtime calls to this helper, so
// the theorem is still bound at TWO stages of the toolchain (compile
// time through the delegated path inside the compound helper, test
// time through the direct runtime calls). Contiguity-axis peer to the
// four `assert_u8_array_covers_inclusive_range` witnesses above:
// those close the contiguous-range corner of the SURJECTIVITY-only
// axis at the four range-covering HASH_DISCRIMINATORS arrays;
// `StructuralKind::HASH_DISCRIMINATORS` was the sole array closing the
// non-contiguous-finite-set corner of the SURJECTIVITY-only axis, and
// now instead binds through the stronger compound helper's
// non-contiguous corner.
/// Compile-time contract verifier — panics at const evaluation time if
/// `arr` is not a PERMUTATION of the inclusive integer range `[LO..=HI]`
/// on the substrate's `u8` cache-key vocabulary. Binds THREE conjunct
/// clauses at ONE `const _` line:
/// 1. ARITY-MISMATCH: `N` MUST equal `HI - LO + 1` — a bijection
/// between `[0..N)` and `[LO..=HI]` forces the cardinality equality
/// by pigeonhole. A regression that adds a spurious duplicate entry
/// to a HASH_DISCRIMINATORS array (bumping `N` past the range's
/// cardinality) fails-loudly at this arm with the ARITY-MISMATCH-
/// provenance panic message. Delegated to no sibling — this arm is
/// the compound helper's unique contribution.
/// 2. Range-membership: every entry in `arr` lies in `[LO, HI]` —
/// delegated to [`assert_u8_array_covers_inclusive_range`] (which
/// ALSO sweeps the FULL-COVERAGE axis; both axes bind through the
/// one delegation call).
/// 3. Pairwise-distinctness: every pair of entries is distinct —
/// delegated to [`assert_u8_array_pairwise_distinct`].
///
/// (1) ∧ (2) ∧ (3) jointly imply the array's entries EXACTLY partition
/// the range: `N` distinct entries chosen from a range of cardinality
/// `N` MUST equal the entire range by pigeonhole. The single compound
/// invocation therefore binds the same theorem as the pair
/// `assert_u8_array_pairwise_distinct(&arr) + assert_u8_array_covers_
/// inclusive_range::<N, LO, HI>(&arr)` PLUS the arity-mismatch check
/// (1) that neither weak sibling carries alone — a strictly stronger
/// contract at HALF the per-array witness-line surface.
///
/// Compression: pre-lift, each of the three intentionally-permutation-
/// shaped HASH_DISCRIMINATORS arrays ([`AtomKind::HASH_DISCRIMINATORS`],
/// [`QuoteForm::HASH_DISCRIMINATORS`],
/// [`crate::error::UnquoteForm::HASH_DISCRIMINATORS`]) bound its
/// permutation contract at TWO `const _` lines (one
/// `assert_u8_array_pairwise_distinct` for INJECTIVITY, one
/// `assert_u8_array_covers_inclusive_range` for SURJECTIVITY-onto-a-
/// range) — six witness lines total across the three arrays. Post-lift
/// each array binds the same theorem PLUS the arity-mismatch check at
/// ONE `const _` line — three witness lines total, a 2:1 compression.
/// [`crate::error::StructuralKind::HASH_DISCRIMINATORS`] stays on the
/// weak-pair contract because its distinct-value set `{0, 2}` is
/// NON-contiguous (gap at `1u8` where the atomic-carve outer marker
/// lives) — the non-contiguous corner binds through
/// `assert_u8_array_pairwise_distinct` + `assert_u8_array_covers_
/// finite_set` instead, awaiting a future `assert_u8_array_permutes_
/// finite_set` compound helper on the non-contiguous corner of the
/// (contiguity) axis. [`crate::error::SexpShape::HASH_DISCRIMINATORS`]
/// stays on the range-coverage-only contract because its twelve-shape →
/// seven-byte collapse means INJECTIVITY DOES NOT hold — so it CANNOT
/// bind a permutation contract on any range corner.
///
/// The invariant is load-bearing for the three permutation-shaped
/// sub-carvings' outer-`Sexp` cache-key partition binding. Each of the
/// three arrays MUST bijectively permute its assigned range corner of
/// `{0..=6}` so `Hash for Sexp`'s outer discriminator hash sequence
/// stays injective on each sub-partition: [`AtomKind::HASH_DISCRIMINATORS`]
/// permutes `{0..=5}` on the nested atomic-payload carve inside `Hash
/// for Atom`; [`QuoteForm::HASH_DISCRIMINATORS`] permutes `{3..=6}` on
/// the quote-family arms of `Hash for Sexp`; UnquoteForm permutes
/// `{5..=6}` on the substitution-subset of the quote-family. A
/// regression that silently unified two arm's cache-key bytes on ANY
/// of the three arrays — OR lifted a fresh N+1 entry drifting `N` above
/// the range's cardinality — would silently invalidate every cached
/// `Sexp` participating in `Expander::cache`. The compound witness
/// catches all three drift modes at COMPILE time.
///
/// Adding a new family-wide `[u8; N]` permutation-of-range array to
/// the substrate: pair the declaration with `const _: () =
/// assert_u8_array_permutes_inclusive_range::<N, LO, HI>(&Self::
/// FOO_ARRAY);` co-located after the array's declaration and the
/// permutation contract binds at compile time. The rustc-forced arity
/// `[u8; N]` composes with this const-eval sweep so cardinality AND
/// arity-cardinality-match AND range-membership AND pairwise-
/// distinctness AND (by pigeonhole) full range-coverage are ALL
/// compile-time theorems on the SAME array from ONE `const _` line.
/// Prefer this compound helper over the weak-pair pattern for any
/// array whose distinct-value set is intentionally EXACTLY a
/// contiguous inclusive range with the array acting as a permutation
/// of it — the two weak helpers stay as the fallback for arrays with
/// LOOSER contracts (e.g. `SexpShape::HASH_DISCRIMINATORS`'s
/// intentionally-non-injective twelve → seven collapse binds only the
/// coverage weak sibling).
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by the four negative
/// runtime pins (`_panics_at_runtime_on_arity_below_cardinality`,
/// `_panics_at_runtime_on_arity_above_cardinality`,
/// `_panics_at_runtime_on_duplicate`,
/// `_panics_at_runtime_on_out_of_range`) that jointly exercise each of
/// the three failure arms.
///
/// The ARITY-MISMATCH panic site carries an axis-provenance string
/// ("ARITY-MISMATCH") chosen DISTINCT from every sibling helper's axis
/// strings ("OUT-OF-RANGE" / "MISSING" on the range-coverage helper;
/// "OUT-OF-SET" / "SET-BYTE-MISSING" on the finite-set-coverage
/// helper) so downstream diagnostics that name the failed axis route
/// UNAMBIGUOUSLY to (a) this compound helper, and (b) the specific
/// arm — a permutation-shaped drift that fails ARITY-MISMATCH is
/// distinct from a range-coverage-drift that fails OUT-OF-RANGE or
/// MISSING at the delegated coverage helper. The two delegated helpers
/// each panic with THEIR OWN provenance strings so drift on the
/// range-membership or pairwise-distinctness arm surfaces with the
/// respective sibling helper's message body.
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide permutation-
/// of-range contract on the `u8` cache-key vocabulary becomes a
/// TYPE-LEVEL theorem the substrate carries per array declaration
/// at ONE `const _` line rather than at TWO per-axis `const _` lines
/// the developer must remember to keep in lockstep across every
/// permutation-shaped HASH_DISCRIMINATORS array.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the permutation-shaped sub-carvings' arrays on the typed
/// algebra makes cardinality drift a compile error rather than a
/// silent `Hash for Sexp` mis-hash on a caller keyed on a
/// permutation-shaped sub-carve.
/// - THEORY.md §VI.1 — generation over composition; the compound
/// arity-check + range-coverage + pairwise-distinctness sweep IS
/// the generative shape. Every new closed-set discriminator array
/// whose distinct-value set is an intentionally-closed contiguous
/// inclusive range with the array acting as a permutation of it
/// adds ONE `const _` line to get the permutation theorem rather
/// than re-deriving TWO per-axis `const _` lines (one for
/// injectivity, one for surjectivity) that would silently drift out
/// of lockstep if one was updated without the other.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// compound permutation proof at declaration site AND the three
/// consumer sites (nested atomic-payload carve inside `Hash for
/// Atom`, quote-family arms of `Hash for Sexp`, substitution-subset
/// of the quote-family) regenerate through the SAME `const _`
/// witness at each of the three permutation-shaped arrays.
///
/// Compound sibling posture to the constituent weak helpers on the
/// (axis-count) axis:
/// [`assert_u8_array_pairwise_distinct`] closes the SINGLE-axis
/// INJECTIVITY corner; [`assert_u8_array_covers_inclusive_range`]
/// closes the SINGLE-axis SURJECTIVITY-onto-range corner; this
/// compound helper closes the DOUBLE-axis (INJECTIVITY ∧ SURJECTIVITY
/// ∧ ARITY) corner on the range side of the (contiguity) axis. The
/// non-contiguous compound corner (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY
/// on a finite non-contiguous set) is a future lift's target — the
/// only pre-existing arm that would bind is
/// [`crate::error::StructuralKind::HASH_DISCRIMINATORS`], currently
/// held by the two-weak-witness pattern.
pub const fn assert_u8_array_permutes_inclusive_range<
const N: usize,
const LO: u8,
const HI: u8,
>(
arr: &[u8; N],
) {
// Arity check FIRST — pigeonhole forces `N == HI - LO + 1` on a
// bijection between `[0..N)` and `[LO..=HI]`. Placing this arm
// FIRST gives cleaner provenance: a drift that grows the array
// past the range cardinality would ALSO fail either the
// out-of-range arm (if the extra entry lies outside `[LO, HI]`)
// OR the pairwise-distinct arm (if it duplicates within range),
// but the ARITY-MISMATCH-named panic message routes the operator
// to the CARDINALITY axis directly rather than to a downstream
// symptom on either weak-axis helper.
let expected_cardinality = (HI - LO) as usize + 1;
if N != expected_cardinality {
panic!(
"assert_u8_array_permutes_inclusive_range: family-wide u8 \
array's ARITY-MISMATCH — the compile-time array cardinality \
`N` does not equal the target inclusive range's cardinality \
`HI - LO + 1`. A bijection between `[0..N)` and `[LO..=HI]` \
forces `N == HI - LO + 1` by pigeonhole — an array whose \
arity drifts above the range's cardinality CANNOT stay both \
pairwise-distinct AND within the range (extras must \
duplicate OR fall outside), and one whose arity drifts \
below CANNOT reach every range byte. The substrate's \
PERMUTATION contract on the array is broken at the ARITY \
axis; every consumer that expects the array's entries to \
bijectively permute the target range (AtomKind / QuoteForm \
/ UnquoteForm sub-carving spaces on their permutation-\
shaped range corners on Hash for Sexp's outer discriminator \
partition) relies on this cardinality equality"
);
}
// Delegate pairwise-distinctness to the sibling injectivity
// helper SECOND (before the range-coverage delegation). Order
// matters for provenance-preservation on the failure modes: with
// `N == HI - LO + 1` (post-arity-check), a duplicate entry
// pigeonhole-forces a missing range byte AND vice-versa — the
// two axes are logically equivalent given arity-cardinality
// match. Placing pairwise-distinct BEFORE covers-range routes a
// duplicate to the sibling's `"duplicate"`-named panic on the
// INJECTIVITY axis (rather than to the covers-range sibling's
// `"MISSING"`-named panic on the SURJECTIVITY axis which would
// fire downstream on the pigeonhole-forced coverage failure).
// Choosing INJECTIVITY-provenance as the primary duplicate-
// surfacing arm matches operator expectations: a "duplicate
// entry" diagnosis names the CAUSE (two entries alias) rather
// than a downstream SYMPTOM (a range byte is unreached because
// its slot is duplicated).
assert_u8_array_pairwise_distinct(arr);
// Delegate range-membership + full-range-coverage to the sibling
// covers-range helper THIRD. Given the two prior arms
// (arity-cardinality-match + pairwise-distinct), the covers-
// range helper's SECOND (`"MISSING"`) arm becomes unreachable
// by pigeonhole: `N` distinct entries chosen from a range of
// cardinality `N` MUST equal the range. Only the FIRST
// (`"OUT-OF-RANGE"`) arm surfaces in practice — a drift that
// lifts an entry outside `[LO, HI]` while staying pairwise-
// distinct panics with the sibling's `"OUT-OF-RANGE"` provenance.
// The delegated coverage sweep at the second arm is kept for
// DEFENSE-IN-DEPTH: a regression that silently dropped the
// pairwise-distinct delegation above would leave a duplicate
// uncaught by the compound helper's OWN body, but the covers-
// range sibling's MISSING check would then catch it as a
// safety-net symptom.
assert_u8_array_covers_inclusive_range::<N, LO, HI>(arr);
}
/// Compile-time contract verifier — panics at const evaluation time if
/// `arr` is not a PERMUTATION of the caller-supplied FINITE SET `set`
/// on the substrate's `u8` cache-key vocabulary. NON-CONTIGUOUS-FINITE-
/// SET peer of the pre-existing [`assert_u8_array_permutes_inclusive_range`]
/// sibling on the (contiguity) axis of the substrate's compound
/// (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) permutation verifiers: where
/// the sibling closes the CONTIGUOUS-INCLUSIVE-RANGE corner (at the
/// three permutation-shaped range-covering HASH_DISCRIMINATORS arrays
/// [`AtomKind::HASH_DISCRIMINATORS`] / [`QuoteForm::HASH_DISCRIMINATORS`]
/// / [`crate::error::UnquoteForm::HASH_DISCRIMINATORS`]), this closes
/// the NON-CONTIGUOUS-FINITE-SET corner (at the one permutation-shaped
/// non-contiguous-covering HASH_DISCRIMINATORS array
/// [`crate::error::StructuralKind::HASH_DISCRIMINATORS`], whose
/// distinct-value set `{0, 2}` is intentionally NON-contiguous with a
/// gap at `1u8` where the atomic-carve outer marker
/// [`AtomKind::OUTER_HASH_DISCRIMINATOR`] lives). Binds FOUR conjunct
/// clauses at ONE `const _` line:
///
/// 1. SET-NOT-PAIRWISE-DISTINCT: the caller-provided TARGET-SET
/// spec `set` MUST itself be pairwise-distinct — a mathematical
/// finite set of cardinality `M` cannot carry a duplicate entry.
/// Post-lift the pre-lift caveat "assuming `set` is itself
/// pairwise-distinct — a well-formedness responsibility on the
/// caller-provided target spec" is now a compile-time theorem
/// the substrate carries per call site rather than a docstring-
/// level responsibility the operator must remember to keep in
/// lockstep with every downstream covers/permutes invocation.
/// Delegated to [`assert_u8_finite_set_pairwise_distinct`] at
/// the TOP of the delegation chain (before the ARITY arm below
/// because a malformed `set` renders the pigeonhole invariants
/// the ARITY arm relies on unsound with a PHANTOM-`M`).
/// 2. ARITY-MISMATCH: `N` MUST equal `M` — a bijection between
/// `[0..N)` and the target set `set` (whose cardinality now
/// provably equals `M` post-clause-1's well-formedness check)
/// forces the cardinality equality by pigeonhole. A regression
/// that adds a spurious duplicate entry to a HASH_DISCRIMINATORS
/// array (bumping `N` past the set's cardinality) fails-loudly at
/// this arm with the ARITY-MISMATCH-provenance panic message.
/// Delegated to no sibling — this arm is the compound helper's
/// unique contribution.
/// 3. Pairwise-distinctness: every pair of entries is distinct —
/// delegated to [`assert_u8_array_pairwise_distinct`].
/// 4. Set-membership + full-set-coverage: every entry lies in `set`
/// AND every set byte is reached — delegated to
/// [`assert_u8_array_covers_finite_set`] (which sweeps BOTH the
/// SET-MEMBERSHIP and FULL-COVERAGE arms, AND re-runs clause 1's
/// SET-WELL-FORMEDNESS delegation as defense-in-depth; all three
/// bind through the one delegation call).
///
/// (1) ∧ (2) ∧ (3) ∧ (4) jointly imply the array's entries EXACTLY
/// partition the set: `N == M` distinct entries chosen from a set of
/// cardinality `M` (proven-well-formed by clause 1) MUST equal the set
/// by pigeonhole. The single compound invocation therefore binds
/// the same theorem as the pair `assert_u8_array_pairwise_distinct(
/// &arr) + assert_u8_array_covers_finite_set::<N, M>(&arr, &set)` PLUS
/// the arity-mismatch check (1) that neither weak sibling carries
/// alone — a strictly stronger contract at HALF the per-array
/// witness-line surface.
///
/// Compression: pre-lift,
/// [`crate::error::StructuralKind::HASH_DISCRIMINATORS`] (`[u8; 2]`
/// permuting the non-contiguous partition `{0, 2}`) bound its
/// permutation-of-finite-set contract at TWO `const _` lines (one
/// `assert_u8_array_pairwise_distinct` for INJECTIVITY, one
/// `assert_u8_array_covers_finite_set` for SURJECTIVITY-onto-set) —
/// two scattered per-axis witness lines that would silently drift out
/// of lockstep if one was updated without the other. Post-lift the
/// array binds the same theorem PLUS the arity-mismatch check at ONE
/// `const _` line — a 2:1 compression at strictly stronger contract
/// strength, symmetric to the sibling
/// [`assert_u8_array_permutes_inclusive_range`]'s 2:1 compression on
/// the three range-covering permutation-shaped arrays. Together the
/// two compound helpers close the WHOLE compound tier of the
/// substrate's `u8` array vocabulary: `StructuralKind` (on the non-
/// contiguous corner) plus `AtomKind` / `QuoteForm` / `UnquoteForm`
/// (on the contiguous corner) — four permutation-shaped arrays across
/// both contiguity postures now bind their compound
/// (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) permutation contract at ONE
/// `const _` line each. [`crate::error::SexpShape::HASH_DISCRIMINATORS`]
/// stays on the range-coverage-only single-axis sibling helper because
/// its intentionally-non-injective twelve-shape → seven-byte collapse
/// means INJECTIVITY does not hold — it CANNOT bind a permutation
/// contract on any contiguity corner.
///
/// The invariant is load-bearing for `StructuralKind`'s non-contiguous
/// sub-carve `{0, 2}` on the outer-`Sexp` cache-key partition:
/// `Sexp::Nil` and `Sexp::List(_)` MUST map bijectively to `{0u8, 2u8}`
/// so `Hash for Sexp`'s outer discriminator hash sequence stays
/// injective on the structural-residual sub-partition. The intentional
/// gap at `1u8` — where the atomic-carve outer marker
/// [`AtomKind::OUTER_HASH_DISCRIMINATOR`] lives — is EXACTLY the
/// reason StructuralKind CANNOT bind through the sibling
/// [`assert_u8_array_permutes_inclusive_range`] helper (its distinct-
/// value set is not a contiguous inclusive range). This compound
/// helper is the non-contiguous corner where StructuralKind's compound
/// contract binds at ONE line. A regression that silently unified two
/// StructuralKind arms' cache-key bytes (a duplicate on the
/// INJECTIVITY arm), OR lifted a fresh entry into the atomic-carve
/// gap at `1u8` (a drift on the SET-MEMBERSHIP arm), OR dropped an
/// entry making the set non-covering (a drift on the SET-BYTE-MISSING
/// arm), OR bumped `N` past the set cardinality (a drift on the ARITY
/// arm), would silently invalidate every cached `Sexp::List(_)` /
/// `Sexp::Nil` participating in `Expander::cache` — pre-lift these
/// four modes were caught only at runtime by the sibling helpers'
/// runtime tests + the pre-lift weak `const _` pair, post-lift the
/// compound `const _` witness catches all four drift modes at COMPILE
/// time at ONE line.
///
/// Adding a new family-wide `[u8; N]` permutation-of-finite-set array
/// to the substrate: pair the declaration with `const _: () =
/// assert_u8_array_permutes_finite_set::<N, M>(&Self::FOO_ARRAY,
/// &[…set…]);` co-located after the array's declaration and the
/// permutation-of-finite-set contract binds at compile time. The
/// rustc-forced arity `[u8; N]` composes with this const-eval sweep so
/// cardinality AND arity-cardinality-match AND set-membership AND
/// pairwise-distinctness AND (by pigeonhole) full set-coverage are
/// ALL compile-time theorems on the SAME array from ONE `const _`
/// line. Prefer this compound helper over the weak-pair pattern for
/// any array whose distinct-value set is intentionally EXACTLY the
/// given finite set with the array acting as a permutation of it —
/// the two weak helpers stay as the fallback for arrays with LOOSER
/// contracts. Prefer the tighter
/// [`assert_u8_array_permutes_inclusive_range`] sibling when the
/// target finite set IS a contiguous inclusive range — this helper is
/// the fallback for the non-contiguous corner.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by the four
/// negative runtime pins
/// (`_panics_at_runtime_on_arity_below_cardinality`,
/// `_panics_at_runtime_on_arity_above_cardinality`,
/// `_panics_at_runtime_on_duplicate`,
/// `_panics_at_runtime_on_out_of_set`) that jointly exercise each of
/// the three failure arms.
///
/// The ARITY-MISMATCH panic site carries the same axis-provenance
/// string `"ARITY-MISMATCH"` as the sibling
/// [`assert_u8_array_permutes_inclusive_range`]'s ARITY arm — the two
/// compound permutation helpers SHARE the arity axis-name because the
/// axis is the SAME (a cardinality-equality contract), but the HELPER
/// name in the panic message routes UNAMBIGUOUSLY to the SPECIFIC
/// contiguity corner (`"assert_u8_array_permutes_finite_set"` vs.
/// `"assert_u8_array_permutes_inclusive_range"`) — string search on
/// the axis PLUS the helper name jointly disambiguates the failed
/// (helper, axis) pair. The two delegated helpers each panic with
/// THEIR OWN provenance strings so drift on the pairwise-distinctness
/// or set-coverage arm surfaces with the respective sibling helper's
/// message body (`"duplicate"` on the INJECTIVITY axis; `"OUT-OF-SET"`
/// / `"SET-BYTE-MISSING"` on the SURJECTIVITY axis).
///
/// Theory grounding:
/// - THEORY.md §V.1 — knowable platform; the family-wide permutation-
/// of-finite-set contract on the `u8` cache-key vocabulary becomes
/// a TYPE-LEVEL theorem the substrate carries per array declaration
/// at ONE `const _` line rather than at TWO per-axis `const _` lines
/// the developer must remember to keep in lockstep across every
/// permutation-of-finite-set-shaped HASH_DISCRIMINATORS array.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the non-contiguous permutation-shaped sub-carvings'
/// arrays on the typed algebra makes cardinality drift a compile
/// error rather than a silent `Hash for Sexp` mis-hash on a caller
/// keyed on a non-contiguous permutation-shaped sub-carve.
/// - THEORY.md §VI.1 — generation over composition; the compound
/// arity-check + set-coverage + pairwise-distinctness sweep IS the
/// generative shape. Every new closed-set discriminator array whose
/// distinct-value set is an intentionally-closed non-contiguous
/// finite partition with the array acting as a permutation of it
/// adds ONE `const _` line to get the permutation theorem rather
/// than re-deriving TWO per-axis `const _` lines (one for
/// injectivity, one for surjectivity) that would silently drift out
/// of lockstep if one was updated without the other.
/// - THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// compound permutation-of-finite-set proof at declaration site AND
/// the consumer site (`StructuralKind` sub-carve inside
/// `Hash for Sexp` on `Sexp::Nil` / `Sexp::List(_)`) regenerate
/// through the SAME `const _` witness.
///
/// Compound sibling posture on the (contiguity) axis:
/// [`assert_u8_array_permutes_inclusive_range`] closes the CONTIGUOUS-
/// INCLUSIVE-RANGE corner (three arrays); this helper closes the
/// NON-CONTIGUOUS-FINITE-SET corner (one array). The two together
/// close the whole (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) compound tier
/// of the substrate's `u8` array vocabulary on both contiguity
/// postures — every intentionally-closed permutation-shaped `[u8; N]`
/// HASH_DISCRIMINATORS array on the substrate now binds its compound
/// permutation contract at ONE `const _` line regardless of whether
/// the target is a contiguous inclusive range or an arbitrary
/// non-contiguous finite set.
pub const fn assert_u8_array_permutes_finite_set<const N: usize, const M: usize>(
arr: &[u8; N],
set: &[u8; M],
) {
// Delegate target-set well-formedness to the sibling SET-side
// pairwise-distinctness helper FIRST — even BEFORE the ARITY
// check below. A malformed `set` (e.g. `[0u8, 2u8, 2u8]` at
// `M = 3`) with a duplicate entry inflates the effective
// cardinality with a PHANTOM-`M` and renders the pigeonhole
// invariants unsound: an `arr` of arity `N == M` that is
// pairwise-distinct and within-set would silently mis-verify
// as a permutation of a cardinality-`M` set when it is really
// covering a cardinality-`< M` set. Placing this arm FIRST
// routes drift on the CALLER'S TARGET-SET SPEC to the SET-side
// well-formedness axis rather than to a downstream ARITY-
// MISMATCH / duplicate / OUT-OF-SET symptom on `arr` (three
// of which would surface DEPENDING on how the caller's mistake
// interacts with the `arr` under verification, producing
// inconsistent operator diagnostics for the SAME underlying
// root cause). The helper's own body re-runs this check via
// the delegated `assert_u8_array_covers_finite_set` call at
// the third arm below as defense-in-depth against a regression
// that silently dropped this delegation at the top; the two
// calls jointly bind the SET-side well-formedness contract at
// TWO stages of the compound helper's delegation chain.
assert_u8_finite_set_pairwise_distinct(set);
// ARITY-MISMATCH check SECOND — pigeonhole forces `N == M` on a
// bijection between `[0..N)` and `set` (given the SET-side
// well-formedness delegated above; the pre-lift docstring's
// "assuming `set` is itself pairwise-distinct" caveat is now a
// compile-time theorem the substrate carries per call site).
// Placing this arm HERE (after well-formedness) gives cleaner
// provenance: a drift that grows the array past the set
// cardinality would ALSO fail either the pairwise-distinct arm
// (if the extra entry duplicates a within-set byte) OR the
// covers-finite-set arm's `"OUT-OF-SET"` axis (if the extra
// entry lies outside `set`), but the ARITY-MISMATCH-named panic
// message routes the operator to the CARDINALITY axis directly
// rather than to a downstream symptom on either weak-axis helper.
if N != M {
panic!(
"assert_u8_array_permutes_finite_set: family-wide u8 array's \
ARITY-MISMATCH — the compile-time array cardinality `N` \
does not equal the target finite set's cardinality `M`. A \
bijection between `[0..N)` and the target set forces `N \
== M` by pigeonhole (given `set`'s well-formedness \
delegated to `assert_u8_finite_set_pairwise_distinct` \
at the top of this helper before the ARITY arm) — an \
array whose arity \
drifts above the set's cardinality CANNOT stay both \
pairwise-distinct AND within the set (extras must \
duplicate OR fall outside), and one whose arity drifts \
below CANNOT reach every set byte. The substrate's \
PERMUTATION-of-FINITE-SET contract on the array is broken \
at the ARITY axis; every consumer that expects the \
array's entries to bijectively permute the target set \
(StructuralKind's `{{0, 2}}` non-contiguous sub-carving \
on Hash for Sexp's outer discriminator partition around \
the atomic-carve gap at `1u8`) relies on this cardinality \
equality"
);
}
// Delegate pairwise-distinctness to the sibling injectivity
// helper SECOND (before the finite-set-coverage delegation). Order
// matters for provenance-preservation on the failure modes: with
// `N == M` (post-arity-check) and `set` well-formed, a duplicate
// entry in `arr` pigeonhole-forces a missing set byte AND vice-
// versa — the two axes are logically equivalent given arity-
// cardinality-match. Placing pairwise-distinct BEFORE covers-
// finite-set routes a duplicate to the sibling's `"duplicate"`-
// named panic on the INJECTIVITY axis (rather than to the
// covers-finite-set sibling's `"SET-BYTE-MISSING"`-named panic
// on the SURJECTIVITY axis which would fire downstream on the
// pigeonhole-forced coverage failure). Matches the sibling
// `assert_u8_array_permutes_inclusive_range`'s ordering: name
// the CAUSE (duplicate) rather than the pigeonhole-forced
// downstream SYMPTOM (SET-BYTE-MISSING).
assert_u8_array_pairwise_distinct(arr);
// Delegate set-membership + full-set-coverage to the sibling
// covers-finite-set helper THIRD. Given the two prior arms
// (arity-cardinality-match + pairwise-distinct on `arr`), the
// covers-finite-set helper's SECOND (`"SET-BYTE-MISSING"`) arm
// becomes unreachable by pigeonhole assuming `set` is well-
// formed: `N == M` distinct entries chosen from a set of
// cardinality `M` MUST equal the set. Only the FIRST
// (`"OUT-OF-SET"`) arm surfaces in practice — a drift that lifts
// an entry outside `set` while staying pairwise-distinct panics
// with the sibling's `"OUT-OF-SET"` provenance. The delegated
// coverage sweep at the second arm is kept for DEFENSE-IN-DEPTH:
// a regression that silently dropped the pairwise-distinct
// delegation above would leave a duplicate uncaught by the
// compound helper's OWN body, but the covers-finite-set
// sibling's `"SET-BYTE-MISSING"` check would then catch it as a
// safety-net symptom.
assert_u8_array_covers_finite_set::<N, M>(arr, set);
}
// Compile-time permutation-of-finite-set witness — one `const _: () =
// assert_u8_array_permutes_finite_set::<N, M>(&…, &[…])` per family-
// wide `[u8; N]` hash-discriminator array on the substrate's closed-
// set outer algebras whose distinct-value set is an intentionally-
// closed non-contiguous finite partition with the array acting as a
// permutation of it. Each invocation is const-evaluated at `cargo
// check` time; a regression that silently drifts the array's
// cardinality away from the set's cardinality OR silently collides
// two entries OR silently drifts an entry outside the set (including
// the archetype drift into the intentional gap at `1u8`) fails the
// build rather than the test suite. Compression peer to the pre-lift
// `assert_u8_array_pairwise_distinct` + `assert_u8_array_covers_
// finite_set` weak-witness pair on the (axis-count) axis: those bound
// `StructuralKind::HASH_DISCRIMINATORS`' invariants at TWO `const _`
// lines (one per axis); this compound helper binds the same theorem
// PLUS the arity-cardinality-equality contract at ONE `const _`
// line — a 2:1 compression at strictly stronger contract strength.
// Contiguity-axis peer to the three `assert_u8_array_permutes_
// inclusive_range` witnesses above: those close the contiguous-
// inclusive-range corner of the compound tier at the three
// permutation-shaped range-covering HASH_DISCRIMINATORS arrays
// (`AtomKind`, `QuoteForm`, `UnquoteForm`); this closes the non-
// contiguous-finite-set corner at the ONE non-contiguous-covering
// permutation-shaped array (`StructuralKind`). Together the two
// compound helpers close the WHOLE compound (INJECTIVITY ∧
// SURJECTIVITY ∧ ARITY) tier of the substrate's `u8` array vocabulary
// on both contiguity postures — every intentionally-closed
// permutation-shaped `[u8; N]` HASH_DISCRIMINATORS array on the
// substrate now binds its compound permutation contract at ONE
// `const _` line regardless of whether the target is a contiguous
// inclusive range or an arbitrary non-contiguous finite set.
const _: () = assert_u8_array_permutes_finite_set::<2, 2>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&[0u8, 2u8],
);
/// Compile-time compound (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) JOINT
/// permutation-of-inclusive-range verifier for a `(scalar, [u8; M], [u8; N])`
/// triple — the (`scalar-plus-two-arrays`) corner of the (carving-shape)
/// axis peer to [`assert_u8_array_permutes_inclusive_range`]'s
/// (`single-array`) corner. Panics at const-eval time (or at runtime for
/// dynamic callers) with an axis-provenance-named message iff the joint
/// union `{scalar} ∪ arr_a ∪ arr_b` fails ANY of:
///
/// 1. ARITY-MISMATCH — `1 + M + N != HI - LO + 1`. A joint bijection
/// between `[0..1+M+N)` and `[LO..=HI]` forces the cardinality
/// equality by pigeonhole. Placed FIRST so the panic message routes
/// the operator directly to the CARDINALITY axis rather than to a
/// downstream range-membership or count-exactly-once symptom.
/// 2. SCALAR-OUT-OF-RANGE — `scalar < LO || scalar > HI`.
/// 3. FIRST-ARRAY-OUT-OF-RANGE — any `arr_a[i] < LO || arr_a[i] > HI`.
/// 4. SECOND-ARRAY-OUT-OF-RANGE — any `arr_b[j] < LO || arr_b[j] > HI`.
/// 5. JOINT-MISSING — some byte in `[LO..=HI]` occurs ZERO times across
/// `{scalar} ∪ arr_a ∪ arr_b`. Given post-arity + post-in-range, this
/// is equivalent to JOINT-duplicate on some OTHER range byte by
/// pigeonhole, but the message routes to the SURJECTIVITY axis for
/// the specific missing byte.
/// 6. JOINT-duplicate — some byte in `[LO..=HI]` occurs TWO or more times
/// across `{scalar} ∪ arr_a ∪ arr_b` (either cross-carving between
/// scalar and one array, cross-carving between the two arrays, OR
/// intra-carving inside a single array). Given post-arity +
/// post-in-range, this is equivalent to JOINT-MISSING on some other
/// range byte by pigeonhole, but the message routes to the
/// INJECTIVITY axis for the specific duplicated byte.
///
/// Arms 5 and 6 fuse into ONE `sweep [LO..=HI] and count exactly once` loop
/// — a byte with `count == 0` witnesses the SURJECTIVITY failure, a byte
/// with `count >= 2` witnesses the INJECTIVITY failure. The two logical
/// axes are equivalent given post-arity + post-in-range but the fused
/// sweep routes provenance to whichever byte violates first, matching the
/// (`"MISSING"` / `"duplicate"`) provenance vocabulary the sibling helpers
/// [`assert_u8_array_covers_inclusive_range`] and
/// [`assert_u8_array_pairwise_distinct`] use on the SINGLE-array corner.
///
/// Compression peer to a hypothetical decomposition through the three
/// pre-existing single-array helpers (`assert_u8_array_pairwise_distinct`
/// each on `[scalar]`/`arr_a`/`arr_b` + `assert_u8_array_covers_
/// inclusive_range` on the concatenation) on the (axis-count) axis: those
/// would need explicit concatenation at rustc time (impossible without
/// runtime `Vec`) OR three per-array + one joint-distinctness call
/// (four+ `const _` lines PLUS threading the joint check through a bespoke
/// primitive); this compound helper binds the SAME joint theorem PLUS the
/// scalar-plus-two-arrays cardinality-equality contract at ONE `const _`
/// line — the compression is 4:1 at strictly stronger contract strength on
/// the (scalar + two arrays) shape corner. Sibling posture on the
/// (carving-shape) axis of the substrate-primitive matrix:
/// * (single-array, permutes-range) — [`assert_u8_array_permutes_inclusive_range`]
/// * (scalar-plus-two-arrays, permutes-range) — THIS helper.
///
/// The load-bearing invariant this helper pins: the outer-`Sexp` cache-key
/// discriminator space `{0..=6}` partitions across the SUBSTRATE'S THREE
/// carvings — [`AtomKind::OUTER_HASH_DISCRIMINATOR`] (scalar `1u8` for
/// `Sexp::Atom(_)`), [`crate::error::StructuralKind::HASH_DISCRIMINATORS`]
/// (`[u8; 2]` at `{0, 2}` for `Sexp::Nil`/`Sexp::List(_)`),
/// [`QuoteForm::HASH_DISCRIMINATORS`] (`[u8; 4]` at `{3, 4, 5, 6}` for the
/// four quote-family variants). Post-lift the JOINT permutation binds at
/// rustc time via ONE `const _` witness; a drift at ANY of the three
/// carvings (renumbered atomic marker, extra `StructuralKind` variant with
/// a byte outside `{0, 2}`, collision between `QuoteForm` and the atomic
/// marker) becomes a compile error rather than a `sexp_shape_hash_
/// discriminator_partitions_by_three_way_carving_disjointly` /
/// `structural_kind_hash_discriminator_disjoint_from_atom_outer_carve_
/// byte_and_quote_form_hash_discriminator_partition` runtime-test
/// regression.
///
/// Theory anchor: THEORY.md §II.1 invariant 5 — composition preserves
/// proofs; the joint carving's compound permutation contract composes
/// through the three sub-algebras' `HASH_DISCRIMINATOR`s and the const-fn
/// contract preserves the joint permutation-of-range proof across `rustc`
/// invocations byte-for-byte. THEORY.md §III — the typescape; the joint-
/// partition property becomes a TYPE-level theorem on the substrate rather
/// than a per-carving test-time invariant. THEORY.md §V.3 — three-pillar
/// attestation; the outer-`Sexp` cache-key partition is the substrate's
/// outer `Sexp` `intent_hash` composition axis — binding the joint
/// permutation at rustc time makes attestation-key drift a compile error
/// rather than a silent BLAKE3 mis-hash.
pub const fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range<
const M: usize,
const N: usize,
const LO: u8,
const HI: u8,
>(
scalar: u8,
arr_a: &[u8; M],
arr_b: &[u8; N],
) {
// ARITY-MISMATCH check FIRST — pigeonhole forces `1 + M + N ==
// HI - LO + 1` on a joint bijection between `[0..1+M+N)` and
// `[LO..=HI]`. Placing this arm FIRST gives cleaner provenance:
// a drift that grows the joint cardinality past the range
// cardinality would ALSO fail either the out-of-range arm OR
// the joint-duplicate arm, but the ARITY-MISMATCH-named panic
// routes the operator to the CARDINALITY axis directly rather
// than to a downstream symptom on the other axes.
let expected_cardinality = (HI - LO) as usize + 1;
if 1 + M + N != expected_cardinality {
panic!(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range: \
family-wide (scalar, [u8; M], [u8; N]) triple's ARITY-\
MISMATCH — the compile-time joint cardinality `1 + M + N` \
does not equal the target inclusive range's cardinality \
`HI - LO + 1`. A joint bijection between `[0..1+M+N)` and \
`[LO..=HI]` forces `1 + M + N == HI - LO + 1` by pigeonhole \
— a joint carving whose cardinality drifts above the \
range's CANNOT stay both jointly-pairwise-distinct AND \
within the range (extras must duplicate OR fall outside), \
and one whose cardinality drifts below CANNOT reach every \
range byte. The substrate's JOINT PERMUTATION contract on \
the outer-`Sexp` cache-key partition (AtomKind's outer \
marker + StructuralKind + QuoteForm carvings jointly \
covering `{{0..=6}}`) is broken at the ARITY axis; every \
consumer that expects the joint carving to bijectively \
permute the target range (Hash for Sexp's outer \
discriminator partition, the three-carving-plus-atom-\
marker joint disjointness contract) relies on this \
cardinality equality"
);
}
// SCALAR-OUT-OF-RANGE arm.
if scalar < LO || scalar > HI {
panic!(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range: \
family-wide (scalar, [u8; M], [u8; N]) triple's scalar \
carries an OUT-OF-RANGE byte — the scalar lies outside \
the target inclusive range `[LO, HI]`. The substrate's \
RANGE-BOUND contract on the joint carving is broken at \
the scalar carving's arm; every consumer that expects the \
scalar-plus-two-arrays joint image to partition an outer \
cache-key space (Hash for Sexp's outer discriminator \
`{{0..=6}}`) relies on the scalar staying within the \
target range"
);
}
// FIRST-ARRAY-OUT-OF-RANGE arm.
let mut i = 0;
while i < M {
if arr_a[i] < LO || arr_a[i] > HI {
panic!(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range: \
family-wide (scalar, [u8; M], [u8; N]) triple's first \
array carries an OUT-OF-RANGE entry at some position — \
the entry's byte lies outside the target inclusive \
range `[LO, HI]`. The substrate's RANGE-BOUND contract \
on the joint carving is broken at the first-array \
carving's arm",
);
}
i += 1;
}
// SECOND-ARRAY-OUT-OF-RANGE arm.
let mut j = 0;
while j < N {
if arr_b[j] < LO || arr_b[j] > HI {
panic!(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range: \
family-wide (scalar, [u8; M], [u8; N]) triple's second \
array carries an OUT-OF-RANGE entry at some position — \
the entry's byte lies outside the target inclusive \
range `[LO, HI]`. The substrate's RANGE-BOUND contract \
on the joint carving is broken at the second-array \
carving's arm",
);
}
j += 1;
}
// JOINT-DISTINCTNESS ∧ JOINT-SURJECTIVITY fused via sweep-and-count.
// Given post-arity + post-in-range, the two logical axes are
// equivalent by pigeonhole but the fused sweep routes provenance to
// whichever byte violates first with the sibling helpers'
// (`"MISSING"` / `"duplicate"`) vocabulary preserved.
let mut b = LO;
loop {
let mut count: u32 = 0;
if scalar == b {
count += 1;
}
let mut i = 0;
while i < M {
if arr_a[i] == b {
count += 1;
}
i += 1;
}
let mut j = 0;
while j < N {
if arr_b[j] == b {
count += 1;
}
j += 1;
}
if count == 0 {
panic!(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range: \
family-wide (scalar, [u8; M], [u8; N]) triple is JOINT-\
MISSING a byte from the target inclusive range \
`[LO, HI]` — every byte in the range must appear at \
least once across the joint union `{{scalar}} ∪ arr_a \
∪ arr_b`. The substrate's JOINT FULL-COVERAGE contract \
on the outer-`Sexp` cache-key partition is broken; the \
SURJECTIVITY axis of the joint permutation fails on \
the specific missing range byte",
);
}
if count >= 2 {
panic!(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range: \
family-wide (scalar, [u8; M], [u8; N]) triple carries a \
JOINT duplicate byte — some byte in `[LO, HI]` appears \
TWO or more times across the joint union `{{scalar}} ∪ \
arr_a ∪ arr_b` (either cross-carving between scalar and \
an array, cross-carving between the two arrays, OR \
intra-carving inside a single array). The substrate's \
JOINT PAIRWISE-DISTINCTNESS contract on the outer-\
`Sexp` cache-key partition is broken; the INJECTIVITY \
axis of the joint permutation fails on the specific \
duplicated range byte",
);
}
if b == HI {
break;
}
b += 1;
}
}
// Compile-time permutation-of-range witnesses — one `const _: () =
// assert_u8_array_permutes_inclusive_range::<N, LO, HI>(&…)` per
// family-wide `[u8; N]` hash-discriminator array on the substrate's
// closed-set outer algebras whose distinct-value set is an
// intentionally-closed contiguous inclusive range with the array
// acting as a permutation of it. Each invocation is const-evaluated
// at `cargo check` time; a regression that silently drifts the
// array's cardinality above the range's cardinality OR silently
// collides two entries OR silently drifts an entry outside the range
// fails the build rather than the test suite. Compression peer to
// the pre-existing `assert_u8_array_pairwise_distinct` +
// `assert_u8_array_covers_inclusive_range` weak-witness pair on the
// (axis-count) axis: those bind the SAME three arrays' invariants at
// TWO `const _` lines per array (six lines total across the three
// arrays); this compound helper binds the same theorem PLUS the
// arity-cardinality-equality contract at ONE `const _` line per
// array (three lines total across the three arrays) — a 2:1
// compression at strictly stronger contract strength.
// `StructuralKind::HASH_DISCRIMINATORS` stays on the weak-pair
// (pairwise-distinct + covers-finite-set) pattern because its
// distinct-value set `{0, 2}` is NON-contiguous (gap at `1u8` where
// the atomic-carve outer marker lives) — the non-contiguous corner
// binds through a future `assert_u8_array_permutes_finite_set`
// compound helper on the non-contiguous corner of the (contiguity)
// axis. `SexpShape::HASH_DISCRIMINATORS` stays on the range-
// coverage-only pattern because its intentionally-non-injective
// twelve-shape → seven-byte collapse means INJECTIVITY does not hold
// — it CANNOT bind a permutation contract on any range corner.
const _: () = assert_u8_array_permutes_inclusive_range::<6, 0, 5>(&AtomKind::HASH_DISCRIMINATORS);
const _: () = assert_u8_array_permutes_inclusive_range::<4, 3, 6>(&QuoteForm::HASH_DISCRIMINATORS);
const _: () = assert_u8_array_permutes_inclusive_range::<2, 5, 6>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
);
// Compile-time FULL-ARRAY per-position ORDER pins — one `const _: () =
// assert_u8_array_slice_equals_u8_array::<N, N, 0>(&…, &[literal
// bytes; N])` per family-wide `[u8; N]` hash-discriminator
// SUB-CARVING array on the substrate's closed-set outer algebras.
// Each invocation exercises the [`assert_u8_array_slice_equals_u8_array`]
// helper at its FULL-ARRAY corner (`M == N`, `START == 0`) — the
// SLICE-EQUALS-ARRAY sweep collapses to an ALL-positions-equal-peer-
// array pointwise identity `arr == [b_0, b_1, …, b_{N-1}]`. The peer
// literal-byte sub-array on the RHS pins BOTH (a) the per-position
// ORDER of the outer array's declaration (the CANONICAL variant-
// declaration order that all `zip(ALL, HASH_DISCRIMINATORS)` consumers
// depend on) AND (b) each per-role `pub(crate) const *_HASH_DISCRIMINATOR`
// alias's canonical `u8` byte value the outer array's slots re-
// export. Strictly STRONGER on the (contract-strength) axis than the
// sibling permutation witnesses IMMEDIATELY ABOVE: those bind each
// array's IMAGE SET (`{0..=5}` for `AtomKind`, `{3..=6}` for
// `QuoteForm`, `{5..=6}` for `UnquoteForm`) via the JOINT
// (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) permutation-of-range contract
// but are SILENT on which SLOT of the array each byte lands at — a
// regression that swapped `SYMBOL_HASH_DISCRIMINATOR = 0` and
// `KEYWORD_HASH_DISCRIMINATOR = 1` (drifting `AtomKind::HASH_DISCRIMINATORS`
// from `[0, 1, 2, 3, 4, 5]` to `[1, 0, 2, 3, 4, 5]`) preserves the
// permutation witness's `{0..=5}` set-image AND the joint witness's
// scalar-plus-two-arrays `{0..=6}` set-image but silently misaligns
// the runtime pin `atom_kind_hash_discriminators_align_with_all_by_index`
// (which iterates `zip(AtomKind::ALL, AtomKind::HASH_DISCRIMINATORS)`
// and pins `HASH_DISCRIMINATORS[i] == ALL[i].hash_discriminator()` —
// after the swap `HASH_DISCRIMINATORS[0] == 1` but
// `ALL[0].hash_discriminator() == AtomKind::Symbol.hash_discriminator()
// == 0` fails the alignment at position 0). Post-lift the ARRAY-LEVEL
// per-position order binds at rustc time via ONE `const _` witness per
// array; a drift at either the per-role `pub(crate) const` byte OR
// the array declaration's ordering fails at `cargo check` BEFORE any
// test scheduler runs.
//
// The four `..._pin_legacy_cache_key_bytes` runtime pins the new
// witnesses supersede:
// * `atom_kind_hash_discriminators_pin_legacy_cache_key_bytes` (in
// `ast.rs`) — six `assert_eq!` on `AtomKind::{SYMBOL, KEYWORD, STR,
// INT, FLOAT, BOOL}_HASH_DISCRIMINATOR == {0, 1, 2, 3, 4, 5}`.
// * `quote_form_hash_discriminators_pin_legacy_cache_key_bytes` (in
// `ast.rs`) — four `assert_eq!` on `QuoteForm::{QUOTE, QUASIQUOTE,
// UNQUOTE, UNQUOTE_SPLICE}_HASH_DISCRIMINATOR == {3, 4, 5, 6}`.
// * `unquote_form_hash_discriminators_pin_legacy_cache_key_bytes` (in
// `error.rs`) — two `assert_eq!` on `UnquoteForm::{UNQUOTE,
// SPLICE}_HASH_DISCRIMINATOR == {5, 6}`.
// * `structural_kind_hash_discriminators_pin_legacy_cache_key_bytes`
// (in `error.rs`) — two `assert_eq!` on `StructuralKind::{NIL,
// LIST}_HASH_DISCRIMINATOR == {0, 2}`.
// Each runtime pin's fourteen total `assert_eq!` inline byte
// comparisons collapse to ONE `const _` witness per array (FOUR
// `const _` lines total) that bind the SAME per-role byte values
// AND the array's per-position ordering at rustc time. The runtime
// pins survive as sibling checks — they compose through the
// per-role `pub(crate) const` alias directly rather than the outer
// container array's declaration; a regression that drifted a
// per-role alias's declaration but LEFT the array's slot-i
// initializer with the correct literal byte inline (structurally
// distinct from the alias-source-of-truth path this family relies
// on) fails at the runtime pin as a distinct failure mode.
//
// Sibling posture to the four-witness EXHAUSTIVE per-position sweep
// on the OUTER `SexpShape::HASH_DISCRIMINATORS` container the trio
// of `assert_u8_array_slice_equals_u8_array::<12, {1, 4}, {0, 7, 8}>`
// witnesses + the `assert_u8_array_slice_is_scalar_replica::<12, 1, 7>`
// witness (all inside `ast.rs`, below the `Sexp` Hash impl area)
// close on the outer twelve-shape container. Those four witnesses
// pin the OUTER container against its FOUR sub-carvings; these four
// witnesses pin each SUB-CARVING array against its LITERAL bytes.
// Together the eight witnesses close the (outer container, sub-
// carving) × (per-position ORDER) 2×N face across the substrate's
// entire outer-`Sexp` cache-key hash-discriminator hierarchy at
// rustc time.
//
// `SexpShape::HASH_DISCRIMINATORS` is INTENTIONALLY OMITTED from
// this family sweep — the outer twelve-shape → seven-byte NON-
// INJECTIVE collapse means the outer container is NOT expressible
// as an equality with any literal `[u8; 12]` peer WITHOUT re-
// stating the six-way atomic-collapse block-constancy segment
// (which is ALREADY pinned via the sibling
// `assert_u8_array_slice_is_scalar_replica::<12, 1, 7>` witness
// below). The four SUB-CARVING arrays in this sweep ARE injective
// on their own carving; each one is expressible as `arr == [b_0,
// b_1, …, b_{N-1}]` with each `b_i` a DISTINCT byte, which is
// EXACTLY the shape `assert_u8_array_slice_equals_u8_array` at the
// FULL-ARRAY corner (`M == N`, `START == 0`) binds.
const _: () = assert_u8_array_slice_equals_u8_array::<6, 6, 0>(
&AtomKind::HASH_DISCRIMINATORS,
&[0u8, 1, 2, 3, 4, 5],
);
const _: () = assert_u8_array_slice_equals_u8_array::<4, 4, 0>(
&QuoteForm::HASH_DISCRIMINATORS,
&[3u8, 4, 5, 6],
);
const _: () = assert_u8_array_slice_equals_u8_array::<2, 2, 0>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
&[5u8, 6],
);
const _: () = assert_u8_array_slice_equals_u8_array::<2, 2, 0>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&[0u8, 2],
);
// Compile-time JOINT permutation-of-range witness — the ONE
// `(scalar, [u8; M], [u8; N])` triple across the substrate whose
// joint carving permutes the OUTER-`Sexp` cache-key discriminator
// range `{0..=6}` byte-for-byte. `AtomKind::OUTER_HASH_DISCRIMINATOR
// = 1u8` (the scalar arm on the atomic-carve marker byte for
// `Sexp::Atom(_)`) merges with `StructuralKind::HASH_DISCRIMINATORS
// = [0, 2]` (the structural-residual carving covering `Sexp::Nil`
// and `Sexp::List(_)` — NON-contiguous inside its own range because
// the `1u8` slot between `0` and `2` is reserved for the atomic-
// carve marker; this is EXACTLY the reason `StructuralKind::HASH_
// DISCRIMINATORS` stays on the weak-witness pair per the sibling
// comment above and does NOT bind through the single-array
// permutation helper) and `QuoteForm::HASH_DISCRIMINATORS = [3, 4,
// 5, 6]` (the quote-family carving covering `Sexp::Quote(_)` /
// `Sexp::Quasiquote(_)` / `Sexp::Unquote(_)` / `Sexp::UnquoteSplice
// (_)`, a permutation on its own range) to jointly cover the WHOLE
// outer-`Sexp` cache-key partition `{0..=6}`. Pre-lift this joint
// bijection was pinned ONLY at runtime via
// `structural_kind_hash_discriminator_disjoint_from_atom_outer_
// carve_byte_and_quote_form_hash_discriminator_partition` (in
// `error.rs`, sweeping the disjointness of the three carvings' byte
// spaces + full-range coverage via `BTreeSet`s) and
// `sexp_shape_hash_discriminator_partitions_by_three_way_carving_
// disjointly` (in `error.rs`, sweeping the shape-level `hash_
// discriminator` image partition via the three carvings'
// `as_atom_kind` / `as_quote_form` / `as_structural_kind`
// projections) — the theorem held only after `cargo test`
// scheduled the two tests. Post-lift the JOINT permutation binds at
// rustc time via ONE `const _` witness on the substrate CONSTANTS
// directly; a drift at ANY of the three carvings (renumbered atomic
// marker, an extra `StructuralKind` variant with a byte outside
// `{0, 2}`, a collision between `QuoteForm` and the atomic marker,
// an arity drift in either array) fails at `cargo check` BEFORE any
// test scheduler runs. The two runtime pins survive as sibling
// checks for the shape-level projection methods (a distinct failure
// mode from a drift in the constants themselves); together with
// this const witness the joint outer-`Sexp` partition theorem is
// enforced at BOTH stages of the toolchain — const-time on the
// CONSTANTS, test-time on the METHODS.
//
// The scalar-plus-two-arrays joint carving is the FIRST substrate
// primitive that binds a bijection across a NON-uniform tuple shape
// (a `u8` PLUS a `[u8; 2]` PLUS a `[u8; 4]`) — the pre-existing
// single-array `assert_u8_array_permutes_inclusive_range` witnesses
// above bind ONE-array permutations; a hypothetical decomposition
// through three single-array calls (one per carving) CANNOT bind
// the joint bijection without either concatenating the three
// carvings at rustc time (impossible without a runtime `Vec`) or
// threading joint-distinctness through a bespoke primitive
// separately (four+ `const _` lines total). The compound helper
// binds the joint theorem at ONE line.
const _: () = assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
AtomKind::OUTER_HASH_DISCRIMINATOR,
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `arr` at positions `[START..END)` is NOT byte-equal to
/// the peer `scalar`.
///
/// Opens the SLICE-BLOCK-CONSTANCY column on the (`u8`) row of the
/// (element-type × contract-shape) matrix. Row-dual sibling posture to
/// the pre-existing (`&'static str`)-row helper
/// [`assert_str_array_is_concatenation_of_two_scalar_replicas`], but
/// specialised to the (u8) element type AND generalised from a
/// FIXED-PARTITION two-block-covering-the-full-array shape to an
/// ARBITRARY sub-slice `[START..END)` inside a possibly-longer array
/// `[0..N)`. Where the (str)-row helper binds a FULL-ARRAY partition
/// `arr == [head; K] ++ [tail; N - K]` (both blocks together cover
/// `[0..N)` exactly), this helper binds a SINGLE-BLOCK SUB-SLICE
/// `arr[START..END) == [scalar; END - START]` (the positions OUTSIDE
/// the slice are unconstrained by this witness — they can carry any
/// bytes, potentially bound by peer witnesses on other slices).
///
/// The load-bearing carrier on the substrate is
/// [`crate::error::SexpShape::HASH_DISCRIMINATORS`] (`[u8; 12]`), whose
/// positions `[1..7)` INTENTIONALLY collapse onto the SINGLE outer
/// cache-key byte [`AtomKind::OUTER_HASH_DISCRIMINATOR`] (`= 1u8`) —
/// the six atomic outer shapes (`Symbol` / `Keyword` / `String` /
/// `Int` / `Float` / `Bool`) all route through `Sexp::Atom(_)`'s
/// SINGLE outer marker byte on the outer-`Sexp` Hash algebra, so their
/// twelve-shape → seven-byte collapse condenses SIX shape slots into
/// ONE cache-key byte. The six per-role
/// [`SexpShape::SYMBOL_HASH_DISCRIMINATOR`] /
/// [`SexpShape::KEYWORD_HASH_DISCRIMINATOR`] /
/// [`SexpShape::STRING_HASH_DISCRIMINATOR`] /
/// [`SexpShape::INT_HASH_DISCRIMINATOR`] /
/// [`SexpShape::FLOAT_HASH_DISCRIMINATOR`] /
/// [`SexpShape::BOOL_HASH_DISCRIMINATOR`] `pub(crate) const` aliases
/// are ALL declared as `= crate::ast::AtomKind::OUTER_HASH_DISCRIMINATOR`
/// on the six atomic-outer arms, so the array-level slice-block-
/// constancy theorem `SexpShape::HASH_DISCRIMINATORS[1..7) == [OUTER; 6]`
/// is the ARRAY-LEVEL surface of the six per-role aliases' shared
/// upstream. A regression that silently reroutes ONE alias (e.g.
/// renames `SexpShape::SYMBOL_HASH_DISCRIMINATOR` to alias
/// `StructuralKind::LIST_HASH_DISCRIMINATOR` instead) OR that reorders
/// `SexpShape::ALL` so a NON-atomic shape lands in positions `[1..7)`
/// (e.g. moves `SexpShape::List` into slot `4`, drifting `LIST_BYTE
/// = 2` into the atomic-collapse slice) fails at `cargo check` BEFORE
/// any test scheduler runs, at ONE `const _` line rather than at the
/// pre-lift sextet of per-alias assertions inside
/// `sexp_shape_hash_discriminators_pin_legacy_outer_cache_key_bytes`.
///
/// Bounds preconditions and gate ordering: three CARDINALITY gates
/// fire at the TOP of the sweep BEFORE any per-position content check
/// begins, so a caller-side turbofish arity slip fails-loud on the
/// bounds axis rather than silently degenerating into a truncated or
/// vacuous sweep:
/// * `START > N` → `START-OUT-OF-BOUNDS` panic. The caller's slice
/// start index sits OUTSIDE the array's valid position range
/// `[0..N]` (inclusive upper bound: `START == N` is the empty-slice
/// corner and is legal). A silent slip past this gate would either
/// panic on `arr[i]` bounds-check at runtime (const-eval catches it
/// first) or, on an over-cautious future refactor that gated with a
/// raw `START >= N`, silently reject the legal `START == N` empty
/// corner.
/// * `END > N` → `END-OUT-OF-BOUNDS` panic. The caller's slice end
/// index sits OUTSIDE the array's valid position range `[0..N]`.
/// Analogous to the `START` gate; the two gates jointly enforce
/// `START, END ∈ [0..N]` before any content sweep.
/// * `START > END` → `INVERTED-RANGE` panic. The caller supplied a
/// right-open slice `[START..END)` whose left bound exceeds its
/// right bound — mathematically the empty slice, but semantically a
/// caller-side turbofish typo (e.g. `::<12, 7, 1>` instead of
/// `::<12, 1, 7>`). Routes to a distinct gate rather than silently
/// accepting the empty sweep so a coordinated typo across `START`
/// and `END` fails-loud on the ordering axis rather than passing
/// vacuously.
/// * `START == END` is a LEGAL empty-slice corner: the sweep never
/// enters the loop body and the helper accepts. The pre-check
/// sequence gates only STRICT violations (`>`) so both endpoints
/// (`START == 0` and `END == N`) remain in range and the `START ==
/// END` empty case degenerates cleanly.
///
/// Delegates to `u8`'s native `==` in const-fn context — no auxiliary
/// byte-equality helper needed (unlike the (str)-row peer's
/// [`str_bytes_equal`] delegation). The single-scalar SLICE-BLOCK-
/// CONSTANCY sweep is the simplest shape in the const-fn family: ONE
/// outer `while i < END` from `i = START`, ONE inner comparison, ONE
/// panic arm.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_slice_content_drift`,
/// `assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_start_out_of_bounds`,
/// `assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_end_out_of_bounds`,
/// `assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_inverted_range`,
/// and
/// `assert_u8_array_slice_is_scalar_replica_panic_message_names_the_helper_and_slice_block_constancy_violation_axis`.
/// The panic-message axis-provenance strings
/// (`"SLICE-BLOCK-CONSTANCY-VIOLATION"`, `"START-OUT-OF-BOUNDS"`,
/// `"END-OUT-OF-BOUNDS"`, `"INVERTED-RANGE"`) are chosen DISTINCT
/// from every sibling helper's axis vocabulary so a diagnostic that
/// crosses helper boundaries stays unambiguous under `grep` on the
/// failed axis.
///
/// Theory grounding:
/// - THEORY.md §III — the typescape; the SLICE-BLOCK-CONSTANCY corner
/// on the (`u8`) row of the (element-type × contract-shape) matrix
/// becomes a TYPE-LEVEL theorem the substrate carries per (arr,
/// scalar, START, END) quadruple rather than a runtime iterator
/// sweep per quadruple. Complements the pre-existing (str)-row
/// FULL-ARRAY BLOCK-CONSTANCY sibling — the two together cover the
/// BLOCK-CONSTANCY column at BOTH the SUB-SLICE arity (this helper)
/// and the FULL-ARRAY-with-two-blocks arity (the sibling), on
/// COMPLEMENTARY element-type rows.
/// - THEORY.md §V.1 — knowable platform; the sub-slice constant-
/// block contract on the substrate's ONE MANY-TO-ONE-collapse
/// `[u8; N]` array binds at `cargo check` time via ONE `const _`
/// line, closing the drift-catch loop one invocation stage earlier
/// than the pre-lift sextet of per-alias assertions inside
/// `sexp_shape_hash_discriminators_pin_legacy_outer_cache_key_bytes`.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the six-way atomic-shape collapse at the ARRAY level
/// makes attestation-key drift on the atomic-collapse slice a
/// compile error rather than a silent BLAKE3 mis-hash across the
/// six atomic outer shapes.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// slice sweep IS the generative shape — every future MANY-TO-ONE
/// variant → canonical-projection substrate SUB-SLICE-CONSTANT
/// segment (a hypothetical `Signal::CLASSES` array whose middle
/// segment collapses several signal variants onto the SAME class
/// byte; a `ProcessPhase::CATEGORIES` array whose per-category
/// segments each collapse onto a shared category byte) picks up
/// the block-constant theorem at ONE new `const _` line rather
/// than at (END - START) inline byte comparisons per callsite.
pub const fn assert_u8_array_slice_is_scalar_replica<
const N: usize,
const START: usize,
const END: usize,
>(
arr: &[u8; N],
scalar: u8,
) {
if START > N {
panic!(
"assert_u8_array_slice_is_scalar_replica: START-OUT-OF-\
BOUNDS — the const parameter `START` sits OUTSIDE the \
array's valid position range `[0..N]` (inclusive upper \
bound: `START == N` is the LEGAL empty-slice corner). \
Fix at the `const _` witness's turbofish by reconciling \
`START` against the array's declared arity `N`. The \
START-OUT-OF-BOUNDS gate fires FIRST — a mistyped \
`START` on the caller side fails HERE before any per-\
position sweep begins, so a subtle bounds slip doesn't \
silently degenerate into a vacuous sweep OR a panic \
deeper in `arr[i]` bounds-checking."
);
}
if END > N {
panic!(
"assert_u8_array_slice_is_scalar_replica: END-OUT-OF-\
BOUNDS — the const parameter `END` sits OUTSIDE the \
array's valid position range `[0..N]` (inclusive upper \
bound: `END == N` is the LEGAL slice-to-end corner). \
Fix at the `const _` witness's turbofish by reconciling \
`END` against the array's declared arity `N`. Peer \
gate to the START-OUT-OF-BOUNDS arm above — the two \
gates jointly enforce `START, END ∈ [0..N]` before any \
content sweep."
);
}
if START > END {
panic!(
"assert_u8_array_slice_is_scalar_replica: INVERTED-RANGE \
— the const parameters `START` and `END` satisfy `START \
> END`, so the right-open slice `[START..END)` is \
mathematically empty but semantically a caller-side \
turbofish typo (e.g. `::<N, END, START>` instead of \
`::<N, START, END>`). Routes to a distinct gate rather \
than silently accepting the empty sweep so a coordinated \
typo across the two const parameters fails-loud on the \
ordering axis. The LEGAL empty-slice corner is `START \
== END` (accepted without entering the sweep); the \
STRICT `START > END` slip is what this gate rejects."
);
}
let mut i = START;
while i < END {
if arr[i] != scalar {
panic!(
"assert_u8_array_slice_is_scalar_replica: SLICE-BLOCK-\
CONSTANCY-VIOLATION — the family-wide `[u8; N]` \
array `arr` carries a byte at some position in \
`[START..END)` (the SLICE segment) that does NOT \
byte-equal the peer `scalar`. The substrate's SLICE-\
BLOCK-CONSTANCY contract on the array-slice is \
broken; every consumer that reads `arr[START..END)` \
as a homogeneous constant block sharing ONE \
canonical byte with the peer `scalar` (the SIX \
atomic-outer-shape collapse onto `crate::ast::\
AtomKind::OUTER_HASH_DISCRIMINATOR` at positions \
`[1..7)` of `crate::error::SexpShape::HASH_\
DISCRIMINATORS` — the twelve-shape → seven-byte \
collapse condensing SIX atomic shape slots into ONE \
outer-`Sexp` cache-key byte; any future MANY-TO-ONE \
variant → canonical-projection substrate SUB-SLICE-\
CONSTANT segment) relies on this invariant. Fix at \
the ARRAY-DECLARATION site (the drifted `arr[i]` \
entry inside the slice segment) OR at the per-role \
scalar constant that `scalar` re-exports — the \
choice depends on whether the drift is an \
unintended slot reorder inside the slice OR a \
rename of the canonical projection byte upstream."
);
}
i += 1;
}
}
// Compile-time SLICE-BLOCK-CONSTANCY witness — the ONE `[u8; N]`
// array on the substrate whose ARRAY-LEVEL structure carries a MANY-
// TO-ONE-COLLAPSE SUB-SLICE segment. `SexpShape::HASH_DISCRIMINATORS`
// (`[u8; 12]`) has positions `[1..7)` INTENTIONALLY collapsing onto
// the SINGLE outer cache-key byte `AtomKind::OUTER_HASH_DISCRIMINATOR
// = 1u8` — the six atomic outer shapes (`Symbol` / `Keyword` /
// `String` / `Int` / `Float` / `Bool`) all route through `Sexp::Atom(_)
// `'s SINGLE outer marker byte on the outer-`Sexp` Hash algebra, so
// their twelve-shape → seven-byte collapse condenses SIX shape slots
// into ONE cache-key byte. Pre-lift this six-way collapse was pinned
// ONLY through the six per-alias runtime assertions inside
// `sexp_shape_hash_discriminators_pin_legacy_outer_cache_key_bytes`
// (`assert_eq!(SexpShape::SYMBOL_HASH_DISCRIMINATOR, 1)` × six roles);
// post-lift the ARRAY-LEVEL slice constancy `SexpShape::HASH_
// DISCRIMINATORS[1..7) == [OUTER; 6]` binds at rustc-time via ONE
// `const _` line, one invocation stage earlier than the runtime pin.
// A regression that reorders `SexpShape::ALL` so a non-atomic variant
// lands in the atomic-collapse slice (e.g. moves `SexpShape::List`
// into slot `4`, drifting `LIST_BYTE = 2` into positions `[1..7)`) OR
// that reroutes ONE atomic-shape alias to a different upstream byte
// fails-loudly HERE at const-eval on the ARRAY-LEVEL slice.
//
// The three OTHER load-bearing SexpShape::HASH_DISCRIMINATORS slices
// are intentionally OMITTED from this compile-time sweep because they
// are ALREADY compile-time-enforced through TIGHTER contracts: the
// singleton slices `[0..1) == [NIL_BYTE]` and `[7..8) == [LIST_BYTE]`
// (`StructuralKind::NIL_HASH_DISCRIMINATOR` and `StructuralKind::LIST_
// HASH_DISCRIMINATOR`) are pinned via the peer `assert_scalar_plus_
// two_u8_arrays_permute_inclusive_range` witness above (which binds
// the outer joint bijection `{0..=6} == {OUTER} ⊕ StructuralKind::
// HASH_DISCRIMINATORS ⊕ QuoteForm::HASH_DISCRIMINATORS`); the four-
// element tail slice `[8..12) == QuoteForm::HASH_DISCRIMINATORS`
// (`[3, 4, 5, 6]`) is pinned via the peer `assert_u8_array_permutes_
// inclusive_range::<4, 3, 6>` witness above (which binds the tail
// slice's PERMUTATION-of-`[3..=6]` shape). Only the middle atomic-
// collapse slice `[1..7)` requires a NEW helper — its shape is
// MANY-TO-ONE-BLOCK-CONSTANT rather than PERMUTATION (which is
// injective and would fail on this six-of-one collapse) or SUBSET
// (which is weaker and would accept the drifted `[1, 1, 2, 1, 1, 1]`
// slice that this witness rejects on position 2).
const _: () = assert_u8_array_slice_is_scalar_replica::<12, 1, 7>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
AtomKind::OUTER_HASH_DISCRIMINATOR,
);
/// Compile-time contract verifier — panics at const evaluation time if
/// any entry of `full` at positions `[START..START + M)` is NOT byte-
/// equal to the peer `sub` entry at the same offset `[i - START]`.
///
/// Opens the SLICE-EQUALS-ARRAY column on the (`u8`) row of the
/// (element-type × contract-shape) matrix. Row-sibling posture to the
/// pre-existing SLICE-BLOCK-CONSTANCY corner on the SAME (`u8`) row
/// ([`assert_u8_array_slice_is_scalar_replica`]) — where that helper
/// binds a sub-slice `full[START..END) == [scalar; END - START]` to a
/// SINGLE scalar (a MANY-TO-ONE-COLLAPSE shape whose per-position
/// image is a CONSTANT byte), this helper binds a sub-slice
/// `full[START..START + M) == sub[..]` to a SIBLING ARRAY of arity `M`
/// (a POSITIONWISE-COMPOSITION shape whose per-position image is
/// carried by an INDEPENDENT peer array). The two together cover the
/// SUB-SLICE column at BOTH the SINGLE-scalar-image arity (the sibling
/// above) AND the ARRAY-of-length-`M`-image arity (this helper).
///
/// The load-bearing carrier on the substrate is the pair
/// ([`crate::error::SexpShape::HASH_DISCRIMINATORS`] (`[u8; 12]`),
/// [`QuoteForm::HASH_DISCRIMINATORS`] (`[u8; 4]`)) at the SexpShape
/// sub-slice `[8..12)`. Both arrays share their four byte values
/// (`3`, `4`, `5`, `6`) via the four per-role
/// [`QuoteForm::QUOTE_HASH_DISCRIMINATOR`] /
/// [`QuoteForm::QUASIQUOTE_HASH_DISCRIMINATOR`] /
/// [`QuoteForm::UNQUOTE_HASH_DISCRIMINATOR`] /
/// [`QuoteForm::UNQUOTE_SPLICE_HASH_DISCRIMINATOR`] `pub(crate) const`
/// aliases, but the two per-array declaration LISTINGS are independent
/// — a regression that reordered ONE array's arm listing without
/// reordering the other's (e.g. swapped positions 10 and 11 of the
/// outer `SexpShape::HASH_DISCRIMINATORS` array so `UNQUOTE_SPLICE`'s
/// byte `6` slid ahead of `UNQUOTE`'s byte `5` while leaving
/// `QuoteForm::HASH_DISCRIMINATORS` in its canonical order) would
/// preserve BOTH arrays' PERMUTATION-of-`[3..=6]` contract — the
/// pre-existing weak witness
/// [`assert_u8_array_permutes_inclusive_range::<4, 3, 6>`] on
/// [`QuoteForm::HASH_DISCRIMINATORS`] above binds the tail SLICE'S
/// image SET (`{3, 4, 5, 6}`) but is SILENT on the tail slice's
/// per-position ORDER against the peer [`QuoteForm::HASH_DISCRIMINATORS`]
/// listing. Pre-lift the POSITIONWISE-tail-equality against the sub-
/// carving array was pinned ONLY at runtime through the per-position
/// sweep inside
/// `sexp_shape_hash_discriminators_align_with_sub_carvings_by_projection`
/// (in `error.rs`), which routes each `SexpShape::HASH_DISCRIMINATORS
/// [i]` through the shape's sub-carving projection method
/// (`as_quote_form().unwrap().hash_discriminator()`) at test-time.
/// Post-lift the ARRAY-LEVEL slice-equals-array contract binds at
/// rustc-time via ONE `const _` line on the substrate CONSTANTS
/// directly — a regression that reordered ONE array's arm listing
/// fails at `cargo check` BEFORE any test scheduler runs.
///
/// Bounds preconditions and gate ordering: two CARDINALITY gates fire
/// at the TOP of the sweep BEFORE any per-position content check
/// begins, so a caller-side turbofish arity slip fails-loud on the
/// bounds axis rather than silently degenerating into a truncated or
/// vacuous sweep:
/// * `START > N` → `START-OUT-OF-BOUNDS` panic. The caller's slice
/// start index sits OUTSIDE the outer array's valid position range
/// `[0..N]` (inclusive upper bound: `START == N` combined with
/// `M == 0` is the LEGAL empty-slice corner and is accepted). A
/// silent slip past this gate would either panic on `full[START +
/// i]` bounds-check at runtime (const-eval catches it first) or, on
/// an over-cautious future refactor that gated with a raw `START >=
/// N`, silently reject the legal `START == N, M == 0` empty corner.
/// * `M > N - START` → `SLICE-LENGTH-OUT-OF-BOUNDS` panic. The
/// caller's sub-array arity `M` overruns the outer array's tail
/// `[START..N)` — semantically equivalent to `START + M > N` but
/// phrased through subtraction to avoid `usize` arithmetic overflow
/// on the (unrealistic but pedantic) `START, M` pair with
/// `START + M > usize::MAX`; gate 1 guarantees `START ≤ N` so
/// `N - START` never underflows. The overrun would land the sweep
/// at `full[START + i]` for some `i ∈ [N - START..M)` and panic
/// deeper in bounds-checking with a helper-name-less message.
/// * `M == 0` is a LEGAL empty-sub-array corner (the sweep never
/// enters the loop body and the helper accepts, regardless of
/// `START`). `START == N` with `M == 0` collapses to the empty-slice
/// corner at the RIGHT endpoint. The pre-check sequence gates only
/// STRICT violations (`>`) so both degenerate corners
/// (`M == 0`, `M == N - START` at the exact-fit right endpoint)
/// remain in range.
///
/// Delegates to `u8`'s native `==` in const-fn context — no auxiliary
/// byte-equality helper needed. The two-array positionwise-composition
/// sweep is the natural arity extension of the single-scalar sibling
/// above: ONE outer `while i < M` from `i = 0`, ONE inner comparison
/// `full[START + i] != sub[i]`, ONE panic arm.
///
/// Runtime callability: the function is a normal `pub const fn`, so
/// callers CAN also invoke it at runtime — pinned by
/// `assert_u8_array_slice_equals_u8_array_panics_at_runtime_on_positionwise_drift`,
/// `assert_u8_array_slice_equals_u8_array_panics_at_runtime_on_start_out_of_bounds`,
/// `assert_u8_array_slice_equals_u8_array_panics_at_runtime_on_slice_length_out_of_bounds`,
/// and
/// `assert_u8_array_slice_equals_u8_array_panic_message_names_the_helper_and_slice_equals_array_violation_axis`.
/// The panic-message axis-provenance strings
/// (`"SLICE-EQUALS-ARRAY-VIOLATION"`, `"START-OUT-OF-BOUNDS"`,
/// `"SLICE-LENGTH-OUT-OF-BOUNDS"`) are chosen DISTINCT from every
/// sibling helper's axis vocabulary — the sibling
/// [`assert_u8_array_slice_is_scalar_replica`] carries
/// `"SLICE-BLOCK-CONSTANCY-VIOLATION"` / `"END-OUT-OF-BOUNDS"` /
/// `"INVERTED-RANGE"` on the SINGLE-scalar-image sweep, so a
/// diagnostic that crosses the two SUB-SLICE helpers routes back to
/// its authoring helper by axis string alone. The
/// `SLICE-LENGTH-OUT-OF-BOUNDS` axis renames what would be the
/// sibling's `END-OUT-OF-BOUNDS` gate to reflect the shift from
/// `(START, END)` const generics to `(START, M)` — the CARDINALITY
/// carrier is the peer array's arity `M`, not an END index.
///
/// Theory grounding:
/// - THEORY.md §III — the typescape; the SLICE-EQUALS-ARRAY corner on
/// the (`u8`) row of the (element-type × contract-shape) matrix
/// becomes a TYPE-LEVEL theorem the substrate carries per
/// `(full, sub, START)` triple rather than a runtime iterator sweep
/// through the sub-carving projection method per triple.
/// Complements the pre-existing SLICE-BLOCK-CONSTANCY sibling on
/// the SAME row — the two together open the SUB-SLICE column at
/// BOTH the SINGLE-scalar-image arity (constant block) AND the
/// ARRAY-of-length-`M`-image arity (positionwise composition).
/// - THEORY.md §V.1 — knowable platform; the positionwise
/// composition contract binding
/// `SexpShape::HASH_DISCRIMINATORS[8..12] ==
/// QuoteForm::HASH_DISCRIMINATORS` at rustc-time closes the drift-
/// catch loop one invocation stage earlier than the pre-lift
/// per-position runtime sweep inside
/// `sexp_shape_hash_discriminators_align_with_sub_carvings_by_projection`.
/// The runtime pin survives as a sibling check for the SHAPE-level
/// projection method chain (a distinct failure mode from a drift
/// in the constants themselves); together the two enforce the
/// theorem at BOTH stages of the toolchain.
/// - THEORY.md §V.3 — three-pillar attestation; the outer-`Sexp`
/// cache-key partition is the `intent_hash` composition axis —
/// binding the quote-family tail-slice's per-position ORDER at the
/// ARRAY level makes attestation-key drift on the four-slot quote-
/// family sub-carving a compile error rather than a silent BLAKE3
/// mis-hash across the four quote-family outer shapes.
/// - THEORY.md §VI.1 — generation over composition; the const-eval
/// slice sweep IS the generative shape — every future substrate
/// POSITIONWISE-COMPOSITION between a container array's sub-slice
/// and a sub-carving's canonical `[u8; M]` listing (a hypothetical
/// `Signal::CATEGORIES` outer array whose middle segment is
/// pointwise equal to a `CriticalSignal::CATEGORIES` sub-carving
/// array; a `ProcessPhase::ORDER` array whose leading segment is
/// pointwise equal to a `PreparationPhase::ORDER` sub-carving)
/// picks up the positionwise-equality theorem at ONE new `const _`
/// line rather than at `M` inline byte comparisons per callsite.
pub const fn assert_u8_array_slice_equals_u8_array<
const N: usize,
const M: usize,
const START: usize,
>(
full: &[u8; N],
sub: &[u8; M],
) {
if START > N {
panic!(
"assert_u8_array_slice_equals_u8_array: START-OUT-OF-\
BOUNDS — the const parameter `START` sits OUTSIDE the \
outer array's valid position range `[0..N]` (inclusive \
upper bound: `START == N` combined with `M == 0` is the \
LEGAL empty-slice-at-right-endpoint corner). Fix at the \
`const _` witness's turbofish by reconciling `START` \
against the outer array's declared arity `N`. The \
START-OUT-OF-BOUNDS gate fires FIRST — a mistyped \
`START` on the caller side fails HERE before the peer \
`SLICE-LENGTH-OUT-OF-BOUNDS` gate reads `N - START` \
(which would underflow `usize` had this gate not caught \
the slip), so a subtle bounds slip doesn't silently \
degenerate into a subtraction wrap-around OR a panic \
deeper in `full[START + i]` bounds-checking."
);
}
if M > N - START {
panic!(
"assert_u8_array_slice_equals_u8_array: SLICE-LENGTH-OUT-\
OF-BOUNDS — the peer sub-array's arity `M` exceeds the \
outer array's tail cardinality `N - START`, so the \
positionwise sweep `full[START + i]` for `i ∈ [0..M)` \
would overrun the outer array's valid position range \
`[0..N)` at some `i ∈ [N - START..M)`. Fix at the \
`const _` witness's turbofish by reconciling `M` against \
the outer array's tail cardinality `N - START` OR by \
narrowing `START` to leave a longer tail. The peer \
`START-OUT-OF-BOUNDS` gate above guarantees `START ≤ N` \
so `N - START` never underflows `usize` at this gate. \
The LEGAL exact-fit corner `M == N - START` (the sub-\
array reaches EXACTLY to the outer array's right \
endpoint) is accepted; the STRICT `M > N - START` slip \
is what this gate rejects."
);
}
let mut i = 0;
while i < M {
if full[START + i] != sub[i] {
panic!(
"assert_u8_array_slice_equals_u8_array: SLICE-EQUALS-\
ARRAY-VIOLATION — the outer `[u8; N]` array `full` \
carries a byte at some position `START + i` (for \
`i ∈ [0..M)`) that does NOT byte-equal the peer \
`[u8; M]` sub-array `sub` at the offset-matched \
position `i`. The substrate's SLICE-EQUALS-ARRAY \
positionwise-composition contract on the sub-slice \
`full[START..START + M) == sub[..]` is broken; \
every consumer that reads `full[START..START + M)` \
as a positionwise-aligned copy of the peer sub-\
carving array (the four-slot QUOTE-family tail \
`crate::error::SexpShape::HASH_DISCRIMINATORS[8..12] \
== crate::ast::QuoteForm::HASH_DISCRIMINATORS`; any \
future container-array sub-slice byte-for-byte equal \
to a peer sub-carving's canonical `[u8; M]` listing) \
relies on this invariant. Fix at the ARRAY-\
DECLARATION site (the drifted `full[START + i]` \
entry inside the slice segment) OR at the peer sub-\
array's arm listing — the choice depends on whether \
the drift is an unintended slot reorder in the outer \
array's tail OR in the sub-carving's own listing."
);
}
i += 1;
}
}
// Compile-time SLICE-EQUALS-ARRAY witness — the ONE `(container,
// sub-carving)` pair on the substrate whose ARRAY-LEVEL structure
// composes a container-array sub-slice byte-for-byte identical to a
// peer sub-carving's canonical `[u8; M]` listing. `SexpShape::HASH_
// DISCRIMINATORS[8..12]` (the four-slot quote-family tail of the
// outer twelve-shape array, `[3, 4, 5, 6]`) is byte-for-byte equal
// to `QuoteForm::HASH_DISCRIMINATORS` (the four-slot quote-family
// carving's canonical listing, `[3, 4, 5, 6]`). Both arrays share
// their four byte values via the four per-role `QuoteForm::{QUOTE,
// QUASIQUOTE, UNQUOTE, UNQUOTE_SPLICE}_HASH_DISCRIMINATOR`
// `pub(crate) const` aliases (the outer SexpShape array's tail-arm
// initializers each spell `Self::<ROLE>_HASH_DISCRIMINATOR` where
// each `SexpShape::<ROLE>_HASH_DISCRIMINATOR` is declared as an
// alias for `QuoteForm::<ROLE>_HASH_DISCRIMINATOR`), so the array-
// level positionwise-equality theorem `SexpShape::HASH_DISCRIMINATORS
// [8..12] == QuoteForm::HASH_DISCRIMINATORS` is the ARRAY-LEVEL
// surface of the four per-role aliases' shared upstream. Pre-lift
// this per-position tail equality was pinned ONLY at runtime through
// the per-position sweep inside `sexp_shape_hash_discriminators_
// align_with_sub_carvings_by_projection` (in `error.rs`, routing
// each `SexpShape::HASH_DISCRIMINATORS[i]` through the shape's sub-
// carving projection `as_quote_form().unwrap().hash_discriminator()`
// on the four quote-family arms); post-lift the ARRAY-LEVEL slice-
// equals-array contract binds at rustc-time via ONE `const _` line,
// one invocation stage earlier than the runtime pin. A regression
// that reorders the outer `SexpShape::HASH_DISCRIMINATORS` array's
// quote-family tail (e.g. swaps positions 10 and 11 so `UNQUOTE_
// SPLICE_HASH_DISCRIMINATOR = 6` slides ahead of `UNQUOTE_HASH_
// DISCRIMINATOR = 5`) while leaving `QuoteForm::HASH_DISCRIMINATORS`
// in its canonical order fails at `cargo check` BEFORE any test
// scheduler runs. The pre-existing `assert_u8_array_permutes_
// inclusive_range::<4, 3, 6>(&QuoteForm::HASH_DISCRIMINATORS)`
// witness above is STRICTLY WEAKER — it binds the sub-carving
// array's image SET is `{3, 4, 5, 6}` but is SILENT on the outer
// container array's tail per-position ORDER against the sub-
// carving's listing.
//
// The atomic-collapse sub-slice `SexpShape::HASH_DISCRIMINATORS
// [1..7)` stays on the sibling `assert_u8_array_slice_is_scalar_
// replica::<12, 1, 7>` witness above because its shape is MANY-TO-
// ONE-COLLAPSE onto a single scalar `AtomKind::OUTER_HASH_
// DISCRIMINATOR`, not POSITIONWISE-COMPOSITION with a peer array —
// there is no natural `[u8; 6]` sub-carving array to compose it
// against (the six atomic outer shapes collapse to a SCALAR image,
// not an array image). The two singleton slices `[0..1)` and
// `[7..8)` on the outer container are pinned via the two sibling
// `assert_u8_array_slice_equals_u8_array::<12, 1, _>` witnesses
// IMMEDIATELY BELOW — see the prose comment there for the per-
// slot binding on `StructuralKind::NIL_HASH_DISCRIMINATOR` and
// `StructuralKind::LIST_HASH_DISCRIMINATOR`. Together the four
// SexpShape `HASH_DISCRIMINATORS` sub-slice witnesses (the
// singleton `[0..1)`, the atomic-collapse `[1..7)`, the singleton
// `[7..8)`, the quote-family tail `[8..12)`) EXHAUSTIVELY pin the
// twelve-slot outer container's per-position byte SHAPE at rustc-
// time, closing the corner the runtime sweep
// `sexp_shape_hash_discriminators_align_with_sub_carvings_by_projection`
// (in `error.rs`) previously covered alone.
const _: () = assert_u8_array_slice_equals_u8_array::<12, 4, 8>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
// Compile-time SLICE-EQUALS-ARRAY singleton witnesses — the two
// remaining unpinned-at-rustc-time slots on
// `crate::error::SexpShape::HASH_DISCRIMINATORS` (`[u8; 12]`). Both
// are covered by the LARGER sub-carving arrays' `[u8; 1]` slice
// projections against the container's singleton slice.
//
// * Position `[0..1)` — `SexpShape::HASH_DISCRIMINATORS[0] ==
// StructuralKind::HASH_DISCRIMINATORS[0] ==
// StructuralKind::NIL_HASH_DISCRIMINATOR == 0u8`. The outer
// container's slot-0 initializer spells `Self::NIL_HASH_
// DISCRIMINATOR` which is declared as an alias for
// `StructuralKind::NIL_HASH_DISCRIMINATOR` (see
// `SexpShape::NIL_HASH_DISCRIMINATOR = StructuralKind::NIL_HASH_
// DISCRIMINATOR` in `error.rs`). Comparing against the singleton
// `[StructuralKind::NIL_HASH_DISCRIMINATOR]` sub-array binds the
// container's SLOT-0 POSITION to the structural-residual
// carving's NIL role at rustc-time.
// * Position `[7..8)` — the mirror slot at the atomic-collapse
// right endpoint, spelling `Self::LIST_HASH_DISCRIMINATOR` which
// aliases `StructuralKind::LIST_HASH_DISCRIMINATOR = 2u8`.
//
// Pre-lift these two per-position bindings were pinned ONLY at
// runtime through the twelve-position sweep inside
// `sexp_shape_hash_discriminators_align_with_sub_carvings_by_projection`
// (routing each `SexpShape::HASH_DISCRIMINATORS[i]` through the
// shape's sub-carving projection `as_structural_kind().unwrap().
// hash_discriminator()` on the two structural-residual arms);
// post-lift the ARRAY-LEVEL slice-equals-array contract binds at
// rustc-time via TWO `const _` lines, one invocation stage earlier
// than the runtime pin. The peer joint witness
// `assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4,
// 0, 6>(AtomKind::OUTER_HASH_DISCRIMINATOR,
// &StructuralKind::HASH_DISCRIMINATORS,
// &QuoteForm::HASH_DISCRIMINATORS)` above is STRICTLY WEAKER on
// these two slots — it binds the SUB-CARVING array
// `StructuralKind::HASH_DISCRIMINATORS = [0, 2]` per-position order
// but is SILENT on which SLOTS of the outer CONTAINER `SexpShape::
// HASH_DISCRIMINATORS` the sub-carving's two bytes land at (a
// regression that swapped `Self::NIL_HASH_DISCRIMINATOR` and
// `Self::LIST_HASH_DISCRIMINATOR` in the outer array initializer
// so slot 0 becomes `2u8` and slot 7 becomes `0u8` would preserve
// the sub-carving array's `[0, 2]` order the joint witness pins
// AND the outer array's global `{0..=6}` set-image the joint
// witness pins, but would silently corrupt the outer container's
// per-position slot-to-carving-role mapping the two new witnesses
// below reject).
//
// Sibling posture to the four-slot QUOTE-family tail
// `assert_u8_array_slice_equals_u8_array::<12, 4, 8>(&SexpShape::
// HASH_DISCRIMINATORS, &QuoteForm::HASH_DISCRIMINATORS)` witness
// IMMEDIATELY ABOVE — that witness carries the sub-carving
// projection at the LARGEST arity (4 positions in a single
// `const _` line); these two witnesses carry the sub-carving
// projection at the SMALLEST arity (1 position each, at the two
// disjoint singleton slots the structural-residual carving
// occupies on the outer container). Together the three SLICE-
// EQUALS-ARRAY witnesses cover the ENTIRE SexpShape ⊃
// {StructuralKind, QuoteForm} sub-carving composition at rustc-
// time — `SexpShape::HASH_DISCRIMINATORS[0..1] ∪ [7..8) ∪ [8..12)`
// exhausts the eight non-atomic slots on the outer container, so
// combined with the sibling `SLICE-BLOCK-CONSTANCY` witness on
// `[1..7)` the twelve-slot outer array is FULLY pinned per-
// position at rustc-time.
//
// The two witnesses use INLINE `[u8; 1]` singleton arrays rather
// than `&StructuralKind::HASH_DISCRIMINATORS[0..1]` slice syntax
// because the helper's signature takes `&[u8; M]` (a const-generic
// array reference, arity-known at rustc time) rather than `&[u8]`
// (a slice type with runtime-length). The inline arrays project
// the two per-role `pub(crate) const` bytes directly — a
// regression that renamed one of the two aliases fails at the
// alias's declaration site FIRST (a missing symbol referent),
// which routes to a distinct diagnostic axis rather than to the
// witness's SLICE-EQUALS-ARRAY-VIOLATION panic.
const _: () = assert_u8_array_slice_equals_u8_array::<12, 1, 0>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
&[crate::error::StructuralKind::NIL_HASH_DISCRIMINATOR],
);
const _: () = assert_u8_array_slice_equals_u8_array::<12, 1, 7>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
&[crate::error::StructuralKind::LIST_HASH_DISCRIMINATOR],
);
// `Sexp` is `PartialEq` but not `Eq` (Float contains NaN). We implement Hash
// manually so cache keys can hash a borrowed `&[Sexp]` directly — avoids the
// serde_json serialization that would otherwise dominate cache overhead on
// cheap macro calls.
//
// The outer per-variant discriminator byte (`0` for Nil, `1` for Atom, `2`
// for List, `3..=6` for the four quote-family variants) binds at ONE site
// on the outer-`Sexp` algebra (`Sexp::hash_discriminator`) rather than at
// four per-arm byte projections here. The seven outer-variant arms
// partition `{0..=6}` injectively; the outer-`Sexp` method routes through
// the intermediate shape-level projection `SexpShape::hash_discriminator`
// (the 12 outer shapes → 7 outer bytes; the six atomic-shape arms
// collapse to the outer Atom marker byte `1`, symmetric with `Sexp::Atom(_)
// → 1u8` on the outer method), which in turn composes through the three
// sub-carvings' typed discriminator methods:
// * `StructuralKind::hash_discriminator` for the two-arm structural-
// residual partition `{0, 2}` (Nil, List);
// * `AtomKind::hash_discriminator` for the nested atomic payload
// `{0..=5}` inside the Atom outer byte `1` (surfaced INSIDE
// `Hash for Atom`, NOT through this outer method OR the shape-level
// method);
// * `QuoteForm::hash_discriminator` for the quote-family arms `{3..=6}`.
// The outer-`Sexp` cache-key algebra now closes at FIVE typed layers
// (outer `Sexp` → `SexpShape` → three sub-carvings). A future eighth
// `Sexp` variant (e.g. `Vector` / `Map` / `Char`) picks a fresh cache-key
// byte outside `{0..=6}` and lands at ONE new arm on
// `Sexp::hash_discriminator` (or, one algebra level up, at ONE new arm on
// `SexpShape::hash_discriminator` — extending either `StructuralKind` if
// it is structural-residual or a fresh sub-algebra), with rustc binding
// the consistency through exhaustiveness over each closed enum.
//
// The per-arm body below only handles the inner-payload hash sequence
// after the outer discriminator byte is routed through
// `self.hash_discriminator().hash(h)` — the recursive `inner.hash(h)` on
// the quote-family arm is asserted-total via `expect_quote_form` (the
// outer pattern guarantees the projection lands `Some`).
impl Hash for Sexp {
fn hash<H: Hasher>(&self, h: &mut H) {
self.hash_discriminator().hash(h);
match self {
Self::Nil => {}
Self::Atom(a) => a.hash(h),
Self::List(items) => {
items.len().hash(h);
for i in items {
i.hash(h);
}
}
Self::Quote(_) | Self::Quasiquote(_) | Self::Unquote(_) | Self::UnquoteSplice(_) => {
let (_, inner) = self.expect_quote_form();
inner.hash(h);
}
}
}
}
// The six atomic variants share the (discriminator, inner) hash shape —
// the per-variant discriminator byte binds at ONE site on the outer-`Atom`
// algebra (`Atom::hash_discriminator`) rather than at six inline
// `<N>u8.hash(h)` arms here. The outer-value method composes through the
// pre-existing marker-level projection `AtomKind::hash_discriminator` (via
// `self.kind().hash_discriminator()`) so the (Atom variant, byte) pairing
// lives at ONE canonical site on the closed-set `AtomKind` algebra rather
// than at TWO (both a parallel six-arm match here AND `AtomKind::hash_
// discriminator`'s canonical site). The inner-payload arm stays a match
// because the payload type differs per variant (`String` for symbol /
// keyword / str, `i64` for int, `f64::to_bits()` for float, `bool` for
// bool); the or-pattern collapses the three string-carrying arms. Float:
// hash the bit pattern. NaN != NaN so PartialEq is broken, but cache
// lookups use PartialEq-by-hash which this satisfies modulo a NaN
// collision risk we accept for template args. The (Atom variant, byte)
// pairing is pinned bit-for-bit by `atom_kind_hash_discriminator_pins_
// legacy_atom_cache_key_bytes` against the pre-lift 0/1/2/3/4/5 sequence
// — same posture as `quote_form_hash_discriminator_pins_legacy_cache_
// key_bytes` for the four-of-thirteen `Sexp` wrapper variants. Post-lift
// the outer-`Atom` `Hash` body is structurally parallel to `Hash for
// Sexp` one algebra layer up — both spell `self.hash_discriminator().hash
// (h); <inner-payload-hash>` at the outer-value carrier, with the byte
// binding routed through the outer-value-level projection at each
// algebra. Routing identity pinned by
// `hash_for_atom_routes_atom_discriminator_through_atom_hash_discriminator`
// on the outer-`Atom` algebra, sibling of
// `hash_for_sexp_routes_outer_discriminator_through_sexp_hash_discriminator`
// on the outer-`Sexp` algebra.
impl Hash for Atom {
fn hash<H: Hasher>(&self, h: &mut H) {
self.hash_discriminator().hash(h);
match self {
Self::Symbol(s) | Self::Keyword(s) | Self::Str(s) => s.hash(h),
Self::Int(n) => n.hash(h),
Self::Float(f) => f.to_bits().hash(h),
Self::Bool(b) => b.hash(h),
}
}
}
/// An S-expression — the homoiconic value + program representation.
/// Lowercase hex for a codepoint, without pulling in a formatter — the escaper
/// is on the Display path and must not recurse into it.
fn alloc_hex(mut n: u32) -> String {
if n == 0 {
return "0".to_string();
}
const DIGITS: &[u8; 16] = b"0123456789abcdef";
let mut buf = Vec::with_capacity(6);
while n > 0 {
buf.push(DIGITS[(n % 16) as usize]);
n /= 16;
}
buf.reverse();
String::from_utf8(buf).expect("hex digits are ascii")
}
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Sexp {
Nil,
Atom(Atom),
List(Vec<Sexp>),
/// `'x` — literal; does not participate in macro substitution.
Quote(Box<Sexp>),
/// `` `x `` — quasi-quotation; substitution happens inside.
Quasiquote(Box<Sexp>),
/// `,x` — substitute the binding named `x`. Only valid inside a quasi-quote.
Unquote(Box<Sexp>),
/// `,@x` — splice the list `x` into the containing list.
UnquoteSplice(Box<Sexp>),
}
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Atom {
/// Plain symbol (`foo`, `defpoint`, `seph.1`).
Symbol(String),
/// Keyword (`:parent`, `:attr`) — a symbol bound to itself.
Keyword(String),
/// String literal.
Str(String),
/// Integer literal.
Int(i64),
/// Floating literal.
Float(f64),
/// Boolean literal (`#t`, `#f`).
Bool(bool),
}
impl Atom {
/// The canonical `:` marker prefix that a [`Self::Keyword`] payload
/// projects THROUGH when rendered as / classified from its
/// canonical-string surface across the substrate's four
/// Keyword-round-trip sites — the reader-entry classifier
/// ([`Self::from_lexeme`]), the Lisp-canonical-form projection
/// ([`fmt::Display for Atom`]), the JSON-canonical-form projection
/// ([`Self::to_json`]), and the iac-forge-canonical-form projection
/// (`Atom::to_iac_forge_sexpr` (removed)).
///
/// Pre-lift the same `":"` byte lived inline at four sites: `':'`
/// (as a `char` pattern) at the [`Self::from_lexeme`] strip site
/// and `":{s}"` (three byte-identical format-string literals) at the
/// three canonical-form projection sites. Post-lift the marker
/// byte lives at ONE canonical constant on the [`Atom`] algebra
/// that all four sites bind to; a future refactor that swaps the
/// marker (e.g. a Racket-compat port to `#:name`, a Clojure-compat
/// port to `::name`) touches ONE line rather than four inline
/// bytes that would silently drift out of round-trip agreement if
/// one was updated without the others.
///
/// Load-bearing round-trip contract:
/// `Self::from_lexeme(&Self::keyword(name).to_string()) ==
/// Self::keyword(name)` — the reader-entry classifier's
/// `strip_prefix(Self::KEYWORD_MARKER)` gate and the Lisp-canonical
/// [`Display`]'s `write!(f, "{}{name}", Self::KEYWORD_MARKER)`
/// emission both bind to THIS constant so the pair cannot drift.
/// Cross-surface round-trip: `Self::to_json` and
/// `Atom::to_iac_forge_sexpr` (removed) emit the same prefix so any BLAKE3
/// attestation over an iac-forge canonical form of a Keyword atom
/// matches the JSON canonical form byte-for-byte on the prefix
/// axis.
///
/// Sibling-shape lift to the workspace's other prefix-marker
/// constants: [`crate::error::UnquoteForm::ALL`] projects each
/// template-marker variant to its punctuation prefix via
/// [`crate::ast::QuoteForm::prefix`] (`"'"`, `"`"`, `","`, `",@"`)
/// — a peer axis on the substrate's marker-byte algebra. This
/// constant sits on the [`Atom`] algebra at the atomic-payload
/// axis where the [`QuoteForm::prefix`] projection sits at the
/// homoiconic-wrapper axis.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Keyword payload, canonical `:` prefix) pairing now binds at
/// ONE constant on the closed-set [`Atom`] algebra regardless of
/// which of the four reader-entry / rendering surfaces reaches in.
/// THEORY.md §VI.1 — generation over composition; the four
/// byte-identical `":"` / `":{s}"` inline literals collapse onto
/// ONE named constant, matching the substrate's three-times rule
/// (four occurrences, well past the ≥2 lift threshold).
/// THEORY.md §V.1 — knowable platform; the canonical
/// keyword-marker byte becomes a TYPE-level constant on the
/// substrate algebra rather than four inline bytes at four
/// consumer surfaces.
pub const KEYWORD_MARKER: &'static str = ":";
/// Canonical `:` LEAD `char` of the [`Self::KEYWORD_MARKER`] prefix
/// (`":"`) — the ONE canonical `char` on the [`Atom`] algebra the
/// substrate's Keyword-prefix lead-byte disjointness contract binds
/// to.
///
/// Sibling posture to the closed set of `pub const` reader-punctuation
/// canonical `char` bytes on the substrate: [`Self::STR_DELIMITER`]
/// (`'"'`), [`Self::STR_ESCAPE_LEAD`] (`'\\'`),
/// [`Self::BOOL_LITERAL_LEAD`] (`'#'`), [`Sexp::LIST_OPEN`] (`'('`),
/// [`Sexp::LIST_CLOSE`] (`')'`), [`Sexp::COMMENT_LEAD`] (`';'`),
/// [`Sexp::COMMENT_TERM`] (`'\n'`), [`QuoteForm::SPLICE_DISCRIMINATOR`]
/// (`'@'`) — every canonical per-role byte the reader's tokenizer
/// specialises on is a `pub const` on its owning closed-set algebra.
/// This constant closes the Keyword-prefix lead byte at the SAME
/// algebra as its one-char [`Self::KEYWORD_MARKER`] `&'static str`
/// projection — the ONE `char` that the `&'static str` projects to
/// when the substrate's consumer needs a `char` (not a `&str`) for
/// cross-axis marker-byte comparisons or for the reader's
/// specific-arm outer-dispatch.
///
/// Structural round-trip contract:
/// `Self::KEYWORD_MARKER.starts_with(Self::KEYWORD_MARKER_LEAD)` —
/// pinned by
/// `atom_keyword_marker_lead_prefixes_keyword_marker`. A regression
/// that drifts EITHER the constant OR the [`Self::KEYWORD_MARKER`]
/// spelling surfaces at the pin rather than at a silent Keyword-
/// prefix reader drift where `:foo` classifies as [`Self::Symbol`]
/// instead of [`Self::Keyword`]. Sibling-shape peer of
/// [`Self::BOOL_LITERAL_LEAD`]'s
/// `Self::bool_literal(b).starts_with(Self::BOOL_LITERAL_LEAD)`
/// round-trip law: where that pin binds the Bool-family two spellings
/// to their shared lead byte, this pin binds the Keyword-marker
/// one-char prefix to its projected lead byte.
///
/// Disjointness contract: `KEYWORD_MARKER_LEAD`'s byte MUST differ
/// from [`Self::STR_DELIMITER`] (`'"'`), [`Self::STR_ESCAPE_LEAD`]
/// (`'\\'`), [`Self::BOOL_LITERAL_LEAD`] (`'#'`),
/// [`Sexp::LIST_OPEN`] (`'('`), [`Sexp::LIST_CLOSE`] (`')'`),
/// [`Sexp::COMMENT_LEAD`] (`';'`), [`Sexp::COMMENT_TERM`]
/// (`'\n'`), every [`QuoteForm::lead_char`] projection AND
/// [`QuoteForm::SPLICE_DISCRIMINATOR`] (`'@'`) — every other
/// closed-set outer-marker byte the reader's tokenizer specialises
/// on. A collision would silently break the reader's outer
/// dispatch: a `:`-prefixed bare atom `:foo` would collide with
/// whichever marker it aliased. Pinned by
/// `atom_keyword_marker_lead_distinct_from_every_other_algebra_marker`.
///
/// Consumer sites this constant closes: SEVEN test-surface sites
/// that pre-lift each extracted the lead byte via
/// `Atom::KEYWORD_MARKER.chars().next().expect(_)` (or `.unwrap()`) —
/// the Keyword arm of the [`Sexp::is_bare_atom_boundary`] negative
/// sweep AND the six cross-axis disjointness pins on the sibling
/// marker-byte algebras
/// ([`QuoteForm::SPLICE_DISCRIMINATOR`], [`Self::BOOL_LITERAL_LEAD`],
/// [`Self::STR_DELIMITER`], [`Self::STR_ESCAPE_LEAD`],
/// [`Sexp::LIST_OPEN`] / [`Sexp::LIST_CLOSE`],
/// [`Sexp::COMMENT_LEAD`], [`Sexp::COMMENT_TERM`]) — collapse onto
/// ONE named byte on the substrate algebra.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Keyword-prefix lead byte, canonical `':'`) pairing binds at ONE
/// constant on the closed-set outer [`Atom`] algebra regardless of
/// which reader-surface consumer reaches in. THEORY.md §II.1
/// invariant 5 — composition preserves proofs; the
/// `Self::KEYWORD_MARKER.starts_with(Self::KEYWORD_MARKER_LEAD)`
/// round-trip law is a coherence proof BETWEEN the paired projection
/// ([`Self::KEYWORD_MARKER`]) AND its projected lead byte (this
/// constant) on ONE algebra — a regression that drifts either side
/// surfaces at the pin rather than as a silent Keyword-prefix reader
/// drift. THEORY.md §V.1 — knowable platform; the canonical
/// Keyword-prefix lead byte becomes a TYPE-level constant on the
/// substrate algebra rather than an inline
/// `.chars().next().expect(_)` extraction at every test surface AND
/// an inline `':'` mention across every docstring pinning the
/// disjointness contract.
///
/// Frontier inspiration: Racket's `read-syntax` colon-prefix reader
/// hook (`#:name` for keyword args, `::name` for module-scoped bindings
/// in some dialects) — where the `:` prefix dispatches keyword-family
/// reader-macros keyed on ONE typed lead byte on the port's reader
/// table. Translated to tatara-lisp: `Atom::KEYWORD_MARKER_LEAD`
/// becomes the ONE typed lead byte on the closed-set outer [`Atom`]
/// algebra that a future keyword-family peer method (e.g. a
/// Clojure-compat port to `::foo` namespaced keywords) can extend
/// through — the paired-prefix discipline that Racket's read-syntax
/// table carries lands here as a `pub const` on the algebra rather
/// than as an inline char literal at every consumer site.
pub const KEYWORD_MARKER_LEAD: char = ':';
/// Project a bare keyword `name` to its canonical qualified rendering
/// — `format!("{}{name}", Self::KEYWORD_MARKER)`, i.e. the ONE
/// canonical [`String`] on the [`Atom`] algebra that composes
/// [`Self::KEYWORD_MARKER`] with a bare keyword name to produce the
/// substrate-canonical `":name"` spelling.
///
/// Sibling projection to [`Self::bool_literal`] on the atomic-payload
/// canonical-rendering axis: where `bool_literal(b)` projects the
/// closed-set `bool` domain to its canonical Scheme spelling
/// `"#t"` / `"#f"` (`&'static str` because the set is finite), THIS
/// method projects the open-set bare-name domain to its canonical
/// qualified spelling `":name"` ([`String`] because the set is
/// unbounded). The [`Atom`] algebra's atomic-payload canonical-
/// rendering axis now carries a typed projection for BOTH the
/// prefix-marked variable-payload variant (Keyword) and the self-
/// marked closed-set-payload variant (Bool).
///
/// Pre-lift the same `format!("{}{s}", Self::KEYWORD_MARKER)`
/// composition lived inline at THREE Keyword-arm sites on the
/// atomic-payload rendering axis:
///
/// 1. [`Self::to_json`]'s [`Self::Keyword`] arm —
/// `serde_json::Value::String(format!(...))` for the JSON-
/// canonical projection.
/// 2. `Atom::to_iac_forge_sexpr` (removed)'s [`Self::Keyword`] arm —
/// `SExpr::Symbol(format!(...))` for the iac-forge canonical-
/// attestation projection.
/// 3. [`fmt::Display for Atom`]'s [`Self::Keyword`] arm —
/// `write!(f, "{}{s}", Self::KEYWORD_MARKER)` for the Lisp-
/// canonical-form Display projection.
///
/// Post-lift the two allocating sites (1) + (2) bind at ONE typed
/// projection on the algebra; the [`fmt::Display for Atom`] site
/// (3) keeps its allocation-free `write!` path but its byte output
/// is pinned bit-identical to this projection by
/// `atom_display_keyword_arm_agrees_with_keyword_qualified_bytes`
/// so the three canonical-rendering surfaces cannot drift out of
/// agreement. Adding a fourth Keyword-rendering site (e.g. a future
/// YAML canonical projection, an LSP hover renderer) binds through
/// THIS projection rather than composing [`Self::KEYWORD_MARKER`]
/// inline — the (Keyword payload, canonical qualified rendering)
/// pairing lives at ONE algebra layer.
///
/// Round-trip contract (with [`Self::from_lexeme`]):
/// `Self::from_lexeme(&Self::keyword_qualified(name)) ==
/// Self::Keyword(name.to_owned())` for every `name: &str` that
/// does NOT itself parse as a Bool spelling, integer, or float
/// (the four typed-entry classification arms preceding the
/// [`Self::KEYWORD_MARKER`]-prefix arm). The classifier's
/// `s.strip_prefix(Self::KEYWORD_MARKER)` gate is the LEFT-inverse
/// of THIS projection on the Keyword-payload subset — pinned by
/// `atom_from_lexeme_inverts_keyword_qualified_on_bare_name`.
/// Composition preserves proofs across the (typed-EXIT rendering,
/// typed-ENTRY classification) round-trip at ONE algebra site.
///
/// Sibling posture to [`QuoteForm::prefix`]'s composition with
/// homoiconic inner forms in [`fmt::Display for Sexp`]'s quote-
/// family arm: where `QuoteForm::prefix` is the [`&'static str`]
/// prefix a quote-family variant composes with an inner rendering
/// via `write!(f, "{}{inner}", qf.prefix())`, THIS method is the
/// composed [`String`] a Keyword atom composes with a bare name.
/// Both projections close a (marker, payload) pair on their owning
/// closed-set algebra.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Keyword payload, canonical qualified rendering) pairing binds
/// at ONE projection on the closed-set [`Atom`] algebra regardless
/// of which of the three canonical-rendering surfaces reaches in.
/// THEORY.md §II.1 invariant 5 — composition preserves proofs; the
/// round-trip law
/// `Self::from_lexeme(&Self::keyword_qualified(n)) ==
/// Self::Keyword(n.into())` is a coherence proof BETWEEN the
/// paired typed-EXIT rendering (this method) AND the typed-ENTRY
/// classification ([`Self::from_lexeme`]) on ONE algebra — a
/// regression that drifts either side surfaces at the pin rather
/// than as a silent Keyword-round-trip drift. THEORY.md §V.1 —
/// knowable platform; the (Keyword payload → canonical qualified
/// rendering) composition becomes a TYPE-level projection on the
/// substrate algebra rather than an inline
/// `format!("{}{s}", Self::KEYWORD_MARKER)` at every consumer
/// site. THEORY.md §VI.1 — generation over composition; three
/// byte-identical inline compositions collapse onto ONE named
/// projection (two routed sites + one Display byte-identity pin),
/// matching the substrate's three-times rule.
///
/// Frontier inspiration: Racket's `syntax/parse` keyword-form
/// canonical-rendering hook — where `#:name` keyword args have
/// ONE canonical printer that composes the port's `KEYWORD_PREFIX`
/// with the bare name rather than N per-consumer `printf`
/// compositions. Translated to tatara-lisp:
/// `Atom::keyword_qualified` becomes the ONE canonical-rendering
/// projection on the closed-set outer [`Atom`] algebra so a
/// future prefix migration (a Racket-compat port to `#:name`, a
/// Clojure-compat port to `::name`) touches ONE
/// [`Self::KEYWORD_MARKER`] constant + zero rendering sites,
/// rather than the pre-lift three inline `format!` compositions
/// that would silently drift.
#[must_use]
pub fn keyword_qualified(name: &str) -> String {
let mut out = String::with_capacity(Self::KEYWORD_MARKER.len() + name.len());
out.push_str(Self::KEYWORD_MARKER);
out.push_str(name);
out
}
/// Project the closed-set `bool` domain to its canonical Scheme-
/// spelling `&'static str` — `"#t"` for `true`, `"#f"` for `false`.
/// ONE projection on the [`Atom`] algebra that the substrate's
/// FOUR `Self::Bool`-round-trip inline byte-literals across TWO
/// consumer sites (the two-arm `Bool(true|false)` fork inside
/// [`fmt::Display for Atom`] and the two-line `if s == "#t"` /
/// `if s == "#f"` cascade inside [`Self::from_lexeme`]) collapse
/// onto — parallel to how [`Self::KEYWORD_MARKER`] is the ONE
/// canonical prefix the four Keyword-round-trip sites bind to.
///
/// Pre-lift the same `"#t"` / `"#f"` bytes lived inline at four
/// sites: two `f.write_str("#t"|"#f")` arms at the Display impl and
/// two `if s == "#t"|"#f"` gates at [`Self::from_lexeme`]. Post-
/// lift the (typed `bool`, canonical Scheme spelling) pairing binds
/// at ONE projection on the [`Atom`] algebra that every consumer
/// routes through; a refactor that swaps the spelling (e.g. a
/// Common-Lisp-compat port to `T` / `NIL`, a JSON-compat port to
/// `true` / `false`) touches ONE method rather than four inline
/// bytes that would silently drift out of round-trip agreement if
/// one was updated without the others. The Display arm also
/// collapses from TWO variant-branches (`Bool(true) => "#t"`,
/// `Bool(false) => "#f"`) to ONE variant-branch
/// (`Bool(b) => Self::bool_literal(*b)`) — the fork on `bool`
/// happens at the projection, not at every consumer's match body.
///
/// Load-bearing round-trip contract:
/// `Self::from_lexeme(&Self::boolean(b).to_string()) ==
/// Self::boolean(b)` for every `b: bool` — the reader-entry
/// classifier's `s == Self::bool_literal(true|false)` gates and the
/// Lisp-canonical [`Display`]'s
/// `f.write_str(Self::bool_literal(*b))` emission both bind to THIS
/// projection so the pair cannot drift. Guards against the
/// CLAUDE.md pin ("bare `true`/`false` are symbols → strings, not
/// bools") — the closed-set `bool` domain projects only through
/// this typed method, so a reader extension that later accepts
/// bare `true`/`false` extends the projection (or its reverse) at
/// ONE algebra site rather than at every callsite in lockstep.
///
/// Sibling-shape peer of [`Self::KEYWORD_MARKER`]: where
/// `KEYWORD_MARKER` is the ONE `&'static str` prefix a Keyword
/// payload composes with at four round-trip sites, this method is
/// the ONE projection a Bool payload composes THROUGH at its two
/// round-trip sites. The [`Atom`] algebra's atomic-payload axis
/// now carries a canonical-marker/spelling for BOTH prefix-marked
/// (Keyword) and self-marked (Bool) variants.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Bool payload, canonical Scheme spelling) pairing now binds at
/// ONE projection on the closed-set [`Atom`] algebra regardless of
/// which of the two reader-entry / rendering surfaces reaches in.
/// THEORY.md §VI.1 — generation over composition; the four byte-
/// identical `"#t"` / `"#f"` inline literals collapse onto ONE
/// named projection, matching the substrate's three-times rule.
/// THEORY.md §V.1 — knowable platform; the canonical Scheme-bool
/// spellings become a TYPE-level projection on the substrate
/// algebra rather than four inline bytes at two consumer surfaces.
#[must_use]
pub fn bool_literal(b: bool) -> &'static str {
if b {
Self::TRUE_LITERAL
} else {
Self::FALSE_LITERAL
}
}
/// Canonical `&'static str` Scheme-bool spelling for the `true`
/// element of the closed `bool` domain — the `"#t"` bytes
/// [`Self::bool_literal`] projects `true` to, AND the
/// [`Self::from_lexeme`] reader classifier gates on. Sibling
/// posture to [`Self::FALSE_LITERAL`] (`"#f"`) on the same
/// bool-spelling algebra layer.
///
/// Pre-lift the same `"#t"` bytes lived inline at [`Self::bool_literal`]'s
/// `true`-arm plus at five test-surface sites that pin the
/// canonical spelling — the ≥2 PRIME-DIRECTIVE trigger. Post-lift
/// the (`true`, canonical Scheme spelling) pairing binds at ONE
/// `pub const` on the closed-set [`Atom`] algebra: the
/// [`Self::bool_literal`] `true`-arm AND every consumer that pins
/// the exact bytes route through this constant, so a spelling
/// migration (e.g. a Common-Lisp-compat port to `"T"`, a JSON-compat
/// port to `"true"`, a Racket-compat port to `"#true"`) is ONE
/// edit HERE with the [`Self::bool_literal`] projection AND every
/// downstream reader/Display consumer mechanically picking it up.
///
/// Sibling posture to the closed set of per-role canonical
/// `pub const` bytes on the substrate's other closed-set outer
/// algebras: [`Self::STR_DELIMITER`] (`'"'`),
/// [`Self::KEYWORD_MARKER`] (`":"`),
/// [`Sexp::LIST_OPEN`] (`'('`),
/// [`crate::error::MacroDefHead::DEFMACRO_KEYWORD`] (`"defmacro"`),
/// [`crate::macro_expand::MacroParams::REST_MARKER`] (`"&rest"`),
/// [`crate::macro_expand::MacroParams::OPTIONAL_MARKER`] (`"&optional"`).
///
/// Structural round-trip contract (composed with the algebra's
/// [`Self::BOOL_LITERAL_LEAD`] axis peer):
/// `Self::TRUE_LITERAL.starts_with(Self::BOOL_LITERAL_LEAD)` — the
/// lead-byte-prefixes-spelling law from
/// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`
/// specialises byte-for-byte to this constant, pinning the
/// (`BOOL_LITERAL_LEAD`, `TRUE_LITERAL`) pairing on ONE typed
/// algebra.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (`true`, canonical Scheme spelling) pairing binds at ONE
/// `pub const` on the closed-set outer [`Atom`] algebra regardless
/// of which of the reader/Display surface consumers reaches in.
/// THEORY.md §VI.1 — generation over composition; the multi-site
/// inline `"#t"` literal collapses onto ONE named `pub const`,
/// matching the substrate's three-times rule. THEORY.md §V.1 —
/// knowable platform; the canonical `true`-spelling becomes a
/// TYPE-level constant on the substrate algebra rather than an
/// inline byte literal at every consumer surface.
pub const TRUE_LITERAL: &'static str = "#t";
/// Canonical `&'static str` Scheme-bool spelling for the `false`
/// element of the closed `bool` domain — the `"#f"` bytes
/// [`Self::bool_literal`] projects `false` to, AND the
/// [`Self::from_lexeme`] reader classifier gates on. Sibling
/// posture to [`Self::TRUE_LITERAL`] (`"#t"`) on the same
/// bool-spelling algebra layer.
///
/// Pre-lift the same `"#f"` bytes lived inline at [`Self::bool_literal`]'s
/// `false`-arm plus at five test-surface sites that pin the
/// canonical spelling — the ≥2 PRIME-DIRECTIVE trigger. Post-lift
/// the (`false`, canonical Scheme spelling) pairing binds at ONE
/// `pub const` on the closed-set [`Atom`] algebra: the
/// [`Self::bool_literal`] `false`-arm AND every consumer that pins
/// the exact bytes route through this constant.
///
/// Structural round-trip contract (composed with the algebra's
/// [`Self::BOOL_LITERAL_LEAD`] axis peer):
/// `Self::FALSE_LITERAL.starts_with(Self::BOOL_LITERAL_LEAD)`.
pub const FALSE_LITERAL: &'static str = "#f";
/// The closed set of two canonical `&'static str` Scheme-bool
/// spellings — the [`Self::TRUE_LITERAL`] (`"#t"`) canonical `true`
/// spelling followed by the [`Self::FALSE_LITERAL`] (`"#f"`)
/// canonical `false` spelling. Canonical declaration order matches
/// the `[true, false]` sweep order every existing sibling test in
/// the crate uses (see e.g. the `for b in [true, false]` sweeps at
/// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`)
/// so `Self::BOOL_LITERALS[i] == Self::bool_literal([true, false][i])`
/// element-wise — pinned by
/// `atom_bool_literals_align_with_bool_literal_by_index`.
///
/// Sibling posture to
/// [`crate::error::MacroDefHead::KEYWORDS`] (`[&'static str; 3]`),
/// [`crate::macro_expand::MacroParams::LAMBDA_LIST_KEYWORDS`]
/// (`[&'static str; 2]`) — every closed-set spelling algebra now
/// pins its projection ALL array at the declaration site via a
/// forced-arity `[&'static str; N]` array whose length fails
/// compilation if a new spelling lands without being added to the
/// set. The closed `bool` domain admits exactly two spellings by
/// construction (a hypothetical third would require extending the
/// underlying `bool` type itself), so this array's `N == 2` is
/// pinned by the mathematics — the forced-arity `[_; 2]` here
/// records that invariant on the substrate algebra so a future
/// tri-valued-logic extension surfaces at the array-arity check
/// rather than as a silent drift.
///
/// Future consumers that compose against [`Self::BOOL_LITERALS`]:
/// an LSP / REPL completion provider surfacing every `#…` partial
/// input against the closed set (`Self::BOOL_LITERALS.iter()` is
/// the ONE typed sweep over every legal bool spelling), a
/// `tatara-check` coverage assertion (every workspace `.lisp` file's
/// bare-`#`-prefixed lexeme must classify to some entry of
/// `Self::BOOL_LITERALS` OR be routed through the broader
/// hash-prefix reader-macro family), any future audit-trail metric
/// jointly labeled by the canonical Scheme spelling (e.g.
/// `tatara_lisp_bool_lexeme_total{literal="#t"}`) — the metric
/// label set IS [`Self::BOOL_LITERALS`].
pub const BOOL_LITERALS: [&'static str; 2] = [Self::TRUE_LITERAL, Self::FALSE_LITERAL];
/// Canonical `#` LEAD byte shared across both [`Self::bool_literal`]
/// spellings (`"#t"` for [`true`], `"#f"` for [`false`]) — the ONE
/// canonical `char` on the [`Atom`] algebra the substrate's Bool-
/// prefix disjointness contract binds to.
///
/// Sibling posture to the closed set of `pub const` reader-punctuation
/// canonical bytes on the substrate: [`Self::STR_DELIMITER`] (`'"'`),
/// [`Self::STR_ESCAPE_LEAD`] (`'\\'`), [`Sexp::LIST_OPEN`] (`'('`),
/// [`Sexp::LIST_CLOSE`] (`')'`), [`Sexp::COMMENT_LEAD`] (`';'`),
/// [`Sexp::COMMENT_TERM`] (`'\n'`), [`QuoteForm::SPLICE_DISCRIMINATOR`]
/// (`'@'`) — every canonical per-role byte the reader's tokenizer
/// specialises on is now a `pub const` on its owning closed-set
/// algebra. This constant closes the Bool-family lead byte at the
/// SAME algebra as its two-char [`Self::bool_literal`] projections
/// so a delimiter swap (e.g. a Common-Lisp-compat port from
/// Scheme `#t`/`#f` to CL `T`/`NIL`, a JSON-compat port to
/// `true`/`false`, or an extension for the broader Scheme
/// hash-prefix reader-macro family `#\char` / `#(vector)` /
/// `#|block-comment|#` / `#;datum-comment`) lands at ONE constant
/// on the algebra rather than at inline `'#'` char literals
/// scattered across the test surface AND the docstrings pinning
/// the disjointness contract.
///
/// Structural round-trip contract:
/// `Self::bool_literal(b).starts_with(Self::BOOL_LITERAL_LEAD)`
/// for every `b: bool` — pinned by
/// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`.
/// A regression that drifts EITHER the constant OR the two
/// [`Self::bool_literal`] arms surfaces at the pin rather than at
/// a silent bool-family reader drift where `#t` / `#f` classify as
/// [`Self::Symbol`] instead of [`Self::Bool`].
///
/// Disjointness contract: `BOOL_LITERAL_LEAD`'s byte MUST differ
/// from [`Self::STR_DELIMITER`] (`'"'`), [`Self::STR_ESCAPE_LEAD`]
/// (`'\\'`), [`Self::KEYWORD_MARKER`]'s lead byte (`':'`),
/// [`Sexp::LIST_OPEN`] (`'('`), [`Sexp::LIST_CLOSE`] (`')'`),
/// [`Sexp::COMMENT_LEAD`] (`';'`), [`Sexp::COMMENT_TERM`]
/// (`'\n'`), every [`QuoteForm::lead_char`] projection AND
/// [`QuoteForm::SPLICE_DISCRIMINATOR`] (`'@'`) — every other
/// closed-set outer-marker byte the reader's tokenizer specialises
/// on. A collision would silently break the reader's outer
/// dispatch: a `#`-prefixed bare atom `#t` would collide with
/// whichever marker it aliased. Pinned by
/// `atom_bool_literal_lead_distinct_from_every_other_algebra_marker`.
///
/// Consumer sites this constant closes: the three test-surface
/// sites that pre-lift each extracted the lead byte via
/// `Self::bool_literal(b).chars().next().unwrap()` (or `.expect(_)`)
/// — the `Bool`-arm of [`Sexp::is_bare_atom_boundary`]'s negative
/// sweep AND the two [`QuoteForm::SPLICE_DISCRIMINATOR`]
/// disjointness assertions — collapse onto ONE named byte on the
/// substrate algebra. The two SPLICE_DISCRIMINATOR assertions
/// (one per `bool_literal` spelling) further collapse to ONE
/// assertion since the lead byte is by construction the SAME
/// across both spellings.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Bool-family lead byte, canonical `'#'`) pairing binds at ONE
/// constant on the closed-set outer [`Atom`] algebra regardless of
/// which reader-surface consumer reaches in. THEORY.md §II.1
/// invariant 5 — composition preserves proofs; the
/// [`Self::bool_literal(b).starts_with(Self::BOOL_LITERAL_LEAD)`]
/// round-trip law is a coherence proof BETWEEN the paired
/// projection ([`Self::bool_literal`]) AND the shared lead byte
/// (this constant) on ONE algebra — a regression that drifts
/// either side surfaces at the pin rather than as a silent
/// hash-prefix reader-family drift. THEORY.md §V.1 — knowable
/// platform; the canonical Bool-family lead byte becomes a
/// TYPE-level constant on the substrate algebra rather than an
/// inline `.chars().next().unwrap()` extraction at every test
/// surface AND an inline `'#'` mention across every docstring
/// pinning the disjointness contract.
pub const BOOL_LITERAL_LEAD: char = '#';
/// Canonical `"` delimiter that opens AND closes a [`Self::Str`]
/// atom in the reader's tokenizer AND self-escapes inside a
/// backslash-escape sequence — ONE canonical `char` on the
/// [`Atom`] algebra the substrate's FOUR `"`-round-trip inline
/// `char` literals at [`crate::reader::tokenize`] bind to.
///
/// Sibling constant of [`Self::KEYWORD_MARKER`] on the atomic-
/// payload marker/delimiter axis of the closed-set [`Atom`]
/// algebra: where `KEYWORD_MARKER` is the ONE `&'static str`
/// prefix a [`Self::Keyword`] payload composes WITH at four
/// canonical-form round-trip sites (reader-entry classifier,
/// Lisp-canonical Display, JSON canonical form, iac-forge
/// canonical form) and [`Self::bool_literal`] is the ONE
/// projection a [`Self::Bool`] payload composes THROUGH at its
/// two Bool-round-trip sites, this constant is the ONE canonical
/// delimiter a [`Self::Str`] payload pairs with at the reader's
/// four `"`-round-trip sites inside [`crate::reader::tokenize`]:
/// 1. The outer-match string-opening arm — the `"` byte that
/// begins a [`crate::reader::Token::Str`] tokenization run.
/// 2. The escape-handler mapping — `\"` unescapes to a bare `"`
/// character inside the accumulated string payload (the
/// only self-escape arm on the reader's five-arm escape
/// table: `\n → \n`, `\t → \t`, `\r → \r`, `\" → "`,
/// `\\ → \\`).
/// 3. The string-closing arm — the `"` byte that terminates the
/// current [`crate::reader::Token::Str`] tokenization run
/// and emits the accumulated payload.
/// 4. The bare-atom tokenizer's break-disjunct — `"` is one of
/// the seven characters that terminates a
/// [`crate::reader::Token::Atom`] run so a bare atom
/// followed by a string (e.g. `foo"body"`) tokenizes as two
/// distinct tokens rather than one Symbol payload.
///
/// Pre-lift the same `"` byte lived inline at four `char`
/// literals scattered across `crate::reader::tokenize`: two outer-
/// match arm patterns (opening + escape-handler), one inner-loop
/// termination pattern (closing), one bare-atom termination
/// disjunct. Post-lift the (Str payload, canonical `"` delimiter)
/// pairing binds at ONE `char` constant on the [`Atom`] algebra
/// that every reader consumer routes through; a refactor that
/// swaps the delimiter (e.g. a Racket-compat port to `#"…"#`
/// heredoc mode, a Python-compat port that also accepts `'`,
/// a triple-quoted heredoc mode) touches ONE constant + one
/// reader table rather than four inline byte literals that would
/// silently drift out of round-trip agreement if one was updated
/// without the others (e.g. an opening `#` without a matching
/// closing `#` would round-trip a broken string with a
/// silently-truncated payload).
///
/// Load-bearing round-trip contract:
/// `read(&format!("{}{s}{}", Atom::STR_DELIMITER,
/// Atom::STR_DELIMITER))[0] == Sexp::Atom(Atom::string(s))` for
/// every escape-free `s: &str`. The reader's opening + closing
/// arms both bind to THIS constant so the delimiter cannot drift
/// silently between opener and closer; a regression that swaps
/// ONE arm's pattern to a different byte fails the round-trip
/// even when the byte-value at the other arm still agrees at
/// the surface. Guards the CLAUDE.md-implicit convention that
/// operator-visible strings use ONE canonical delimiter across
/// the reader entry surface — the delimiter is a first-class
/// algebra fact rather than a per-callsite reader convention.
///
/// Sibling-shape peer of [`Self::KEYWORD_MARKER`] on the closed-
/// set [`Atom`] algebra: where `KEYWORD_MARKER` (`":"`) partitions
/// bare-atom lexemes at reader-entry classifier `strip_prefix`
/// gate into `Keyword` vs default `Symbol`, this constant (`'"'`)
/// partitions the reader's outer tokenizer arm into
/// `Token::Str` vs `Token::Atom` — both are the ONE canonical
/// marker byte the reader binds to when discriminating an
/// [`Atom`] variant's typed-entry classification path. A `Str`
/// payload takes the `Token::Str` reader branch (with THIS
/// delimiter) NOT the `Token::Atom` reader branch (routed
/// through [`Self::from_lexeme`]) — the two paths remain
/// structurally disjoint through the reader's delimiter
/// dispatch.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Str payload, canonical `"` delimiter) pairing now binds at
/// ONE constant on the closed-set [`Atom`] algebra regardless of
/// which of the four reader tokenizer sites reaches in.
/// THEORY.md §VI.1 — generation over composition; four byte-
/// identical inline `'"'` char literals in `crate::reader::tokenize`
/// collapse onto ONE named constant. Four occurrences, well past
/// the ≥2 lift threshold — the substrate's three-times rule at
/// the Str-delimiter axis. THEORY.md §V.1 — knowable platform;
/// the canonical string-delimiter byte becomes a TYPE-level
/// constant on the substrate algebra rather than four inline
/// bytes at four consumer sites inside one reader file.
pub const STR_DELIMITER: char = '"';
/// Canonical `\` escape-lead byte that OPENS a backslash-escape
/// sequence inside a [`Self::Str`] payload AND self-escapes to the
/// same byte inside that sequence — ONE canonical `char` on the
/// [`Atom`] algebra the substrate's TWO `\`-round-trip inline
/// `char` literals at [`crate::reader::tokenize`] bind to.
///
/// Sibling constant of [`Self::STR_DELIMITER`] on the same
/// Str-payload delimiter axis of the closed-set [`Atom`] algebra:
/// where `STR_DELIMITER` is the ONE canonical delimiter that
/// BOUNDS a Str payload from the outside (opener, closer, self-
/// escape, bare-atom terminator), this constant is the ONE
/// canonical escape lead that ESCAPES-IN a following byte from
/// the INSIDE of the same payload. The two constants together
/// span the Str-tokenization boundary — every `char` the reader's
/// `Token::Str` accumulation loop specialises on binds to one of
/// them.
///
/// The reader's TWO `\`-round-trip sites inside
/// [`crate::reader::tokenize`]:
/// 1. The escape-lead outer arm — the `\` byte that triggers the
/// inner escape-handler branch that consumes the following
/// byte as an escape sequence.
/// 2. The escape-handler's self-escape arm — inside the reader's
/// six-arm escape table (`\n → \n`, `\t → \t`, `\r → \r`,
/// `\" → "`, `\\ → \`, passthrough), the self-escape arm on
/// the escape-lead axis: pattern AND mapped value both bind
/// to THIS constant so `\\` unescapes to a single `\` byte
/// in the accumulated payload. Sibling posture to the
/// analogous self-escape arm on [`Self::STR_DELIMITER`] axis
/// (`\"` unescapes to `"`) — the two self-escape arms are
/// the escape table's ONLY pattern-equals-value arms; every
/// other arm is pattern-distinct-from-value.
///
/// Pre-lift the same `\` byte lived inline at two `char` literals
/// scattered across `crate::reader::tokenize`: one outer-arm
/// pattern (escape-lead detection), one inner-loop escape-handler
/// arm's pattern + value pair (the self-escape mapping). Post-
/// lift the (Str-payload escape lead, canonical `\` byte) pairing
/// binds at ONE `char` constant on the [`Atom`] algebra that every
/// reader consumer routes through; a refactor that swaps the
/// escape lead (e.g. a Rust-compat port to `\\` byte-strings, a
/// hypothetical Racket-compat port that adopts `#\` prefix syntax
/// as the escape lead, or a heredoc mode that suspends escaping
/// altogether) touches ONE constant + one reader table rather
/// than two inline byte literals that would silently drift out of
/// round-trip agreement if one was updated without the other
/// (e.g. the outer arm's pattern updated without the inner self-
/// escape's pattern + value would leak a stale escape lead through
/// the wrong branch).
///
/// Load-bearing round-trip contract:
/// `read(&format!("{}{}{}{}", Atom::STR_DELIMITER,
/// Atom::STR_ESCAPE_LEAD, Atom::STR_ESCAPE_LEAD,
/// Atom::STR_DELIMITER))[0] ==
/// Sexp::Atom(Atom::string(Atom::STR_ESCAPE_LEAD.to_string()))`.
/// The `\\` inside a STR_DELIMITER-wrapped payload unescapes to
/// ONE `\` byte on the accumulated payload — pinning the (self-
/// escape pattern, self-escape mapped value) pair against
/// re-inlining. A regression that swaps ONE side of the self-
/// escape arm to a different byte fails this round-trip even when
/// the pattern OR value at the other side still agrees at the
/// surface, because both sides bind to THIS constant.
///
/// Sibling-shape peer of [`Self::STR_DELIMITER`] on the closed-set
/// [`Atom`] algebra: where `STR_DELIMITER` partitions the outer-
/// tokenizer arm into `Token::Str` vs `Token::Atom`, this constant
/// partitions the inner-tokenizer arm (inside `Token::Str`
/// accumulation) into the escape-handler branch vs the passthrough
/// `Some((_, ch))` branch — both are the ONE canonical marker
/// byte the reader binds to when discriminating the Str-payload
/// accumulation loop's branch dispatch.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Str-payload escape lead, canonical `\` byte) pairing now binds
/// at ONE constant on the closed-set [`Atom`] algebra regardless
/// of which of the two reader tokenizer sites reaches in.
/// THEORY.md §VI.1 — generation over composition; two byte-
/// identical inline `'\\'` char literals in `crate::reader::tokenize`
/// collapse onto ONE named constant. Two occurrences at the ≥2
/// lift threshold — the substrate's three-times rule at the
/// Str-escape-lead axis. THEORY.md §V.1 — knowable platform; the
/// canonical string-escape-lead byte becomes a TYPE-level constant
/// on the substrate algebra rather than two inline bytes at two
/// consumer sites inside one reader file.
pub const STR_ESCAPE_LEAD: char = '\\';
/// Canonical Str-payload escape-table projection — total closed-set
/// decode from the ONE post-escape-lead source byte the reader's
/// escape-handler branch consumes to the ONE decoded byte pushed
/// onto the accumulated Str payload. ONE typed projection on the
/// closed-set [`Atom`] algebra that the substrate's Str-escape
/// decode boundary binds to; every consumer that reaches inside a
/// [`Self::Str`] payload for a backslash-escape sequence routes
/// through THIS method rather than a per-site inline
/// `match esc { … }` table.
///
/// Closes the Str-payload tokenization boundary that
/// [`Self::STR_DELIMITER`] + [`Self::STR_ESCAPE_LEAD`] began: where
/// those two constants pin the ONE canonical delimiter byte AND
/// the ONE canonical escape-lead byte the reader's outer + inner
/// branch dispatch specialises on, this method pins the ONE
/// canonical decode table the escape-handler's inner branch
/// consumes AFTER the escape-lead byte fires. The three constants
/// together span the Str-payload tokenization axis — every byte
/// the reader's `Token::Str` accumulation loop reads either
/// terminates the payload (`STR_DELIMITER`), triggers the escape
/// handler (`STR_ESCAPE_LEAD`), pushes through unchanged
/// (passthrough), OR is fed into THIS method as the escape source
/// byte AND its result pushed onto the payload.
///
/// Total function: EVERY `char` maps to exactly one decoded
/// `char`. The five typed arms bind the substrate's canonical
/// escape shorthand:
///
/// | esc source | decoded byte |
/// | ------------------------- | ------------------------- |
/// | `'n'` | `'\n'` |
/// | `'t'` | `'\t'` |
/// | `'r'` | `'\r'` |
/// | `Self::STR_DELIMITER` | `Self::STR_DELIMITER` |
/// | `Self::STR_ESCAPE_LEAD` | `Self::STR_ESCAPE_LEAD` |
/// | any other `char` | itself (passthrough) |
///
/// The two self-escape arms (`STR_DELIMITER → STR_DELIMITER`,
/// `STR_ESCAPE_LEAD → STR_ESCAPE_LEAD`) are the ONLY
/// pattern-equals-value arms in the table; both bind through the
/// closed-set [`Atom`] algebra constants so a delimiter-swap or
/// escape-lead-swap on the algebra propagates through pattern AND
/// value at ONE site rather than as scattered inline byte literals
/// that would silently drift out of round-trip agreement if one
/// was updated without the other.
///
/// The three named-escape arms (`'n'` / `'t'` / `'r'`) are the
/// substrate's canonical whitespace shorthand — pattern-distinct-
/// from-value on every arm (each maps a printable ASCII letter to
/// its corresponding C0 control byte). Pre-lift the whole table
/// lived inline at ONE site inside [`crate::reader::tokenize`]'s
/// escape-handler branch; post-lift the table lives at ONE typed
/// projection on the [`Atom`] algebra that the reader consumes
/// through a single `Self::decode_str_escape(esc)` call. Adding a
/// sixth named-escape arm (e.g. `'0' → '\0'` for the NUL byte, or
/// an `'x'` hex-byte-prefix arm) extends THIS method's match
/// rather than mutating the reader's inline block.
///
/// Load-bearing round-trip contract: for every `esc: char`,
/// `read(&format!("{}{}{}{}", Atom::STR_DELIMITER,
/// Atom::STR_ESCAPE_LEAD, esc, Atom::STR_DELIMITER))[0] ==
/// Sexp::Atom(Atom::string(Atom::decode_str_escape(esc)
/// .to_string()))`. Every escape-source byte inside a
/// STR_DELIMITER-wrapped payload decodes through THIS projection
/// end-to-end — pinning the (reader escape-handler branch, this
/// method) pairing against a silent drift at either side. A
/// regression that re-inlines the reader's table would break the
/// pin the moment a new arm lands here but NOT there (or vice
/// versa).
///
/// Sibling-shape peer of [`QuoteForm::from_lead_char`] on the
/// closed-set [`QuoteForm`] algebra: where `from_lead_char` is
/// the ONE typed dispatch on the outer-tokenizer quote-family
/// axis (four homoiconic prefix chars decode to `Option<Self>`),
/// this method is the ONE typed dispatch on the inner-tokenizer
/// Str-escape axis (every escape-source char decodes to a
/// resolved `char`). Both are the substrate's canonical
/// closed-set projections the reader consumes through ONE call
/// site each; both close the reader's per-char specialization
/// point onto the algebra.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Str-escape source byte, decoded byte) pairing now binds at
/// ONE typed projection on the closed-set [`Atom`] algebra
/// regardless of which consumer reaches in. THEORY.md §VI.1 —
/// generation over composition; the reader's five-arm inline
/// table plus one passthrough arm at [`crate::reader::tokenize`]
/// collapses onto ONE named projection. THEORY.md §V.1 — knowable
/// platform; the canonical Str-escape decode table becomes a
/// TYPE-level method on the substrate algebra rather than an
/// inline block inside one reader file — a future decoder
/// (e.g. a Racket-compat port, a heredoc mode, a raw-string
/// mode) plugs a peer projection onto the same algebra rather
/// than forking the reader.
///
/// Canonical newline-escape SOURCE char — the ONE `'n'` byte
/// [`Self::decode_str_escape`]'s newline arm pattern-matches on.
/// Sibling constant of [`Self::NEWLINE_ESCAPE_DECODED`] on the
/// same (source, decoded) escape-arm axis: the (`'n'`, `'\n'`)
/// pairing is the first of the substrate's three named-escape
/// arms; each pairing binds at ONE `pub const` per role rather
/// than at an inline `char` literal at the match-arm pattern +
/// value. Sibling posture to [`Self::STR_DELIMITER`] /
/// [`Self::STR_ESCAPE_LEAD`] one axis over on the same
/// Str-payload tokenization boundary — those two constants pin
/// the ONE canonical delimiter byte AND the ONE canonical
/// escape-lead byte the reader's outer + inner branch dispatch
/// specialises on; this constant + its five per-role peers
/// close the (named-escape, self-escape) decode-arm surface at
/// the same closed-set [`Atom`] algebra.
pub const NEWLINE_ESCAPE_SOURCE: char = 'n';
/// Canonical newline-escape DECODED byte — the ONE `'\n'` C0
/// control byte [`Self::decode_str_escape`]'s newline arm
/// value-emits when the source char is [`Self::NEWLINE_ESCAPE_SOURCE`].
/// Peer of the SOURCE constant on the SAME (source, decoded)
/// escape-arm axis; the pairing (`NEWLINE_ESCAPE_SOURCE`,
/// `NEWLINE_ESCAPE_DECODED`) IS the first row of the
/// [`Self::NAMED_ESCAPE_TABLE`] two-column algebra.
pub const NEWLINE_ESCAPE_DECODED: char = '\n';
/// Canonical tab-escape SOURCE char — the ONE `'t'` byte
/// [`Self::decode_str_escape`]'s tab arm pattern-matches on.
/// Second of the three named-escape SOURCE `pub const` peers.
pub const TAB_ESCAPE_SOURCE: char = 't';
/// Canonical tab-escape DECODED byte — the ONE `'\t'` C0
/// control byte [`Self::decode_str_escape`]'s tab arm
/// value-emits when the source char is [`Self::TAB_ESCAPE_SOURCE`].
/// Peer of the SOURCE constant on the SAME (source, decoded)
/// escape-arm axis; the pairing (`TAB_ESCAPE_SOURCE`,
/// `TAB_ESCAPE_DECODED`) IS the second row of the
/// [`Self::NAMED_ESCAPE_TABLE`] two-column algebra.
pub const TAB_ESCAPE_DECODED: char = '\t';
/// Canonical carriage-return-escape SOURCE char — the ONE `'r'`
/// byte [`Self::decode_str_escape`]'s carriage-return arm
/// pattern-matches on. Third of the three named-escape SOURCE
/// `pub const` peers.
pub const CARRIAGE_RETURN_ESCAPE_SOURCE: char = 'r';
/// Canonical carriage-return-escape DECODED byte — the ONE
/// `'\r'` C0 control byte [`Self::decode_str_escape`]'s
/// carriage-return arm value-emits when the source char is
/// [`Self::CARRIAGE_RETURN_ESCAPE_SOURCE`]. Peer of the SOURCE
/// constant on the SAME (source, decoded) escape-arm axis; the
/// pairing (`CARRIAGE_RETURN_ESCAPE_SOURCE`,
/// `CARRIAGE_RETURN_ESCAPE_DECODED`) IS the third row of the
/// [`Self::NAMED_ESCAPE_TABLE`] two-column algebra.
pub const CARRIAGE_RETURN_ESCAPE_DECODED: char = '\r';
/// Canonical NAMED-escape table — the closed-set ALL array over
/// the substrate's three (SOURCE, DECODED) pairings the
/// pattern-distinct-from-value named-escape arms of
/// [`Self::decode_str_escape`] emit, in canonical declaration
/// order (newline / tab / carriage-return). Forced-arity
/// `[(char, char); 3]` composition — a hypothetical fourth
/// named-escape arm (e.g. `'0' → '\0'` for the NUL byte, `'e'
/// → '\x1b'` for ESC, or a Racket-compat `'a' → '\x07'` for
/// BEL) extends [`Self::decode_str_escape`]'s match ONCE +
/// this array ONCE + TWO new per-role `pub const`s (one on
/// each axis) in lockstep; rustc's forced-arity check on
/// `[(char, char); N]` binds the extension through the array
/// declaration site. Sibling posture to
/// [`QuoteForm::PREFIXES`] / [`QuoteForm::IAC_FORGE_TAGS`] on
/// the outer-tokenizer quote-family axis — where those ALL
/// arrays close the reader-prefix + canonical-form byte
/// vocabularies on the [`QuoteForm`] closed set, this array
/// closes the named-escape (source, decoded) pairing vocabulary
/// on the inner-tokenizer Str-escape axis of the [`Atom`]
/// closed set.
///
/// The `[(char, char); 3]` shape (rather than a `[char; 3]`
/// singleton) is load-bearing: the escape-arm is a projection
/// from a source byte to a decoded byte, both bytes are typed
/// data, and pinning them as a PAIR at the array declaration
/// site closes the drift channel between pattern (source) and
/// value (decoded) that a scalar array would leave open.
///
/// Excludes the two pattern-equals-value self-escape arms
/// (`Self::STR_DELIMITER → Self::STR_DELIMITER`,
/// `Self::STR_ESCAPE_LEAD → Self::STR_ESCAPE_LEAD`) because
/// those bind through [`Self::STR_DELIMITER`] +
/// [`Self::STR_ESCAPE_LEAD`] one axis over on the Str-payload
/// delimiter axis — the (source, decoded) pairing there is
/// definitionally the identity by algebra design (a delimiter-
/// swap propagates through pattern AND value at ONE constant
/// per axis). This array closes the OTHER three arms — the
/// pattern-DISTINCT-from-value named-escape rows.
pub const NAMED_ESCAPE_TABLE: [(char, char); 3] = [
(Self::NEWLINE_ESCAPE_SOURCE, Self::NEWLINE_ESCAPE_DECODED),
(Self::TAB_ESCAPE_SOURCE, Self::TAB_ESCAPE_DECODED),
(
Self::CARRIAGE_RETURN_ESCAPE_SOURCE,
Self::CARRIAGE_RETURN_ESCAPE_DECODED,
),
];
/// Canonical SELF-escape table — the closed-set ALL array over the
/// substrate's TWO pattern-EQUALS-value arms of
/// [`Self::decode_str_escape`], in canonical declaration order
/// ([`Self::STR_DELIMITER`], [`Self::STR_ESCAPE_LEAD`]) matching
/// the projection's match-arm order. Forced-arity `[char; 2]`
/// composition — a hypothetical third self-escape byte (e.g. a
/// raw-string mode adopting `'#'` as an additional self-escaping
/// delimiter, or a Racket-compat `'|'` verbatim-symbol boundary)
/// extends [`Self::decode_str_escape`]'s match ONCE + this array
/// ONCE + ONE new `pub const` on the closed-set [`Atom`] algebra
/// in lockstep; rustc's forced-arity check on `[char; N]` binds
/// the extension through the array declaration site.
///
/// Peer to [`Self::NAMED_ESCAPE_TABLE`] on the SAME Str-payload
/// tokenization boundary: where `NAMED_ESCAPE_TABLE` closes the
/// THREE pattern-DISTINCT-from-value named-escape rows (`'n' →
/// '\n'`, `'t' → '\t'`, `'r' → '\r'`), this array closes the TWO
/// pattern-EQUALS-value self-escape rows (`STR_DELIMITER →
/// STR_DELIMITER`, `STR_ESCAPE_LEAD → STR_ESCAPE_LEAD`). The two
/// arrays together span the FIVE non-passthrough arms of
/// [`Self::decode_str_escape`] — every byte the reader's
/// `Token::Str` escape-handler branch specialises on lives in
/// exactly ONE of the two closed-set arrays OR falls through the
/// `other => other` passthrough at the algebra's projection.
///
/// The `[char; 2]` shape (rather than a `[(char, char); 2]`
/// pairing peer to `NAMED_ESCAPE_TABLE`) is load-bearing: the
/// self-escape arm is definitionally the identity by algebra
/// design (a delimiter-swap propagates through pattern AND value
/// at ONE constant per axis), so the PAIRING collapses to a
/// SCALAR on this sub-vocabulary. The SHAPE ASYMMETRY between the
/// two peer arrays ([(char, char); N] vs [char; N]) IS the
/// structural axis distinguishing the pattern-DISTINCT-from-value
/// vocabulary from the pattern-EQUALS-value vocabulary — a
/// consumer that reaches for the array shape encodes its
/// vocabulary's identity relation in the SHAPE it iterates.
///
/// Sibling posture to [`QuoteForm::PREFIXES`] +
/// [`QuoteForm::IAC_FORGE_TAGS`] on the outer-tokenizer
/// quote-family axis — where those ALL arrays close the TWO
/// byte-vocabulary axes (reader prefix + iac-forge tag) of the
/// outer-tokenizer `QuoteForm` closed set with parallel shapes,
/// `NAMED_ESCAPE_TABLE` + `SELF_ESCAPE_TABLE` close the TWO
/// sub-vocabularies (pattern-distinct + pattern-equals) of the
/// inner-tokenizer `Atom` Str-escape closed set with asymmetric
/// shapes reflecting the identity-relation asymmetry.
pub const SELF_ESCAPE_TABLE: [char; 2] = [Self::STR_DELIMITER, Self::STR_ESCAPE_LEAD];
/// Canonical closed-set ALL array over every escape-SOURCE byte
/// [`Self::decode_str_escape`] has a non-passthrough arm for — the
/// SPAN of the two peer sub-vocabulary source columns
/// ([`Self::NAMED_ESCAPE_TABLE`]'s three (SOURCE, DECODED) pairs'
/// SOURCE column + [`Self::SELF_ESCAPE_TABLE`]'s two rows) in
/// canonical declaration order matching `decode_str_escape`'s
/// match-arm order. Forced-arity `[char; 5]` composition — a
/// hypothetical sixth non-passthrough arm (e.g. a `'0' → '\0'`
/// NUL-byte extension, a Racket-compat `'a' → '\x07'` BEL, a raw-
/// string mode adopting `'#'` as an additional self-escaping
/// delimiter) extends [`Self::decode_str_escape`]'s match ONCE +
/// EITHER `NAMED_ESCAPE_TABLE` or `SELF_ESCAPE_TABLE` ONCE + this
/// ALL array ONCE + one new per-role `pub const` (or pair) in
/// lockstep; rustc's forced-arity check on `[char; N]` binds the
/// extension through the array declaration site.
///
/// Cross-sub-vocabulary SPAN peer to [`Self::NAMED_ESCAPE_TABLE`] +
/// [`Self::SELF_ESCAPE_TABLE`] at the ALL-array level: where those
/// two arrays partition the FIVE non-passthrough arms of
/// [`Self::decode_str_escape`] into the pattern-DISTINCT-from-value
/// sub-vocabulary (3 rows, `[(char, char); 3]`) AND the pattern-
/// EQUALS-value sub-vocabulary (2 rows, `[char; 2]`), this array
/// closes the UNION of the SOURCE columns at ONE typed
/// `[char; 5]` on the SAME closed-set [`Atom`] algebra. Pre-lift
/// the SPAN identity lived at TWO sites: the runtime iterator
/// chain
/// `Atom::NAMED_ESCAPE_TABLE.iter().map(|&(src, _)| src)
/// .chain(Atom::SELF_ESCAPE_TABLE.iter().copied()).collect()` at
/// `atom_decode_str_escape_composes_end_to_end_through_reader_for_every_named_arm`
/// AND the prose docstring for [`Self::SELF_ESCAPE_TABLE`] naming
/// "the FIVE non-passthrough arms" as a cardinality identity. Post-
/// lift the SPAN binds at ONE forced-arity `[char; 5]` on the
/// [`Atom`] algebra so consumers that want "every char for which
/// decode_str_escape is not the identity passthrough" iterate the
/// typed array rather than reassembling the two peer arrays at
/// each callsite.
///
/// Also sibling-shape to [`Sexp::LIST_DELIMITERS`] (`[char; 2]` on
/// the outer-structural paired-delimiter axis of the closed-set
/// [`Sexp`] algebra), [`Sexp::COMMENT_DELIMITERS`] (`[char; 2]` on
/// the reader-discard paired-delimiter axis of the SAME [`Sexp`]
/// algebra), [`Atom::BOOL_LITERALS`] (`[&'static str; 2]` on the
/// Scheme-bool spelling axis of this same [`Atom`] algebra), and
/// [`QuoteForm::LEADS`] (`[char; 3]` on the DISTINCT-lead-byte
/// sub-vocabulary axis of the closed-set [`QuoteForm`] algebra) —
/// every closed-set outer projection on the substrate that carries
/// a scalar `[char; N]` sub-vocabulary now pins its canonical
/// bytes at ONE `pub const` per role plus a forced-arity ALL array
/// for family-wide consumers.
///
/// Composition law (SPAN): `ESCAPE_SOURCES ==
/// [NAMED_ESCAPE_TABLE[0].0, NAMED_ESCAPE_TABLE[1].0,
/// NAMED_ESCAPE_TABLE[2].0, SELF_ESCAPE_TABLE[0],
/// SELF_ESCAPE_TABLE[1]]` AND `ESCAPE_SOURCES.len() ==
/// NAMED_ESCAPE_TABLE.len() + SELF_ESCAPE_TABLE.len()` — the
/// forced-arity + canonical declaration order together pin every
/// downstream index-sweep consumer to the (named-source-column
/// prefix, self-source-column suffix) partition at rustc time; a
/// reorder that broke the partition (e.g. interleaving the two
/// sub-vocabularies' rows) fails at the composition pin below.
///
/// Path-uniformity contract carried at the row level: for every
/// `esc` in `ESCAPE_SOURCES`, `Self::decode_str_escape(esc) != esc`
/// iff `esc` is a NAMED_ESCAPE_TABLE SOURCE row (the three
/// pattern-DISTINCT-from-value arms), and `Self::decode_str_escape
/// (esc) == esc` iff `esc` is a SELF_ESCAPE_TABLE row (the two
/// pattern-EQUALS-value arms). The union is exhaustive over the
/// FIVE non-passthrough arms so no `ESCAPE_SOURCES` row projects
/// through the `other => other` passthrough branch — the arm-set
/// closure is pinned structurally at
/// `atom_escape_sources_every_row_projects_through_a_non_passthrough_arm_of_decode_str_escape`.
///
/// Pairwise disjointness: every row is distinct from every other
/// row — the closed-set SPAN inherits pairwise disjointness from
/// the two peer sub-vocabularies (each already pairwise distinct
/// via `atom_named_escape_table_sources_pairwise_distinct` +
/// `atom_self_escape_table_pairwise_distinct`) PLUS the cross-
/// sub-vocabulary disjointness pinned by
/// `atom_self_escape_table_disjoint_from_named_escape_table`. This
/// ALL array's own `atom_escape_sources_pairwise_distinct` test
/// closes the disjointness contract at the SPAN-level so a future
/// refactor that added a sixth arm whose SOURCE aliased an
/// existing arm surfaces HERE rather than at a distant reader
/// round-trip.
///
/// Future consumers that compose against [`Self::ESCAPE_SOURCES`]:
/// - LSP / REPL completion for the escape-source vocabulary — the
/// completion set IS `Self::ESCAPE_SOURCES` rather than a
/// per-consumer chain over the two peer arrays.
/// - `tatara-check` coverage assertions that a `.lisp` corpus
/// exercises every non-passthrough escape arm — the sweep IS
/// `Self::ESCAPE_SOURCES.iter()` rather than a runtime chain
/// over `NAMED_ESCAPE_TABLE.iter().map(|&(src, _)| src)
/// .chain(SELF_ESCAPE_TABLE.iter().copied())`.
/// - Any future syntax-highlighter that colors escape sequences —
/// the classifier binds through `Self::ESCAPE_SOURCES` rather
/// than through two parallel per-sub-vocabulary lookups.
/// - Any future fuzz-input generator that biases toward escape
/// sequences — the source-byte pool IS `Self::ESCAPE_SOURCES`
/// rather than reassembled from the two peer arrays.
///
/// Theory anchor: THEORY.md §III — the typescape; the FIVE non-
/// passthrough source bytes now bind at ONE typed `[char; 5]` on
/// the closed-set [`Atom`] algebra rather than at a runtime chain
/// over the two peer sub-vocabulary arrays reassembled per
/// consumer. THEORY.md §V.1 — knowable platform; the non-
/// passthrough source-byte SPAN becomes load-bearing typed data at
/// the algebra level. THEORY.md §VI.1 — generation over
/// composition; the "FIVE non-passthrough arms" identity that
/// lived as prose in the [`Self::SELF_ESCAPE_TABLE`] docstring AND
/// as a runtime iterator chain at one test site regenerates
/// identically through this ONE typed forced-arity array.
pub const ESCAPE_SOURCES: [char; 5] = [
Self::NEWLINE_ESCAPE_SOURCE,
Self::TAB_ESCAPE_SOURCE,
Self::CARRIAGE_RETURN_ESCAPE_SOURCE,
Self::STR_DELIMITER,
Self::STR_ESCAPE_LEAD,
];
/// Canonical closed-set ALL array over every DECODED byte
/// [`Self::decode_str_escape`] can emit from a non-passthrough arm
/// — the SPAN of the two peer sub-vocabulary DECODED columns
/// ([`Self::NAMED_ESCAPE_TABLE`]'s three (SOURCE, DECODED) pairs'
/// DECODED column + [`Self::SELF_ESCAPE_TABLE`]'s two rows, which
/// are pattern-EQUALS-value so their DECODED column is definitionally
/// the row byte itself) in canonical declaration order matching
/// `decode_str_escape`'s match-arm order. Forced-arity `[char; 5]`
/// composition — a hypothetical sixth non-passthrough arm (e.g. a
/// `'0' → '\0'` NUL-byte extension, a Racket-compat `'a' → '\x07'`
/// BEL, a raw-string mode adopting `'#'` as an additional
/// self-escaping delimiter) extends [`Self::decode_str_escape`]'s
/// match ONCE + EITHER `NAMED_ESCAPE_TABLE` or `SELF_ESCAPE_TABLE`
/// ONCE + this ALL array ONCE + [`Self::ESCAPE_SOURCES`] ONCE + one
/// new per-role `pub const` (or pair) in lockstep; rustc's forced-
/// arity check on `[char; N]` binds the extension through the array
/// declaration site.
///
/// Column-dual peer to [`Self::ESCAPE_SOURCES`] on the SAME closed-set
/// [`Atom`] algebra: where `ESCAPE_SOURCES` closes the SOURCE column
/// of the FIVE non-passthrough arms at ONE typed `[char; 5]`, this
/// array closes the DECODED column at the SAME shape. Together the
/// two arrays close the (SOURCE, DECODED) cross-product of
/// `decode_str_escape`'s non-passthrough arm-set at two byte-
/// identical `[char; 5]` shapes on the SAME closed-set [`Atom`]
/// algebra — the shape symmetry across the two columns of the SAME
/// arm-set is itself a typed load-bearing invariant carrying the
/// column-dual identity relation on the algebra.
///
/// Cross-sub-vocabulary SPAN peer to [`Self::NAMED_ESCAPE_TABLE`] +
/// [`Self::SELF_ESCAPE_TABLE`] at the ALL-array level: where those
/// two arrays partition the FIVE non-passthrough arms of
/// [`Self::decode_str_escape`] into the pattern-DISTINCT-from-value
/// sub-vocabulary (3 rows, `[(char, char); 3]`) AND the pattern-
/// EQUALS-value sub-vocabulary (2 rows, `[char; 2]`), this array
/// closes the UNION of the DECODED columns at ONE typed
/// `[char; 5]` on the SAME closed-set [`Atom`] algebra. Pre-lift
/// the DECODED SPAN identity lived at ZERO callsites — the substrate
/// had a typed SOURCE-column SPAN ([`Self::ESCAPE_SOURCES`]) but the
/// DECODED-column SPAN was only reachable by iterating the two peer
/// sub-vocabulary arrays' DECODED columns per consumer OR by mapping
/// `ESCAPE_SOURCES` through [`Self::decode_str_escape`] at runtime;
/// post-lift the DECODED SPAN binds at ONE forced-arity `[char; 5]`
/// on the [`Atom`] algebra so consumers that want "every byte
/// decode_str_escape can emit from a typed non-passthrough arm"
/// iterate the typed array rather than reassembling it per callsite.
///
/// Also sibling-shape to [`Sexp::LIST_DELIMITERS`] (`[char; 2]` on
/// the outer-structural paired-delimiter axis of the closed-set
/// [`Sexp`] algebra), [`Sexp::COMMENT_DELIMITERS`] (`[char; 2]` on
/// the reader-discard paired-delimiter axis of the SAME [`Sexp`]
/// algebra), [`Atom::BOOL_LITERALS`] (`[&'static str; 2]` on the
/// Scheme-bool spelling axis of this same [`Atom`] algebra), and
/// [`QuoteForm::LEADS`] (`[char; 3]` on the DISTINCT-lead-byte
/// sub-vocabulary axis of the closed-set [`QuoteForm`] algebra) —
/// every closed-set outer projection on the substrate that carries
/// a scalar `[char; N]` sub-vocabulary now pins its canonical bytes
/// at ONE `pub const` per role plus a forced-arity ALL array for
/// family-wide consumers.
///
/// Composition law (SPAN): `ESCAPE_DECODED ==
/// [NAMED_ESCAPE_TABLE[0].1, NAMED_ESCAPE_TABLE[1].1,
/// NAMED_ESCAPE_TABLE[2].1, SELF_ESCAPE_TABLE[0],
/// SELF_ESCAPE_TABLE[1]]` AND `ESCAPE_DECODED.len() ==
/// NAMED_ESCAPE_TABLE.len() + SELF_ESCAPE_TABLE.len()` — the
/// forced-arity + canonical declaration order together pin every
/// downstream index-sweep consumer to the (named-decoded-column
/// prefix, self-decoded-column suffix) partition at rustc time; a
/// reorder that broke the partition (e.g. interleaving the two
/// sub-vocabularies' rows) fails at the composition pin below.
///
/// Column-dual pointwise projection law: for every index `i` in
/// `0..5`, `ESCAPE_DECODED[i] == Self::decode_str_escape(
/// ESCAPE_SOURCES[i])`. The two forced-arity `[char; 5]` arrays are
/// the SOURCE column and DECODED column of `decode_str_escape`'s
/// non-passthrough arm-set — the pointwise projection identity is
/// pinned structurally at
/// `atom_escape_decoded_projects_pointwise_from_escape_sources_through_decode_str_escape`.
///
/// Pairwise disjointness: every row is distinct from every other
/// row — `'\n'`, `'\t'`, `'\r'`, `'"'`, `'\\'` are five distinct
/// C0-and-ASCII bytes. Distinctness on the DECODED column follows
/// from (a) the NAMED sub-vocabulary's DECODED-column pairwise
/// distinctness at `atom_named_escape_table_decoded_pairwise_distinct`,
/// (b) the SELF sub-vocabulary's pairwise distinctness at
/// `atom_self_escape_table_pairwise_distinct`, and (c) the fact
/// that no NAMED-DECODED byte (`'\n'`, `'\t'`, `'\r'` — all C0
/// control bytes) can alias a SELF byte (`'"'`, `'\\'` — printable
/// ASCII bytes). The pairwise-distinctness pin below closes the
/// contract at the SPAN level so a future refactor that added a
/// sixth arm whose DECODED aliased an existing row surfaces HERE
/// rather than at a distant reader round-trip.
///
/// Future consumers that compose against [`Self::ESCAPE_DECODED`]:
/// - A Str-render / encoder consumer that needs to escape a DECODED
/// byte back into its SOURCE form — the classifier IS "is this
/// byte in `Self::ESCAPE_DECODED`?" rather than a per-consumer
/// chain over the two peer sub-vocabularies' DECODED columns.
/// - LSP / REPL diagnostic rendering that needs to name every byte
/// the substrate's escape-handler can emit — the completion set
/// IS `Self::ESCAPE_DECODED` rather than a runtime map through
/// `decode_str_escape` from `ESCAPE_SOURCES`.
/// - A syntax-highlighter that colors decoded-escape byte payloads —
/// the classifier binds through `Self::ESCAPE_DECODED` rather
/// than through two parallel per-sub-vocabulary lookups.
/// - A fuzz-input generator that biases toward decoded-escape byte
/// payloads (probing the reader's error-recovery path when a
/// raw C0 byte appears inside a Str payload) — the target-byte
/// pool IS `Self::ESCAPE_DECODED` rather than reassembled from
/// the two peer arrays.
///
/// Theory anchor: THEORY.md §III — the typescape; the FIVE
/// DECODED bytes of the non-passthrough arm-set now bind at ONE
/// typed `[char; 5]` on the closed-set [`Atom`] algebra rather than
/// at a runtime map through `decode_str_escape` from
/// `ESCAPE_SOURCES`. THEORY.md §V.1 — knowable platform; the
/// non-passthrough DECODED-byte SPAN becomes load-bearing typed
/// data at the algebra level. THEORY.md §VI.1 — generation over
/// composition; the column-dual identity that lived only as a
/// runtime `decode_str_escape` projection of the peer SOURCE-column
/// SPAN regenerates identically through this ONE typed forced-arity
/// array.
pub const ESCAPE_DECODED: [char; 5] = [
Self::NEWLINE_ESCAPE_DECODED,
Self::TAB_ESCAPE_DECODED,
Self::CARRIAGE_RETURN_ESCAPE_DECODED,
Self::STR_DELIMITER,
Self::STR_ESCAPE_LEAD,
];
/// Canonical closed-set ALL array over every `(SOURCE, DECODED)`
/// pair [`Self::decode_str_escape`] projects at a non-passthrough
/// arm — the paired-column SPAN closing BOTH columns of the FIVE
/// non-passthrough arms at ONE typed forced-arity
/// `[(char, char); 5]` on the closed-set [`Atom`] algebra.
/// Composes as `NAMED_ESCAPE_TABLE`'s three pattern-DISTINCT-from-
/// value rows (which are already `(char, char)` shape) followed by
/// `SELF_ESCAPE_TABLE`'s two pattern-EQUALS-value rows re-shaped as
/// `(row, row)` pairs (the definitional-identity closure of the
/// self-escape sub-vocabulary at the paired shape), in canonical
/// declaration order matching `decode_str_escape`'s match-arm order.
///
/// Cross-column peer-collapse of [`Self::ESCAPE_SOURCES`] +
/// [`Self::ESCAPE_DECODED`] — the two byte-identical `[char; 5]`
/// column-dual arrays close the SOURCE column and DECODED column
/// SEPARATELY at ONE forced-arity `[char; 5]` each; this array
/// closes BOTH columns TOGETHER at ONE typed forced-arity
/// `[(char, char); 5]` on the SAME closed-set [`Atom`] algebra.
/// Together the three arrays close the FIVE non-passthrough arms
/// at THREE typed forced-arity shapes: `[char; 5]` on the SOURCE
/// column, `[char; 5]` on the DECODED column, and `[(char, char);
/// 5]` on the paired-column composition. The shape symmetry
/// `(SOURCE, DECODED)` pair at row `i` IS
/// `(ESCAPE_SOURCES[i], ESCAPE_DECODED[i])` is a load-bearing
/// pointwise identity carrying the two-column composition relation
/// on the algebra.
///
/// Paired-column SPAN peer to [`Self::NAMED_ESCAPE_TABLE`] +
/// [`Self::SELF_ESCAPE_TABLE`] at the paired-shape level: where
/// those two arrays partition the FIVE arms into the pattern-
/// DISTINCT-from-value sub-vocabulary (3 rows already at
/// `[(char, char); 3]` shape by algebra design) AND the pattern-
/// EQUALS-value sub-vocabulary (2 rows at `[char; 2]` shape by
/// definitional-identity collapse), this array closes the UNION of
/// the two sub-vocabularies at ONE typed `[(char, char); 5]` — the
/// self-escape rows re-shaped from `char` to `(char, char)` at the
/// SPAN level via the definitional-identity `(row, row)`
/// composition. Pre-lift the paired-column SPAN identity lived at
/// ZERO callsites at the paired shape — consumers wanting "every
/// `(SOURCE, DECODED)` pair `decode_str_escape` projects at a non-
/// passthrough arm on the closed-set [`Atom`] algebra" had to zip
/// the two column-dual `[char; 5]` peer arrays at their sites OR
/// iterate `NAMED_ESCAPE_TABLE` and re-shape `SELF_ESCAPE_TABLE`'s
/// rows to `(row, row)` per callsite. Post-lift the paired-column
/// SPAN binds at ONE forced-arity `[(char, char); 5]` on the
/// [`Atom`] algebra.
///
/// Also sibling-shape to [`Self::NAMED_ESCAPE_TABLE`]
/// (`[(char, char); 3]` on the same paired-column axis, one sub-
/// vocabulary over on the pattern-DISTINCT-from-value axis of the
/// SAME closed-set [`Atom`] algebra) — the paired-column shape is
/// the substrate-canonical shape for closing a `(SOURCE, DECODED)`
/// cross-product at ONE typed array on the algebra; extending it
/// from the NAMED sub-vocabulary's 3-row shape to the SPAN's 5-row
/// shape is a mechanical arity extension. A hypothetical sixth
/// non-passthrough arm (e.g. a `'0' → '\0'` NUL-byte extension,
/// a Racket-compat `'a' → '\x07'` BEL, a raw-string mode adopting
/// `'#'` as an additional self-escaping delimiter) extends
/// [`Self::decode_str_escape`]'s match ONCE plus EITHER
/// `NAMED_ESCAPE_TABLE` or `SELF_ESCAPE_TABLE` ONCE plus this ALL
/// array ONCE plus both column-dual `[char; 5]` peer arrays
/// ([`Self::ESCAPE_SOURCES`] and [`Self::ESCAPE_DECODED`]) ONCE
/// each plus one new per-role `pub const` (or pair) in lockstep;
/// rustc's forced-arity check on `[(char, char); N]` binds the
/// extension through the array declaration site.
///
/// Composition law (paired SPAN): for every index `i` in `0..5`,
/// `ESCAPE_TABLE[i] == (ESCAPE_SOURCES[i], ESCAPE_DECODED[i])`.
/// The forced-arity `[(char, char); 5]` + canonical declaration
/// order pin every downstream index-sweep consumer to the (named
/// prefix, self suffix) partition at rustc time. The paired-SPAN
/// row identity is pinned structurally at
/// `atom_escape_table_composes_pointwise_from_escape_sources_and_escape_decoded_column_duals`.
///
/// Sub-vocabulary partition law: `ESCAPE_TABLE[0..3] ==
/// NAMED_ESCAPE_TABLE` (the pattern-DISTINCT-from-value sub-
/// vocabulary at its native paired shape passes through
/// identically), AND for i in 3..5, `ESCAPE_TABLE[i] ==
/// (SELF_ESCAPE_TABLE[i-3], SELF_ESCAPE_TABLE[i-3])` (the pattern-
/// EQUALS-value sub-vocabulary re-shapes from `char` to
/// `(row, row)` at the SPAN level via the definitional-identity
/// collapse). Pinned structurally at
/// `atom_escape_table_partitions_into_named_paired_prefix_and_self_reshape_suffix`.
///
/// Pattern-classification partition law: for every index `i` in
/// `0..3`, `ESCAPE_TABLE[i].0 != ESCAPE_TABLE[i].1` (the NAMED
/// pattern-DISTINCT-from-value prefix); for every index `i` in
/// `3..5`, `ESCAPE_TABLE[i].0 == ESCAPE_TABLE[i].1` (the SELF
/// pattern-EQUALS-value suffix). The classification carried in the
/// row's per-column identity relation IS the sub-vocabulary
/// identity — a consumer classifying an escape arm reads the sub-
/// vocabulary off `row.0 == row.1` rather than off an index range
/// or a separate tag. Pinned structurally at
/// `atom_escape_table_named_prefix_is_pattern_distinct_and_self_suffix_is_pattern_equals`.
///
/// Pointwise projection law: for every `(src, decoded)` in
/// `ESCAPE_TABLE`, `Self::decode_str_escape(src) == decoded`. The
/// paired-column SPAN closes the (input, output) cross-product of
/// `decode_str_escape`'s non-passthrough arm-set at ONE typed
/// array so a refactor that drifted the arm-set (swapped rows,
/// added a row without extending the array, or removed a row
/// without extending the array) surfaces HERE at the first drifted
/// pair rather than at a distant sweep site.
///
/// Future consumers that compose against [`Self::ESCAPE_TABLE`]:
/// - A round-trip reader/renderer that pairs SOURCE bytes with
/// their DECODED payloads — the paired vocabulary IS
/// `Self::ESCAPE_TABLE` rather than a zip of the two column-dual
/// peer arrays.
/// - LSP / REPL diagnostic rendering that names both columns of
/// every non-passthrough arm — the completion set IS
/// `Self::ESCAPE_TABLE` rather than reassembled from the two
/// sub-vocabulary arrays via a `char → (char, char)` re-shape on
/// the SELF rows.
/// - A syntax-highlighter that colors both the SOURCE byte and the
/// DECODED payload of every escape arm — the classifier binds
/// through `Self::ESCAPE_TABLE` rather than through two parallel
/// per-column lookups.
/// - A fuzz-input generator that exercises `decode_str_escape`'s
/// projection round-trip — the input-output pool IS
/// `Self::ESCAPE_TABLE` rather than a runtime zip of the peer
/// arrays.
/// - A hypothetical `EscapeArm` typed sum enumerating the FIVE
/// non-passthrough arms at ONE closed-set enum on the algebra
/// (with `ESCAPE_TABLE` becoming its `.pair()` projection).
///
/// Theory anchor: THEORY.md §III — the typescape; the FIVE
/// `(SOURCE, DECODED)` pairs of the non-passthrough arm-set now
/// bind at ONE typed `[(char, char); 5]` on the closed-set
/// [`Atom`] algebra rather than at a runtime zip of the two peer
/// column-dual arrays. THEORY.md §V.1 — knowable platform; the
/// non-passthrough paired-column SPAN becomes load-bearing typed
/// data at the algebra level. THEORY.md §VI.1 — generation over
/// composition; the paired-column identity that lived only as a
/// runtime zip of the peer column-dual `[char; 5]` SPANs
/// regenerates identically through this ONE typed forced-arity
/// pair-array. THEORY.md §II.1 invariant 5 — composition preserves
/// proofs; the pointwise composition law `ESCAPE_TABLE[i] ==
/// (ESCAPE_SOURCES[i], ESCAPE_DECODED[i])` is a load-bearing
/// structural invariant carrying the two-column composition
/// relation between the paired SPAN and its two column-dual peer
/// SPANs. A refactor that drifted any of the three arrays'
/// declaration orders (paired SPAN, SOURCE-column SPAN, DECODED-
/// column SPAN) OR drifted `decode_str_escape`'s match-arm
/// ordering surfaces at the first drifted index across the three
/// pointwise composition pins.
pub const ESCAPE_TABLE: [(char, char); 5] = [
Self::NAMED_ESCAPE_TABLE[0],
Self::NAMED_ESCAPE_TABLE[1],
Self::NAMED_ESCAPE_TABLE[2],
(Self::SELF_ESCAPE_TABLE[0], Self::SELF_ESCAPE_TABLE[0]),
(Self::SELF_ESCAPE_TABLE[1], Self::SELF_ESCAPE_TABLE[1]),
];
#[must_use]
/// A string payload as source text, quoted and escaped so that
/// [`Self::decode_str_escape`] (plus the reader's `\u{…}` arm) reads back
/// exactly these bytes.
///
/// The inverse of the reader, deliberately written as one: anything the
/// reader cannot decode is emitted as `\u{…}` rather than as a shorter
/// escape that would mean something different.
#[must_use]
pub fn escape_str_payload(s: &str) -> String {
let mut out = String::with_capacity(s.len() + 2);
out.push(Self::STR_DELIMITER);
for c in s.chars() {
match c {
Self::STR_DELIMITER | Self::STR_ESCAPE_LEAD => {
out.push(Self::STR_ESCAPE_LEAD);
out.push(c);
}
Self::NEWLINE_ESCAPE_DECODED => {
out.push(Self::STR_ESCAPE_LEAD);
out.push(Self::NEWLINE_ESCAPE_SOURCE);
}
Self::TAB_ESCAPE_DECODED => {
out.push(Self::STR_ESCAPE_LEAD);
out.push(Self::TAB_ESCAPE_SOURCE);
}
Self::CARRIAGE_RETURN_ESCAPE_DECODED => {
out.push(Self::STR_ESCAPE_LEAD);
out.push(Self::CARRIAGE_RETURN_ESCAPE_SOURCE);
}
// Everything else the reader cannot round-trip literally goes
// out as `\u{…}`, which it CAN. Printable characters — including
// every non-ASCII one — are emitted raw, so ordinary text stays
// readable.
c if c.is_control() => {
out.push_str("\\u{");
out.push_str(&alloc_hex(c as u32));
out.push('}');
}
c => out.push(c),
}
}
out.push(Self::STR_DELIMITER);
out
}
pub const fn decode_str_escape(esc: char) -> char {
match esc {
Self::NEWLINE_ESCAPE_SOURCE => Self::NEWLINE_ESCAPE_DECODED,
Self::TAB_ESCAPE_SOURCE => Self::TAB_ESCAPE_DECODED,
Self::CARRIAGE_RETURN_ESCAPE_SOURCE => Self::CARRIAGE_RETURN_ESCAPE_DECODED,
Self::STR_DELIMITER => Self::STR_DELIMITER,
Self::STR_ESCAPE_LEAD => Self::STR_ESCAPE_LEAD,
other => other,
}
}
/// Canonical [`Self::Symbol`] constructor — first of the six per-
/// variant typed-construct methods on the closed-set [`Atom`]
/// algebra. Takes `impl Into<String>` so the consumer composes any
/// `&str` / `String` / `Cow<'_, str>` into the typed payload without
/// pre-coercing at its site — the `.into()` boundary lives at this
/// method on the algebra, parallel to how the [`Sexp`] outer
/// constructors ([`Sexp::symbol`], [`Sexp::keyword`],
/// [`Sexp::string`]) accept the same `impl Into<String>` shape at
/// the outer algebra layer.
///
/// Sibling typed-construct family on the closed-set [`Atom`]
/// algebra — paired section-for-retraction with the soft-projection
/// family ([`Self::as_symbol`], [`Self::as_keyword`],
/// [`Self::as_string`], [`Self::as_int`], [`Self::as_float`],
/// [`Self::as_bool`]). Pre-lift the typed-construct family was
/// missing from the algebra: consumers reached for the bare
/// `Self::Symbol(s.into())` tuple-variant constructor + `.into()`
/// coercion at every site (with no `impl Into` ergonomy on the
/// algebra), AND the soft-projection family had no constructor
/// peer — section-for-retraction was uneven. Post-lift every
/// consumer that builds an [`Atom`] from a typed payload at one
/// site AND projects an [`Atom`] back to its typed payload at
/// another binds to ONE method per direction on the algebra. The
/// six [`Sexp`] outer constructors ([`Sexp::symbol`] through
/// [`Sexp::boolean`]) route through `Self::Atom(Atom::X(_))` —
/// `.into()` ergonomy on the inner algebra is reused at the outer
/// algebra without re-derivation.
///
/// Round-trip law binding it to the soft-projection sibling: for
/// every `s: &str`, `Atom::symbol(s).as_symbol() == Some(s)` —
/// every other arm projects to `None`. Same posture across the
/// five sibling pairs (`Atom::keyword(s).as_keyword() == Some(s)`,
/// …). The `kind()` projection ([`Self::kind`]) similarly
/// round-trips through the construct face: `Atom::symbol(_).kind()
/// == AtomKind::Symbol`.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle;
/// every consumer that constructs an [`Atom`] of a typed kind binds
/// to ONE typed method on the algebra rather than to the bare
/// tuple-variant constructor + per-site `.into()` coercion.
/// THEORY.md §V.1 — knowable platform; the `(AtomKind variant,
/// typed construct method)` pair becomes a TYPE projection on the
/// substrate's [`Atom`] algebra. THEORY.md §VI.1 — generation over
/// composition; the `[Sexp; 6]` outer constructors at
/// [`Sexp::symbol`]–[`Sexp::boolean`] regenerate identically
/// through `Self::Atom(Atom::X(_))` composition rather than
/// re-deriving the `.into()` + tuple-variant pair per outer
/// constructor.
///
/// Frontier inspiration: Racket's `(symbol 'x)` / `(string s)` —
/// the typed-construct face the consumer reaches for a typed
/// atomic value paired one-for-one with `(symbol? v)` /
/// `(symbol->string v)` predicate/projection siblings; the
/// substrate's [`Self::symbol`] / [`Self::as_symbol`] pair is the
/// Rust-typed peer on the closed-set [`Atom`] algebra, with
/// `impl Into<String>` standing in for Racket's typed-pair coerce
/// face. MLIR's `mlir::SymbolAttr::get(ctx, name)` — typed-IR
/// attribute construction routes through ONE typed factory paired
/// with `mlir::dyn_cast<SymbolAttr>(attr)` on the projection face;
/// `Atom::symbol` is the substrate's unstructured-Rust peer.
#[must_use]
pub fn symbol(s: impl Into<String>) -> Self {
Self::Symbol(s.into())
}
/// Canonical [`Self::Keyword`] constructor — second of the six
/// per-variant typed-construct methods on the closed-set [`Atom`]
/// algebra. See [`Self::symbol`] for the algebra-level docstring.
#[must_use]
pub fn keyword(s: impl Into<String>) -> Self {
Self::Keyword(s.into())
}
/// Canonical [`Self::Str`] constructor — third of the six per-variant
/// typed-construct methods. The method name is `string` for
/// consumer-vocabulary continuity with [`Self::as_string`] /
/// [`Sexp::string`] / [`crate::error::SexpShape::String`] (the typed
/// payload variant is `Str` for `String` shortening; the consumer-
/// facing method keeps `string` for symmetry).
#[must_use]
pub fn string(s: impl Into<String>) -> Self {
Self::Str(s.into())
}
/// Canonical [`Self::Int`] constructor — fourth of the six per-variant
/// typed-construct methods. The `i64` is taken by value (no
/// `impl Into<…>` widening) — strict typed identity at the algebra
/// boundary, the same posture [`Self::as_int`] preserves on the
/// soft-projection face (`Atom::Int(n)` projects to `Some(n)` only;
/// the `Sexp::as_float` consumer is where Int→Float widening lives).
#[must_use]
pub fn int(n: i64) -> Self {
Self::Int(n)
}
/// Canonical [`Self::Float`] constructor — fifth of the six
/// per-variant typed-construct methods. The `f64` is taken by value
/// (no `impl Into<…>` widening), matching [`Self::int`]'s strict
/// typed-identity posture at the algebra boundary.
#[must_use]
pub fn float(n: f64) -> Self {
Self::Float(n)
}
/// Canonical [`Self::Bool`] constructor — sixth and last of the six
/// per-variant typed-construct methods on the closed-set [`Atom`]
/// algebra. Together with the five siblings ([`Self::symbol`],
/// [`Self::keyword`], [`Self::string`], [`Self::int`],
/// [`Self::float`]) the per-`Atom`-variant typed-construct family is
/// complete across all six closed-set arms, and pairs section-for-
/// retraction with the soft-projection family ([`Self::as_symbol`],
/// [`Self::as_keyword`], [`Self::as_string`], [`Self::as_int`],
/// [`Self::as_float`], [`Self::as_bool`]) — every consumer that
/// constructs an [`Atom`] from a typed payload at one site AND
/// projects an [`Atom`] back to its typed payload at another binds
/// to ONE method per direction on the algebra rather than to the
/// bare tuple-variant constructor + the soft-projection method
/// asymmetrically.
///
/// The closed-set `bool` payload's Scheme-canonical `#t` / `#f`
/// reader lexemes are dispatched at [`Self::from_lexeme`] (the
/// typed-ENTRY classifier) — this method is the construction face
/// the consumer composes the typed `bool` value into when building
/// an [`Atom`] from already-typed Rust, parallel to how
/// [`Self::int`] and [`Self::float`] take their typed payload by
/// value.
#[must_use]
pub fn boolean(b: bool) -> Self {
Self::Bool(b)
}
/// Project the atomic value into its closed-set [`AtomKind`] marker —
/// `Symbol(_) → AtomKind::Symbol`, `Keyword(_) → AtomKind::Keyword`,
/// `Str(_) → AtomKind::Str`, `Int(_) → AtomKind::Int`,
/// `Float(_) → AtomKind::Float`, `Bool(_) → AtomKind::Bool`. The
/// projection discards the payload and surfaces the typed
/// discriminator that every per-atom-kind dispatch site (Hash cache-
/// key bytes via [`AtomKind::hash_discriminator`], outer-shape
/// projection via [`AtomKind::sexp_shape`], diagnostic label via
/// [`AtomKind::label`]) keys on.
///
/// Soft-projection peer of [`Sexp::as_quote_form`]: where
/// `as_quote_form` decomposes the four homoiconic prefix wrappers
/// into `(QuoteForm, &Sexp)`, `kind` decomposes the six atomic
/// payloads into `AtomKind` alone — there is no inner-sexp body to
/// surface, so the projection's return type is just the marker.
/// Sibling-arm sweep with the quote-family `as_quote_form` /
/// `QuoteForm` algebra lifts the (Atom variant, byte-discriminator,
/// canonical-label, SexpShape variant) quadruple from per-callsite
/// discipline (`Hash for Atom`'s six byte literals AND
/// `domain::sexp_shape`'s six SexpShape literals) onto ONE typed
/// algebra the substrate's diagnostic + cache-key surfaces both
/// route through.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Atom variant, downstream-consumer-payload) pairing now binds at
/// ONE typed projection site (this method composed with
/// [`AtomKind`]'s arms) regardless of which consumer surface
/// (cache-key Hash, diagnostic SexpShape, future LSP completion
/// label) needs it. A regression that drifts ONE consumer's pairing
/// from the others cannot reach the substrate's runtime.
#[must_use]
pub fn kind(&self) -> AtomKind {
match self {
Self::Symbol(_) => AtomKind::Symbol,
Self::Keyword(_) => AtomKind::Keyword,
Self::Str(_) => AtomKind::Str,
Self::Int(_) => AtomKind::Int,
Self::Float(_) => AtomKind::Float,
Self::Bool(_) => AtomKind::Bool,
}
}
/// Project the atomic payload to its canonical `&'static str`
/// diagnostic label — `"symbol"` for [`Self::Symbol`], `"keyword"`
/// for [`Self::Keyword`], `"string"` for [`Self::Str`], `"int"` for
/// [`Self::Int`], `"float"` for [`Self::Float`], `"bool"` for
/// [`Self::Bool`]. The outer-`Atom` peer on the [`Atom`] algebra of
/// [`AtomKind::label`] (the marker-level label projection on the
/// closed-set atomic-kind algebra) and [`crate::ast::Sexp::type_name`]
/// (the outer-value label projection on the [`crate::ast::Sexp`]
/// algebra composed through [`crate::ast::Sexp::shape`] +
/// [`crate::error::SexpShape::label`]). Every label is byte-for-byte
/// identical to the corresponding [`crate::error::SexpShape`] variant's
/// label — the AtomKind ⊂ SexpShape label-vocabulary containment
/// established by [`AtomKind::label`]'s composition through
/// [`AtomKind::sexp_shape`] surfaces at the outer-`Atom` layer through
/// this projection.
///
/// Composition law: `atom.label() == atom.kind().label() ==
/// atom.kind().sexp_shape().label()` for every `atom: &Atom`. The
/// body composes [`Self::kind`] (the typed projection lifting each
/// [`Atom`] variant into its peer [`AtomKind`] marker) with
/// [`AtomKind::label`] (the canonical `&'static str` projection on the
/// closed-set atomic-payload algebra), so the six atomic-arm labels
/// live at ONE canonical site ([`crate::error::SexpShape::label`]'s
/// atomic arms, via [`AtomKind::label`]'s composition through
/// [`AtomKind::sexp_shape`]) rather than at TWO
/// ([`crate::error::SexpShape::label`] AND a parallel six-arm match
/// on the outer [`Atom`] algebra, pre-lift). Cross-algebra agreement
/// law: `Sexp::Atom(atom.clone()).type_name() == atom.label()` for
/// every `atom: Atom` — the outer-[`crate::ast::Sexp`] label
/// projection at the atomic-payload arms routes through
/// [`crate::ast::Sexp::shape`]'s
/// `Self::Atom(a) => a.kind().sexp_shape()` arm which composes with
/// [`crate::error::SexpShape::label`] byte-for-byte with this
/// projection's `self.kind().label()` composition, so the (outer
/// `Sexp` label, outer `Atom` label) agreement is a TYPED CONSEQUENCE
/// of the two typed compositions rather than literal discipline at
/// two sites.
///
/// Sibling-shape lift to [`Self::kind`] (the closed-set atomic-kind
/// projection): where `kind()` carries the typed [`AtomKind`] marker
/// on the [`Atom`] algebra, `label()` carries the `&'static str`
/// literal the rendered diagnostic surface wants (still derived from
/// the typed marker, but flattened through [`AtomKind::label`] for
/// substring-grep callers, future
/// [`crate::error::LispError::TypeMismatch`] `got` slots keyed on an
/// atomic witness before the outer [`crate::ast::Sexp`] wrap, and
/// future LSP hover / REPL completion / audit-trail metric surfaces
/// that hold an [`Atom`] value directly rather than a wrapped
/// [`crate::ast::Sexp::Atom`]). The `&'static str` lifetime is
/// load-bearing: the composition allocates nothing at runtime
/// ([`Self::kind`] returns a `Copy` value and [`AtomKind::label`]
/// yields `&'static str`).
///
/// Pre-lift the (Atom variant, `&'static str` diagnostic label)
/// pairing had no typed projection on the outer-[`Atom`] algebra —
/// a consumer with a typed [`Atom`] in hand (a hand-authored
/// [`Atom`] value at a test-harness diagnostic, a future
/// [`crate::domain`] typed-kwarg gate that rejects on an atomic
/// witness before the outer [`crate::ast::Sexp`] wrap, a future LSP
/// hover surface that emits an atomic-payload identity without an
/// enclosing [`crate::ast::Sexp::Atom`] wrap, a future audit-trail
/// metric keyed on the observed atomic kind) wanting the canonical
/// diagnostic label had to spell the two-step composition
/// `atom.kind().label()` at every callsite, OR go through
/// [`crate::ast::Sexp::Atom(atom.clone()).type_name()`] which wraps
/// and unwraps for no runtime purpose. Post-lift the composition
/// binds at ONE typed-algebra method on the outer [`Atom`] value-
/// carrier — the SIXTH consumer of the outer-[`Atom`] projection
/// surface (sibling of [`Self::kind`], [`Self::to_json`],
/// `Atom::to_iac_forge_sexpr` (removed), [`Self::from_lexeme`], and the six
/// per-variant soft-projection methods [`Self::as_symbol`] /
/// [`Self::as_keyword`] / [`Self::as_string`] / [`Self::as_int`] /
/// [`Self::as_float`] / [`Self::as_bool`] + the composite
/// [`Self::as_symbol_or_string`]).
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (Atom
/// variant, `&'static str` diagnostic label) pairing becomes a TYPE
/// projection on the outer-[`Atom`] algebra rather than a per-
/// callsite `.kind().label()` two-step OR a wrap-through-Sexp
/// [`crate::ast::Sexp::Atom(atom.clone()).type_name()`] round-trip.
/// A typo or swap at the outer-`Atom` label site is no longer a
/// runtime label drift but a compile error against the typed
/// composition — the [`Atom`] ↔ [`AtomKind`] ↔ label chain is
/// rustc-enforced end-to-end. THEORY.md §II.1 invariant 2 — free
/// middle; the outer-[`Atom`] diagnostic-label projection now binds
/// at ONE site on the outer-`Atom` algebra, composing through the
/// pre-existing marker-level label projection ([`AtomKind::label`])
/// rather than duplicating the six-arm match. THEORY.md §VI.1 —
/// generation over composition; the outer-`Atom` label projection is
/// the missing algebra layer between the outer [`Atom`] value-carrier
/// and the pre-existing [`AtomKind`] marker-level label projection —
/// the three pre-existing typed layers ([`Atom`] → [`AtomKind`] →
/// [`crate::error::SexpShape`] → `&'static str`) become a full
/// four-layer typed composition through ONE new named projection on
/// the outer value-carrier.
///
/// Frontier inspiration: MLIR's `mlir::Attribute::getAbstractAttribute()
/// .getName()` typed projection composed with the attribute-kind's
/// typed string identity — narrowing an attribute-carrier value
/// through its typed kind identity yields the canonical diagnostic
/// string identity in ONE typed composition on the outer attribute
/// algebra. Translated through the substrate's outer-[`Atom`]
/// value-carrier algebra, `atom.kind().label()` closes the (outer
/// value, canonical diagnostic label) pairing at ONE typed projection
/// on the value-carrier algebra composed through the marker-level
/// diagnostic-label face. Racket's `(syntax-kind stx)` composed with
/// `(kind-label kind)` on the datum-kind taxonomy — the typed
/// diagnostic label emerges from a two-hop composition on the outer
/// datum-carrier through the typed kind identity. `Atom::label` is
/// the Rust-typed peer on the closed-set outer-[`Atom`] algebra with
/// [`AtomKind`] standing in for Racket's datum-kind taxonomy.
#[must_use]
pub fn label(&self) -> &'static str {
self.kind().label()
}
/// Project the atomic value into its outer-shape [`SexpShape`]
/// variant — `Symbol(_) → SexpShape::Symbol`,
/// `Keyword(_) → SexpShape::Keyword`, `Str(_) → SexpShape::String`,
/// `Int(_) → SexpShape::Int`, `Float(_) → SexpShape::Float`,
/// `Bool(_) → SexpShape::Bool`. The outer-value peer of
/// [`AtomKind::sexp_shape`] one algebra layer down and of
/// [`Sexp::shape`] one algebra layer up. Body composes through
/// `self.kind().sexp_shape()` — routing through [`Self::kind`]
/// (the typed 6-arm outer-value → marker projection) then
/// [`AtomKind::sexp_shape`] (the canonical 6-of-12 atomic-payload
/// carving of [`SexpShape`]) so the (Atom variant, SexpShape
/// variant) pairing lives at ONE canonical site
/// ([`AtomKind::sexp_shape`]'s six match arms in `ast.rs`) rather
/// than at six byte-identical inline arms across consumers.
///
/// Same composition-through-carving-marker posture as [`Self::label`]
/// (`self.kind().label()`) one vocabulary axis over on the
/// outer-`Atom` algebra: [`Self::label`] closes the diagnostic-label
/// axis, this method closes the outer-shape-projection axis, and
/// both compose through the SAME typed marker layer
/// ([`Self::kind`] into [`AtomKind`]) into the outer-shape's
/// per-axis canonical site. The two methods now paint the
/// outer-`Atom` value with typed projections onto BOTH the
/// diagnostic-label vocabulary AND the outer-shape closed-set —
/// the pair mirrors how [`Sexp::type_name`] and [`Sexp::shape`]
/// paint the outer-`Sexp` value one algebra layer up.
///
/// Composition law: `atom.sexp_shape() == atom.kind().sexp_shape()`
/// for every `atom: &Atom`. Pinned by
/// `atom_sexp_shape_composes_through_kind_sexp_shape_for_every_variant`
/// across a representative payload sweep (including NaN via
/// `f64::to_bits` round-trip on the Float arm, matching
/// [`Hash for Atom`]'s posture; both empty and non-empty
/// String/Symbol/Keyword arms; `i64::{MIN, MAX}` on the Int arm;
/// both Bool arms). Sibling of
/// `atom_label_composes_through_kind_label_for_every_variant` one
/// vocabulary axis over.
///
/// Cross-algebra agreement law: for every `atom: &Atom`,
/// `atom.sexp_shape() == Sexp::Atom(atom.clone()).shape()`. The
/// outer-`Atom` shape projection routes into the SAME canonical
/// site the outer-`Sexp` [`Sexp::shape`] projection lands on for
/// every atomic-payload arm — pinned by
/// `atom_sexp_shape_agrees_with_sexp_shape_at_every_atom_arm` via
/// byte-equality on the `SexpShape` variant across all six atomic
/// arms. Sibling of
/// `atom_label_agrees_with_sexp_type_name_at_every_atom_arm` one
/// vocabulary axis over.
///
/// Round-trip through the outer-shape's soft-projection sibling:
/// `atom.sexp_shape().as_atom_kind() == Some(atom.kind())` for
/// every `atom: &Atom` — the typed embed `Atom → AtomKind →
/// SexpShape` inverts through the soft-projection retraction
/// `SexpShape → AtomKind` exactly on the 6-of-12 atomic-payload
/// image. Pinned by
/// `atom_sexp_shape_round_trips_through_sexp_shape_as_atom_kind`.
///
/// The `SexpShape` return type (owned; [`SexpShape`] is not `Copy`
/// because its `Unknown(String)` arm carries a `String`) is the
/// outer-shape closed set; consumers that want the diagnostic
/// label render string compose `atom.sexp_shape().label()`, and
/// that composition IS `atom.label()` byte-for-byte by the
/// composition-through-carving-marker posture the two methods
/// share.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (outer
/// `Atom` variant, `SexpShape` variant) pairing becomes a TYPE
/// projection on the outermost atomic value-carrier algebra
/// composed through the pre-existing marker-level projection,
/// rather than at parallel inline match arms each future consumer
/// of the outer-shape from an outer-`Atom` value has to re-derive.
/// THEORY.md §II.1 invariant 2 — free middle; the outer-`Atom`
/// outer-shape algebra now closes over THREE typed layers (outer
/// `Atom` → [`AtomKind`] → [`SexpShape`]) with rustc-enforced
/// consistency across each — a regression that drifts ONE layer's
/// shape mapping from the others cannot reach the substrate's
/// runtime typed-witness surface, `LispError::TypeMismatch.got`
/// slot, or [`SexpWitness::shape`] projection. THEORY.md §VI.1 —
/// generation over composition; the outer-value projection is the
/// missing algebra layer between the outer `Atom` and the
/// pre-existing marker-level shape projection — the two
/// pre-existing typed layers become a full THREE-layer typed
/// composition through ONE new named projection.
///
/// Frontier inspiration: MLIR's `mlir::Attribute::getType()`
/// typed projection composed with the attribute-kind's typed
/// outer-type identity — narrowing an attribute-carrier value
/// through its typed kind identity yields the outer-type identity
/// in ONE typed composition on the outer attribute algebra.
/// Translated through the substrate's outer-`Atom` value-carrier
/// algebra, `atom.kind().sexp_shape()` closes the (outer value,
/// outer-shape) pairing at ONE typed projection on the value-
/// carrier algebra composed through the marker-level
/// outer-shape face.
#[must_use]
pub fn sexp_shape(&self) -> SexpShape {
self.kind().sexp_shape()
}
/// Stable, per-variant byte discriminator that paired with the
/// recursive payload hash builds the substrate's [`Hash for Atom`]
/// projection — `0u8` for [`Self::Symbol`], `1u8` for
/// [`Self::Keyword`], `2u8` for [`Self::Str`], `3u8` for
/// [`Self::Int`], `4u8` for [`Self::Float`], `5u8` for
/// [`Self::Bool`]. The outer-value peer on the [`Atom`] algebra of
/// [`AtomKind::hash_discriminator`] (the marker-level cache-key byte
/// projection on the closed-set atomic-kind algebra), sibling of
/// [`Self::label`] and [`Self::sexp_shape`] one vocabulary axis over
/// on the outer-`Atom` algebra. Body composes through
/// `self.kind().hash_discriminator()` — routing through [`Self::kind`]
/// (the typed 6-arm outer-value → marker projection) then
/// [`AtomKind::hash_discriminator`] (the canonical 6-arm cache-key
/// byte projection) so the (Atom variant, byte) pairing lives at
/// ONE canonical site ([`AtomKind::hash_discriminator`]'s six match
/// arms) rather than at six inline `<N>u8.hash(h)` arms at
/// [`Hash for Atom`]'s callsite.
///
/// Composition law: `atom.hash_discriminator() ==
/// atom.kind().hash_discriminator()` for every `atom: &Atom`. Pinned
/// by `atom_hash_discriminator_composes_through_kind_hash_discriminator_for_every_variant`
/// across a representative payload sweep (including NaN via
/// `f64::to_bits` round-trip on the Float arm, matching
/// [`Hash for Atom`]'s posture; both empty and non-empty
/// String/Symbol/Keyword arms; `i64::{MIN, MAX}` on the Int arm;
/// both Bool arms). Sibling of
/// `atom_label_composes_through_kind_label_for_every_variant` and
/// `atom_sexp_shape_composes_through_kind_sexp_shape_for_every_variant`
/// one vocabulary axis over.
///
/// Routing-identity law binding it to [`Hash for Atom`]'s post-lift
/// body: for every `atom: &Atom`, hashing via the impl produces
/// byte-identical output to a hand-driven
/// `atom.hash_discriminator().hash(h); <inner-payload-hash>`
/// sequence. Pinned by
/// `hash_for_atom_routes_atom_discriminator_through_atom_hash_discriminator`.
/// Sibling posture to
/// `hash_for_sexp_routes_outer_discriminator_through_sexp_hash_discriminator`
/// one algebra layer up — the two routing pins jointly enforce the
/// outer-value Hash bodies at BOTH algebras stay structurally
/// parallel (`self.hash_discriminator().hash(h); <inner>`).
///
/// `pub(crate)` because the byte-discriminator surface is an
/// implementation detail of the substrate's [`Hash for Atom`]
/// cache-key contract; exposing it publicly would leak the cache-key
/// shape through the API without enabling any external consumer the
/// public projections ([`Self::kind`], [`Self::label`],
/// [`Self::sexp_shape`]) don't already serve. Same posture as
/// [`AtomKind::hash_discriminator`] one algebra layer down and
/// [`crate::ast::Sexp::hash_discriminator`] one algebra layer up.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (outer
/// `Atom` variant, cache-key byte) pairing becomes a TYPE projection
/// on the outermost atomic value-carrier algebra composed through the
/// pre-existing marker-level projection, rather than a two-hop
/// composition at the [`Hash for Atom`] callsite. THEORY.md §II.1
/// invariant 2 — free middle; the outer-`Atom` cache-key algebra now
/// closes over THREE typed layers (outer `Atom` → [`AtomKind`] → byte)
/// with rustc-enforced consistency across each — a regression that
/// drifts the [`Hash for Atom`] callsite's byte routing from the
/// canonical [`AtomKind::hash_discriminator`] site cannot reach the
/// substrate's expansion-cache runtime. THEORY.md §VI.1 — generation
/// over composition; the outer-value byte projection is the missing
/// algebra layer between the outer `Atom` and the pre-existing
/// marker-level byte projection — the two pre-existing typed layers
/// become a full THREE-layer typed composition through ONE new named
/// projection on the outer value-carrier, closing the (label,
/// sexp_shape, hash_discriminator) trio on the outer-`Atom` algebra.
///
/// Frontier inspiration: MLIR's
/// `mlir::Attribute::getAsOpaquePointer()` typed projection composed
/// with the attribute-kind's stable identifier — narrowing an
/// attribute-carrier value through its typed kind identity yields the
/// canonical cache-key identity in ONE typed composition on the outer
/// attribute algebra. Translated through the substrate's
/// outer-[`Atom`] value-carrier algebra,
/// `atom.kind().hash_discriminator()` closes the (outer value, byte
/// cache-key discriminator) pairing at ONE typed projection on the
/// value-carrier algebra composed through the marker-level cache-key
/// face. Racket's `(datum-hash-key datum)` composed with
/// `(kind-hash-tag kind)` on the datum-kind taxonomy — the byte
/// cache-key identity emerges from a two-hop composition on the
/// outer datum-carrier through the typed kind identity;
/// `Atom::hash_discriminator` is the Rust-typed peer on the
/// closed-set outer-[`Atom`] algebra with [`AtomKind`] standing in
/// for Racket's datum-kind taxonomy.
#[must_use]
pub(crate) fn hash_discriminator(&self) -> u8 {
self.kind().hash_discriminator()
}
/// Project the atomic payload to its canonical [`serde_json::Value`]
/// rendering — the typed-algebra peer of [`fmt::Display for Atom`] at
/// the JSON-projection boundary. Lifts six inline atom arms inside
/// [`crate::domain::sexp_to_json`]'s outer match (one
/// `Sexp::Atom(Atom::<variant>(payload)) => JValue::<…>(…)` arm
/// per [`AtomKind`] variant) onto ONE typed-algebra method that
/// every consumer routes through. Sibling-shape lift to the prior
/// `Display for Atom` (the canonical-string rendering surface),
/// `Hash for Atom` (the cache-key bytes surface via
/// [`AtomKind::hash_discriminator`]), and the upcoming
/// `Atom::to_iac_forge_sexpr` (the canonical-SExpr rendering
/// surface, feature-gated `iac-forge`) — every per-`Atom`-variant
/// projection now binds at ONE method on the closed-set algebra
/// rather than at six inline arms inside its consumer.
///
/// Mapping (preserves the byte-identical pre-lift behavior at the
/// `sexp_to_json` callsite):
/// * [`Self::Symbol`] payload `s` → [`serde_json::Value::String`] of
/// `s` cloned (Symbols are enum discriminants — the JSON
/// deserializer reads them as the string-form variant tag).
/// * [`Self::Keyword`] payload `s` → [`serde_json::Value::String`]
/// of `":{s}"` (Keywords prefix with `:` in their canonical
/// wire-form; `json_to_sexp`'s inverse strips the prefix).
/// * [`Self::Str`] payload `s` → [`serde_json::Value::String`] of
/// `s` cloned.
/// * [`Self::Int`] payload `n` → [`serde_json::Value::Number`] of
/// `n` (lossless via `serde_json::Number::from(i64)`).
/// * [`Self::Float`] payload `n` → [`serde_json::Value::Number`] of
/// `n` IFF `n` is finite (NaN / ±∞ collapse to
/// [`serde_json::Value::Null`]; this is JSON's structural
/// inexpressibility of those f64 values, NOT a substrate
/// choice). The NaN/∞→Null branch is pinned at one test below
/// (`atom_to_json_float_nan_and_infinity_collapse_to_null`).
/// * [`Self::Bool`] payload `b` → [`serde_json::Value::Bool`] of
/// `b`.
///
/// Bidirectional contract anchored by tests in this module:
/// * `atom_to_json_projects_each_variant_to_canonical_json_value`
/// — sweeps a representative atom of each [`AtomKind`] variant
/// and pins each variant's canonical JValue mapping
/// byte-for-byte against the pre-lift inline rule, so a future
/// regression that drifts ONE arm (e.g. swaps `Symbol`'s
/// mapping to a Number, or drops `Keyword`'s `:` prefix) fails
/// loudly.
/// * `atom_to_json_float_nan_and_infinity_collapse_to_null`
/// — pins the JSON-structural inexpressibility branch at the
/// atom layer directly, so a future Atom-Display-style refactor
/// that bypasses [`serde_json::Number::from_f64`] (e.g. tries
/// to emit `NaN` as the string `"NaN"`) surfaces at the
/// typed-algebra boundary without requiring a Sexp wrap.
/// * `sexp_to_json_atom_arms_route_through_atom_to_json` (in
/// [`crate::domain::tests`]) — pins the lifted boundary:
/// `sexp_to_json(&Sexp::Atom(a.clone())) == Ok(a.to_json())`
/// for every atomic payload variant. Catches a future drift
/// where one surface's per-variant body changes without the
/// other.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition;
/// the (Atom variant, canonical JValue rendering) pair lived inline
/// at the `sexp_to_json` site as six byte-identical arms. The lift
/// retires the per-site fan-out onto ONE method on the `Atom`
/// algebra. THEORY.md §II.1 invariant 2 — free middle; the typed-
/// exit JSON projection, the Display-surface rendering, the
/// diagnostic surface, and any future canonical-form surface
/// (e.g. `Atom::to_iac_forge_sexpr`) all route through ONE
/// per-variant projection family rather than per-callsite
/// re-derivation. THEORY.md §V.1 — knowable platform; a future
/// seventh atomic kind (e.g. `Char` for `#\x` reader syntax) lands
/// at one [`AtomKind::ALL`] entry plus one arm here plus one arm
/// per sibling projection — exhaustively checked by the compiler,
/// not by per-consumer convention.
///
/// Frontier inspiration: MLIR's `mlir::AsmPrinter::printAttribute`
/// — the typed-IR attribute printer dispatches on the closed-set
/// `AttributeKind` so every printer body for a kind lives at ONE
/// implementation site; `Atom::to_json` is the unstructured-Rust
/// peer on the `Atom` algebra for the JSON canonical-form surface
/// (where `Display for Atom` is the Lisp-canonical-form peer and
/// `From<&Sexp> for iac_forge::SExpr` is the canonical-attestation-
/// form peer). Racket's `(syntax->datum stx)` then a serializer
/// over the datum prim — `to_json` is the substrate's serializer
/// at the atomic-payload layer, with the closed-set `AtomKind`
/// standing in for Racket's datum-prim taxonomy.
#[must_use]
pub fn to_json(&self) -> serde_json::Value {
match self {
Self::Symbol(s) => serde_json::Value::String(s.clone()),
// Keyword arm routes through the typed
// [`Self::keyword_qualified`] projection on the atomic-
// payload canonical-rendering axis — the ONE composition
// of [`Self::KEYWORD_MARKER`] with a bare keyword name on
// the [`Atom`] algebra, shared with
// `Atom::to_iac_forge_sexpr` (removed)'s Keyword arm and pinned
// byte-identical to [`fmt::Display for Atom`]'s Keyword
// arm. Pre-lift each of the three sites carried its own
// inline `format!("{}{s}", Self::KEYWORD_MARKER)`
// composition; post-lift the composition lives at ONE
// typed algebra projection.
Self::Keyword(s) => serde_json::Value::String(Self::keyword_qualified(s)),
Self::Str(s) => serde_json::Value::String(s.clone()),
Self::Int(n) => serde_json::Value::Number((*n).into()),
Self::Float(n) => serde_json::Number::from_f64(*n)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null),
Self::Bool(b) => serde_json::Value::Bool(*b),
}
}
/// Inverse of [`Self::to_json`] restricted to the JSON `Number`
/// discriminator — the ONE typed inverse projection on the closed-set
/// [`Atom`] algebra that names the (`serde_json::Number` →
/// [`Self::Int`] / [`Self::Float`]) bifurcation. Lifts the pre-lift
/// inline three-arm cascade inside [`crate::ast::Sexp::from_json`]'s
/// `serde_json::Value::Number(n)` outer-match arm — first
/// `n.as_i64()?` sink to [`Self::Int`] then `n.as_f64()?` sink to
/// [`Self::Float`] then a `Self::Int(0)` typed floor for the
/// structural-impossibility residual — onto ONE typed projection on
/// the [`Atom`] algebra so the paired FORWARD ([`Self::to_json`]'s
/// [`Self::Int`] / [`Self::Float`] arms) and INVERSE (this method)
/// numeric-axis projections live at ONE algebra layer.
///
/// Mapping (byte-identical to the pre-lift cascade in
/// [`crate::ast::Sexp::from_json`]):
///
/// | `serde_json::Number` shape | result |
/// | ---------------------------------- | ------------------ |
/// | `n.as_i64() == Some(i)` | [`Self::Int`]`(i)` |
/// | `n.as_i64() == None`, `.as_f64() == Some(f)` | [`Self::Float`]`(f)` |
/// | `n.as_i64() == None`, `.as_f64() == None` | [`Self::Int`]`(0)` — typed floor |
///
/// Every `serde_json::Number` today is either i64-fitting,
/// u64-fitting (projected through f64), or f64-fitting — the
/// `Int(0)` residual arm is a static-invariant statement that
/// `serde_json::Number`'s closed-set discriminator excludes the
/// "neither i64 nor f64" case in practice; the typed floor stays
/// explicit so a future `serde_json` extension does NOT silently
/// misroute through an unreachable-panic. The `Self::int(0)`
/// composition in the pre-lift code equalled `Self::Atom(Atom::Int(0))`
/// via the `Sexp::int` sugar; post-lift the [`Atom`] algebra owns
/// the typed floor at the atomic layer directly.
///
/// Round-trip laws (paired with [`Self::to_json`]'s numeric arms):
///
/// * For every `i: i64`, `Atom::from_json_number(&i.into()) ==
/// Atom::Int(i)` — the [`Self::Int`] → `JValue::Number` →
/// [`Self::Int`] round-trip is byte-identical.
/// * For every finite non-integer-valued `f: f64`,
/// `Atom::from_json_number(&serde_json::Number::from_f64(f)
/// .unwrap()) == Atom::Float(f)` — the [`Self::Float`] →
/// `JValue::Number` → [`Self::Float`] round-trip is byte-identical
/// for `f64` values that don't overlap the i64-fitting subset of
/// [`serde_json::Number`]'s discriminator (i.e. non-integer-valued
/// finite floats; integer-valued floats round-trip through the
/// [`Self::Int`] arm by `as_i64`'s eager check).
/// * Non-finite floats ([`f64::NAN`], [`f64::INFINITY`],
/// [`f64::NEG_INFINITY`]) collapse to [`serde_json::Value::Null`]
/// in [`Self::to_json`] — they NEVER produce a [`serde_json::Number`]
/// value, so the round-trip law does not apply to them. This
/// asymmetry is JSON's structural inexpressibility of non-finite
/// floats (pinned at
/// `atom_to_json_float_nan_and_infinity_collapse_to_null`), not a
/// substrate choice.
///
/// ONE consumer entrypoint the substrate binds against: the outer
/// [`crate::ast::Sexp::from_json`]'s `serde_json::Value::Number(n)`
/// arm was pre-lift a hand-rolled three-branch cascade
/// (`if let Some(i) = n.as_i64() { Self::int(i) } else if let
/// Some(f) = n.as_f64() { Self::float(f) } else { Self::int(0) }`);
/// post-lift the outer arm collapses to
/// `Self::Atom(Atom::from_json_number(n))` — the ONE typed inverse
/// on the [`Atom`] algebra owns the numeric-axis bifurcation, the
/// outer arm delegates. A regression that drifts the outer arm
/// (e.g. re-inlines the bifurcation and swaps the `as_i64`/`as_f64`
/// order so `42.0` sinks to [`Self::Float`] instead of
/// [`Self::Int`]) becomes structurally unreachable — there is
/// exactly ONE numeric decode both directions of the round-trip
/// consume.
///
/// Sibling-lift posture: this method mirrors [`Self::from_lexeme`]
/// on the typed-entry classification axis — that method decodes a
/// bare-atom lexeme (`&str`) into the six-way [`Atom`] taxonomy;
/// THIS method decodes a JSON `Number` into the two-way (
/// [`Self::Int`] / [`Self::Float`]) numeric subtaxonomy on the SAME
/// algebra. Together with the seven typed-EXIT projections on
/// [`Atom`] ([`fmt::Display for Atom`], [`Self::to_json`],
/// `Atom::to_iac_forge_sexpr` (removed), [`Self::label`],
/// [`Self::sexp_shape`], [`Self::hash_discriminator`],
/// [`Self::bool_literal`]) and the two typed-ENTRY projections on
/// [`Atom`] ([`Self::from_lexeme`], THIS method) the algebra's
/// canonical-form bidirectional sweep is complete across every
/// production-site rendering + parsing surface — every consumer's
/// (`Atom` variant, canonical rendering) OR (canonical source,
/// `Atom` variant) pairing binds at ONE method per direction per
/// surface on the closed-set algebra rather than at inline arms
/// scattered across per-consumer sites.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// (JSON `Number` → typed [`Atom`] numeric variant) projection IS
/// the typed-entry gate on the JSON numeric axis. Placing the
/// paired forward (`Atom::to_json`'s [`Self::Int`] / [`Self::Float`]
/// arms) AND inverse (THIS method) on the [`Atom`] algebra closes
/// the round-trip closure at ONE algebra layer — future numeric
/// taxonomy extensions (e.g. `u64`-fitting arm for the
/// `serde-preserve-order` feature's `arbitrary_precision` mode, a
/// [`Self::Bigint`] variant for arbitrary-precision integers, a
/// [`Self::Rational`] variant for [`num_rational::Rational64`])
/// extend the algebra ONCE at [`Self::to_json`]'s match AND ONCE at
/// this method's cascade — both edits land on the SAME algebra
/// rather than across the `Atom` module AND the `Sexp` module
/// boundary. THEORY.md §V.1 — knowable platform; the numeric
/// inverse projection becomes a NAMED primitive on the substrate's
/// [`Atom`] algebra rather than an inline three-arm cascade at the
/// `Sexp::from_json` consumer. THEORY.md §II.1 invariant 5 —
/// composition preserves proofs; the round-trip law
/// `Atom::from_json_number(&Atom::Int(n).to_json_as_number()) ==
/// Atom::Int(n)` (pinned at
/// `atom_from_json_number_round_trips_atom_to_json_int_arm`) is a
/// coherence proof BETWEEN the paired projections on ONE algebra —
/// a regression that drifts either side surfaces at the pin
/// rather than as a silent Sexp ↔ JSON round-trip drift.
///
/// Frontier inspiration: MLIR's `mlir::parseAttribute(str, ctx)` —
/// the typed-IR parser inverse of `printAttribute` lives on the
/// SAME `Attribute` algebra as its printer dual; the substrate's
/// [`Self::from_json_number`] is the unstructured-Rust peer on the
/// [`Atom`] algebra for the JSON-numeric canonical-form inverse,
/// paired with [`Self::to_json`]'s numeric arms as the closed
/// numeric-axis round-trip. Racket's
/// `(json->racket (racket->json v))` numeric identity — the
/// round-trip law that a JSON-projected numeric datum recovers to
/// its source Racket numeric primitive; THIS method's round-trip
/// pins are the Rust-typed peer on the [`Atom`] algebra with the
/// closed-set numeric taxonomy ([`Self::Int`] / [`Self::Float`])
/// standing in for Racket's numeric tower.
#[must_use]
pub fn from_json_number(n: &serde_json::Number) -> Self {
if let Some(i) = n.as_i64() {
Self::Int(i)
} else if let Some(f) = n.as_f64() {
Self::Float(f)
} else {
Self::Int(0)
}
}
// REMOVED (consolidation phase 2 step 8): `Atom::to_iac_forge_sexpr`
// and the `crate::interop` module it mirrored. Both were gated on a
// `iac-forge` Cargo feature this crate never declared, against an
// `iac_forge` dependency it never had — unconditionally dead, and
// uncompilable had the gate ever opened. Re-introducing the bridge
// needs a crates.io-published `iac-forge` first; see
// TATARA-LISP-CONSOLIDATION.md open question 7.
//
// NOT part of this deletion: the `iac_forge_tag` / `IAC_FORGE_TAGS`
// / `from_iac_forge_tag` family on `QuoteForm`, `SexpShape`,
// `UnquoteForm` and `Sexp`. Those are pure `&'static str` closed-set
// projections with no dependency on the `iac-forge` crate; they stay
// live and tested.
/// Classify a bare reader-token lexeme into its typed [`Atom`]
/// variant — the typed-ENTRY mirror of the three typed-EXIT
/// projections on the [`Atom`] algebra ([`fmt::Display for Atom`],
/// [`Self::to_json`], `Atom::to_iac_forge_sexpr` (removed)). Lifts the
/// five-statement classification cascade that lived inline at the
/// reader's private `atom_from_str` helper onto ONE typed-algebra
/// method on the closed-set [`Atom`] algebra; the reader's
/// `Token::Atom(s)` arm collapses to `Sexp::Atom(Atom::from_lexeme(&s))`.
/// Completes the bidirectional sweep across the four production-site
/// per-`Atom`-variant projection shapes (typed-exit Display, JSON,
/// iac-forge canonical attestation, AND now typed-entry
/// classification) onto the algebra.
///
/// Classification rule (byte-identical to the pre-lift reader
/// `atom_from_str` cascade):
/// 1. `"#t"`/`"#f"` → [`Self::Bool`] — the Scheme bool spellings;
/// bare `true`/`false` re-read as [`Self::Symbol`] (the
/// CLAUDE.md "Lisp bools" warning — every `:values-overlay`
/// payload depends on this for `Value::Bool` round-trip).
/// 2. `:foo` (leading `:`) → [`Self::Keyword`] — strips the `:`
/// so the inverse [`fmt::Display`] rule (`Keyword(s) →
/// ":{s}"`) round-trips.
/// 3. `i64::from_str` succeeds → [`Self::Int`] — load-bearing
/// ORDERING: tried BEFORE `f64` so `"1"` classifies as
/// [`Self::Int`]`(1)`, NOT [`Self::Float`]`(1.0)`. Typed-int-
/// vs-typed-float distinction at the Display→read boundary
/// is the dual of `fmt_float`'s `.0`-suffix discipline.
/// 4. `f64::from_str` succeeds → [`Self::Float`].
/// 5. Default → [`Self::Symbol`].
///
/// Composition laws (pinned by tests below):
/// * `Atom::from_lexeme(&a.to_string()) == a` for every variant
/// EXCEPT [`Self::Str`] (Display renders Str with quote marks
/// — strings take the reader's `"`-quoted tokenizer branch,
/// NOT the bare-atom branch).
/// * `read(s)` for every canonical bare-atom source lexeme
/// equals `vec![Sexp::Atom(Atom::from_lexeme(s))]` (pinned by
/// `reader_atom_token_arm_routes_through_atom_from_lexeme_for_
/// every_kind` in [`crate::reader::tests`]).
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry;
/// `atom_from_str` was the typed-entry gate as a free function in
/// `reader.rs`, outside the typed `Atom` algebra. Naming it on the
/// algebra brings the typed-entry side INTO the same closed-set
/// match family the typed-exit projections live on, so a future
/// seventh atomic kind (e.g. `Char` for `#\x` reader syntax) lands
/// at ONE [`AtomKind::ALL`] entry plus ONE arm here plus ONE arm
/// per typed-exit projection — exhaustively checked by rustc
/// across all FOUR per-variant projection families. THEORY.md
/// §II.1 invariant 2 — free middle; FOUR consumers (typed-entry
/// classification, Display rendering, JSON projection, canonical-
/// attestation-form projection) now route through ONE
/// per-`Atom`-variant projection family on the closed-set algebra.
/// THEORY.md §VI.1 — generation over composition; this lift
/// completes the bidirectional sweep across the four production
/// surfaces the prior runs in this series named.
///
/// Frontier inspiration: Racket's `(read-syntax …)` dispatches a
/// bare-atom lexeme through a closed-set classifier keyed on
/// prefix + parse-as-numeric cascade; `Atom::from_lexeme` is the
/// substrate's typed-Rust peer, with [`AtomKind`] standing in for
/// Racket's datum-prim taxonomy. MLIR's
/// `mlir::AsmParser::parseAttribute` dispatches on the closed-set
/// `AttributeKind` so every parser body for a kind lives at ONE
/// implementation site; `Atom::from_lexeme` is the
/// unstructured-Rust peer on the [`Atom`] algebra for the
/// typed-entry classification surface.
#[must_use]
pub fn from_lexeme(s: &str) -> Self {
if s == Self::bool_literal(true) {
return Self::Bool(true);
}
if s == Self::bool_literal(false) {
return Self::Bool(false);
}
if let Some(rest) = s.strip_prefix(Self::KEYWORD_MARKER) {
return Self::Keyword(rest.to_owned());
}
if let Ok(n) = s.parse::<i64>() {
return Self::Int(n);
}
if let Ok(n) = s.parse::<f64>() {
return Self::Float(n);
}
Self::Symbol(s.to_owned())
}
/// Soft projection onto the [`Self::Symbol`] payload — `Some(&str)`
/// iff this is a [`Self::Symbol`] variant, `None` for every other
/// atomic kind (`Keyword`, `Str`, `Int`, `Float`, `Bool`).
///
/// FIRST of the six per-variant soft-projection methods on the typed
/// [`Atom`] algebra — the typed-EXIT *soft*-projection peer of the
/// typed-EXIT canonical-form projections ([`fmt::Display for Atom`],
/// [`Self::to_json`], `Atom::to_iac_forge_sexpr` (removed)) and the typed-ENTRY
/// classifier ([`Self::from_lexeme`]). Where the canonical-form trio
/// projects the atomic payload to a *rendered* canonical surface
/// (string / JSON / iac-forge SExpr) and the classifier projects a
/// lexeme to the typed `Atom`, this method projects the typed `Atom`
/// to its inner payload — the soft-decomposition face of the closed
/// set, completing the algebra surface across BOTH bidirectional axes
/// (canonical-form rendering + classification on the typed-ENTRY/
/// typed-EXIT axis; soft decomposition on the typed-EXIT side at the
/// payload axis).
///
/// Sibling soft-projection peer of [`Sexp::as_quote_form`]: where
/// `as_quote_form` soft-decomposes the four homoiconic prefix
/// wrappers into `Option<(QuoteForm, &Sexp)>`, this method (and its
/// five `as_*` siblings on [`Atom`]) soft-decompose the six atomic
/// payloads into `Option<&str>` / `Option<i64>` / `Option<f64>` /
/// `Option<bool>` — there is no inner-sexp body to surface, so the
/// projection's return type is just the payload. The
/// `Sexp::as_symbol` consumer at the `Sexp` algebra layer composes
/// this projection with [`Sexp::as_atom`] (the structural lift to
/// the inner [`Atom`]) — `Sexp::as_symbol(self) ==
/// self.as_atom().and_then(Atom::as_symbol)` — so the per-`Atom`-
/// variant soft-projection binds at ONE method on the typed algebra
/// rather than at six inline `Self::Atom(Atom::X(s)) => Some(s)` arms
/// inside the `Sexp` consumer.
///
/// Lifts the inline `Self::Atom(Atom::Symbol(s)) => Some(s)` arm at
/// [`Sexp::as_symbol`]'s match body onto ONE typed-algebra projection
/// the `Sexp` consumer routes through via the structural lift
/// [`Sexp::as_atom`]. Sibling-shape lift to the typed-EXIT
/// canonical-form projections (`Display for Atom`, `Atom::to_json`,
/// `Atom::to_iac_forge_sexpr`) and the typed-ENTRY classifier
/// (`Atom::from_lexeme`) — every per-`Atom`-variant projection
/// across both the rendering surfaces AND the soft-decomposition
/// surface now binds at ONE method on the closed-set algebra rather
/// than at inline arms inside its consumer.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Atom variant, downstream-consumer-payload) pairing now binds at
/// ONE typed projection per consumer surface (six canonical-form
/// surfaces — `Display`, JSON, iac-forge, plus the soft-projection
/// FAMILY this method opens), regardless of which consumer reaches
/// in. THEORY.md §VI.1 — generation over composition; the six inline
/// `Self::Atom(Atom::X(s)) => Some(_)` arms at `Sexp::as_X` sites
/// (well past the ≥2 PRIME-DIRECTIVE trigger once the structural
/// shape is named) collapse onto the closed-set `Atom` algebra so a
/// future seventh atomic kind (e.g. `Char` for `#\x` reader syntax,
/// `Bigint` for arbitrary-precision integers) extends `Atom::ALL` +
/// the per-variant soft-projection method ONCE and rustc enforces
/// matching across every consumer through the closed-set match.
/// THEORY.md §V.1 — knowable platform; the (Atom variant, payload)
/// pairing becomes a TYPE projection on the substrate algebra
/// rather than six inline arms at the `Sexp` consumer. A typo or
/// swap at the soft-projection site is no longer a runtime drift
/// but a compile error against the typed projection.
///
/// Frontier inspiration: Racket's `(symbol? v)` / `(symbol->string
/// v)` pair — the typed-predicate + typed-projection pair at the
/// atomic-payload layer; this method (and its five `as_*` siblings)
/// is the substrate's typed soft-projection peer on the closed-set
/// `Atom` algebra, with `Option<&str>` standing in for the
/// predicate-AND-projection pair Racket carries as two functions.
/// MLIR's `mlir::dyn_cast<SymbolAttribute>(attr)` — the typed-IR
/// soft-downcast onto a closed-set attribute family; `Atom::as_symbol`
/// is the unstructured-Rust peer on the `Atom` algebra for the
/// soft-projection face, with the closed-set `AtomKind` standing in
/// for MLIR's `AttributeKind` taxonomy.
#[must_use]
pub fn as_symbol(&self) -> Option<&str> {
match self {
Self::Symbol(s) => Some(s),
_ => None,
}
}
/// Soft projection onto the [`Self::Keyword`] payload — `Some(&str)`
/// iff this is a [`Self::Keyword`] variant, `None` for every other
/// atomic kind. The returned `&str` is the payload AFTER the `:`
/// prefix has been stripped at the typed-ENTRY classifier
/// boundary ([`Self::from_lexeme`] strips `:` when constructing a
/// `Keyword`; this projection surfaces the bare identifier).
/// SECOND of the six per-variant soft-projection methods on the
/// typed [`Atom`] algebra — see [`Self::as_symbol`] for the
/// algebra-level docstring.
#[must_use]
pub fn as_keyword(&self) -> Option<&str> {
match self {
Self::Keyword(s) => Some(s),
_ => None,
}
}
/// Soft projection onto the [`Self::Str`] payload — `Some(&str)` iff
/// this is a [`Self::Str`] variant (the typed `"…"`-quoted string
/// literal payload at the reader's [`crate::reader::Token::Str`]
/// branch), `None` for every other atomic kind. THIRD of the six
/// per-variant soft-projection methods — named `as_string` at the
/// `Sexp` consumer for consumer-vocabulary continuity with the
/// pre-lift `Sexp::as_string` projection (the typed payload variant
/// is `Str` for `String` shortening; the consumer-facing method
/// keeps `string` for symmetry with the `ExpectedKwargShape::String`
/// label and the [`SexpShape::String`] outer-shape marker).
#[must_use]
pub fn as_string(&self) -> Option<&str> {
match self {
Self::Str(s) => Some(s),
_ => None,
}
}
/// Soft projection onto the [`Self::Int`] payload — `Some(i64)` iff
/// this is a [`Self::Int`] variant, `None` for every other atomic
/// kind. FOURTH of the six per-variant soft-projection methods.
/// The `i64` is returned by value (the payload is `Copy`); contrast
/// with [`Self::as_symbol`] / [`Self::as_keyword`] / [`Self::as_string`]
/// which borrow the underlying `String` payload as `&str` because
/// `String` is not `Copy`.
///
/// Strict typed identity: this method projects `Atom::Int(n)` to
/// `Some(n)` only. The `Sexp::as_float` consumer at the `Sexp`
/// algebra layer widens `Int` to `Float` (`Atom::Int(n) → Some(n as
/// f64)`) for caller convenience at the numeric-kwarg boundary; the
/// `Atom`-level projection here stays strict so the typed-identity
/// distinction `Int(1)` vs `Float(1.0)` (the load-bearing typed
/// identity at the [`Self::from_lexeme`] ⇄ Display round-trip
/// boundary, dual of [`fmt_float`]'s `.0`-suffix discipline) is
/// preserved at the algebra layer. The widening lives at the
/// `Sexp::as_float` consumer (`a.as_float().or_else(|| a.as_int()
/// .map(|n| n as f64))`) where the convenience is wanted, not at
/// the algebra-level projection where the typed identity is
/// load-bearing.
#[must_use]
pub fn as_int(&self) -> Option<i64> {
match self {
Self::Int(n) => Some(*n),
_ => None,
}
}
/// Soft projection onto the [`Self::Float`] payload — `Some(f64)`
/// iff this is a [`Self::Float`] variant, `None` for every other
/// atomic kind. FIFTH of the six per-variant soft-projection
/// methods.
///
/// Strict typed identity: `Atom::Int(n)` does NOT project through
/// this method (it stays `None`). The [`Sexp::as_float`] consumer
/// widens `Int` to `Float` at the `Sexp` algebra layer for caller
/// convenience; this algebra-level projection stays strict. See
/// [`Self::as_int`]'s docstring for the typed-identity contract.
#[must_use]
pub fn as_float(&self) -> Option<f64> {
match self {
Self::Float(n) => Some(*n),
_ => None,
}
}
/// Soft projection onto the [`Self::Bool`] payload — `Some(bool)`
/// iff this is a [`Self::Bool`] variant, `None` for every other
/// atomic kind. SIXTH and LAST of the six per-variant soft-projection
/// methods on the typed [`Atom`] algebra; together with the five
/// siblings ([`Self::as_symbol`], [`Self::as_keyword`],
/// [`Self::as_string`], [`Self::as_int`], [`Self::as_float`]) the
/// per-`Atom`-variant soft-projection family is complete across all
/// six closed-set arms. The CLAUDE.md-pinned `"#t"` / `"#f"` Scheme
/// bool spellings the reader's typed-ENTRY classifier
/// [`Self::from_lexeme`] dispatches on bind the lexeme → typed
/// [`Self::Bool`] direction; this method binds the typed
/// [`Self::Bool`] → payload direction at the soft-decomposition
/// face.
#[must_use]
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(b) => Some(*b),
_ => None,
}
}
/// Soft projection onto the *symbol-or-string* union — `Some(&str)` iff
/// this is a [`Self::Symbol`] variant OR a [`Self::Str`] variant, `None`
/// for every other atomic kind (`Keyword`, `Int`, `Float`, `Bool`).
/// The atomic-payload peer of [`Sexp::as_symbol_or_string`] —
/// disjunctive composition of [`Self::as_symbol`] + [`Self::as_string`]
/// at the typed [`Atom`] algebra rather than at the [`Sexp`] consumer
/// layer where the union previously composed two distinct
/// [`Sexp::as_atom`] traversals.
///
/// Sibling soft-projection peer of the six per-variant projections
/// ([`Self::as_symbol`], [`Self::as_keyword`], [`Self::as_string`],
/// [`Self::as_int`], [`Self::as_float`], [`Self::as_bool`]) — this
/// union projection completes the soft-decomposition family on the
/// closed-set [`Atom`] algebra by naming the (Symbol ⊎ Str) union
/// the substrate's named-form NAME gate ([`crate::compile::split_name_slot`]
/// via [`Sexp::as_symbol_or_string`]) keys on. Both NAME-author
/// surfaces (`(defcompiler my-name …)` — bare symbol; `(defcompiler
/// "my-name" …)` — quoted string) project to `Some("my-name")`
/// through one method on the algebra.
///
/// Composition law binding it to [`Sexp::as_symbol_or_string`]: for
/// every [`Sexp`] `s`,
/// `s.as_symbol_or_string() == s.as_atom().and_then(Atom::as_symbol_or_string)`
/// — the same structural-lift composition pattern [`Sexp::as_symbol`]
/// / [`Sexp::as_keyword`] / [`Sexp::as_string`] / [`Sexp::as_int`] /
/// [`Sexp::as_bool`] route through on the six per-variant axis.
/// Lifts the `self.as_symbol().or_else(|| self.as_string())`
/// disjunctive composition at [`Sexp::as_symbol_or_string`]'s body
/// (TWO `Sexp::as_atom` traversals pre-lift) onto ONE typed-algebra
/// projection the `Sexp` consumer routes through via the structural
/// lift [`Sexp::as_atom`] (ONE `Sexp::as_atom` traversal post-lift).
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Symbol ⊎ Str) union projection now binds at ONE method on the
/// closed-set [`Atom`] algebra regardless of which consumer reaches
/// in. THEORY.md §VI.1 — generation over composition; the
/// disjunctive `as_symbol().or_else(|| as_string())` composition at
/// [`Sexp::as_symbol_or_string`]'s body collapses onto a SINGLE
/// structural lift through [`Sexp::as_atom`] + the algebra-level
/// union projection, eliminating the double-traversal redundancy
/// the pre-lift consumer-layer composition carried. THEORY.md §V.1
/// — knowable platform; the (Symbol-or-Str) NAME-slot union becomes
/// a TYPE projection on the substrate algebra rather than a
/// disjunctive composition at every NAME-gate consumer.
///
/// Frontier inspiration: Racket's `(or/c symbol? string?)`
/// contract — a typed disjunctive predicate the consumer binds to
/// in one place rather than re-deriving the disjunction at every
/// callsite; [`Self::as_symbol_or_string`] is the substrate's
/// unstructured-Rust peer with the typed projection (`Option<&str>`)
/// surfacing the underlying payload alongside the predicate face.
/// MLIR's `mlir::dyn_cast<StringLike>(attr)` — typed soft-downcast
/// onto a closed-set attribute union; [`Self::as_symbol_or_string`]
/// is the substrate's [`Atom`]-algebra peer for the
/// (Symbol ⊎ Str) union, with `Option<&str>` standing in for MLIR's
/// typed downcast result.
#[must_use]
pub fn as_symbol_or_string(&self) -> Option<&str> {
self.as_symbol().or_else(|| self.as_string())
}
}
/// Closed-set typed discriminator for the six [`Atom`] payload variants —
/// `Symbol(String)`, `Keyword(String)`, `Str(String)`, `Int(i64)`,
/// `Float(f64)`, `Bool(bool)` — paired with the projections every
/// per-atom-kind consumer keys on ([`Self::hash_discriminator`] for
/// [`Hash for Atom`]'s cache-key bytes, [`Self::sexp_shape`] for
/// [`crate::domain::sexp_shape`]'s atom-arm collapse, [`Self::label`]
/// for the operator-facing diagnostic vocabulary, [`Self::FromStr`]
/// for the typed-inverse decode that lets LSP / REPL / metric-aggregator
/// consumers round-trip a rendered diagnostic label back into the typed
/// discriminator).
///
/// Atomic-payload peer of [`QuoteForm`] (the four homoiconic prefix
/// wrappers — `Sexp::{Quote, Quasiquote, Unquote, UnquoteSplice}`):
/// where `QuoteForm` carves the closed set on `Sexp`'s wrapper-variant
/// axis, `AtomKind` carves the closed set on `Sexp`'s atomic-payload
/// axis. Together the two closed-set discriminators cover every reachable
/// `Sexp` outermost shape except `Nil` and `List` (the structural
/// constructors `()` and `(…)`) — every other shape is either an
/// `Atom(_)` projecting through this enum's [`Self::sexp_shape`] arm or a
/// quote-family wrapper projecting through [`QuoteForm::sexp_shape`].
/// After this lift the two enums' [`Self::sexp_shape`] arms own ALL TEN
/// of [`SexpShape`]'s twelve canonical labels through ONE typed
/// composition each rather than through per-callsite arm-pairing in
/// [`crate::domain::sexp_shape`].
///
/// Mirror at the atomic-payload boundary of the prior-run [`QuoteForm`]
/// (homoiconic-prefix-wrapper closed set, 4 variants), the cross-crate
/// `tatara-process` closed-set family
/// (`ConditionKind::ALL`, `ProcessPhase::ALL`, `ProcessSignal::ALL`,
/// `ChannelKind::ALL`, `IntentKind::ALL`, `LifetimeKind::ALL`,
/// `RequestorKind::ALL`, `ReceiptKind::ALL`, …) and this crate's own
/// [`SexpShape`] (the twelve reachable Sexp outermost shapes — the
/// SUPERSET this enum projects into via [`Self::sexp_shape`]) and
/// [`UnquoteForm`] (the two template-substitution markers) closed-set
/// lifts: those enums key their respective rejection or projection
/// variants on a typed identity carried inside the variant's data shape;
/// this enum keys the SIX [`Atom`] payload variants on a typed
/// discriminator identity threaded through ALL THREE per-atom-kind
/// dispatch sites ([`Hash for Atom`]'s six byte literals,
/// [`crate::domain::sexp_shape`]'s six atom arms, AND the
/// diagnostic-label vocabulary [`SexpShape::label`] publishes for the
/// atom subset). Adding a hypothetical seventh atomic kind (e.g. a
/// `Char` literal for `#\x` reader syntax, a `Bigint` for arbitrary-
/// precision integers, a `Symbol2` for namespaced symbols) requires
/// extending this enum, which rustc-enforces matching at every
/// projection site ([`Self::label`], [`Self::hash_discriminator`],
/// [`Self::sexp_shape`], [`Atom::kind`], the [`Hash for Atom`] inner
/// match, and the [`Self::FromStr`] sweep keyed on [`Self::ALL`]) — the
/// closed set becomes a TYPE rather than six `&'static str` / `u8`
/// / `SexpShape` literals that could drift independently across the
/// substrate's three per-atom-kind consumer surfaces.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// atomic-payload discriminator at a typed-entry rejection IS part of
/// the proof of WHAT the gate observed, and naming its closed-set
/// identity lifts the discriminator from per-site literal-pair
/// discipline (a byte at the Hash site, a SexpShape variant at the
/// `sexp_shape` site, a `&'static str` at any future LSP completion
/// site) to ONE typed enum the substrate's diagnostic + cache-key
/// surfaces both bind against. THEORY.md §II.1 invariant 2 — free
/// middle; THREE consumers ([`Hash for Atom`],
/// [`crate::domain::sexp_shape`], and the future diagnostic /
/// completion surface) route through ONE typed closed-set match
/// family, so a regression that drifts ONE consumer's pairing from the
/// others cannot reach the substrate's runtime. THEORY.md §V.1 —
/// knowable platform; the closed set of atomic payload kinds becomes a
/// TYPE rather than six byte literals (Hash) + six SexpShape literals
/// (`sexp_shape`) scattered across distinct files — a typo in any one
/// site is no longer a runtime drift but a compile error against the
/// typed projection. THEORY.md §VI.1 — generation over composition;
/// the (Atom variant, label, discriminator-byte, SexpShape variant)
/// quadruple appeared inline at THREE sites (`Hash for Atom`'s six
/// byte arms, `domain::sexp_shape`'s six atom arms, plus implicit
/// pairing across `SexpShape::label`'s six atom-subset arms) — well
/// past the ≥2 PRIME-DIRECTIVE trigger once the structural shape is
/// named.
#[derive(Debug, Clone, Copy, PartialEq, Eq, tatara_closed_set::DeriveClosedSet)]
#[closed_set(via = "label", display, generate_unknown = "atom kind")]
pub enum AtomKind {
/// `Atom::Symbol(_)` — `"symbol"` diagnostic label, byte `0u8`
/// hash discriminator, projects to [`SexpShape::Symbol`].
Symbol,
/// `Atom::Keyword(_)` — `"keyword"` diagnostic label, byte `1u8`
/// hash discriminator, projects to [`SexpShape::Keyword`].
Keyword,
/// `Atom::Str(_)` — `"string"` diagnostic label, byte `2u8` hash
/// discriminator, projects to [`SexpShape::String`].
Str,
/// `Atom::Int(_)` — `"int"` diagnostic label, byte `3u8` hash
/// discriminator, projects to [`SexpShape::Int`].
Int,
/// `Atom::Float(_)` — `"float"` diagnostic label, byte `4u8` hash
/// discriminator, projects to [`SexpShape::Float`].
Float,
/// `Atom::Bool(_)` — `"bool"` diagnostic label, byte `5u8` hash
/// discriminator, projects to [`SexpShape::Bool`].
Bool,
}
impl AtomKind {
/// The closed set of six atomic [`Atom`] payload kinds — single
/// source of truth that drives every per-kind projection
/// ([`Self::label`] / [`fmt::Display`], [`Self::hash_discriminator`],
/// [`Self::sexp_shape`], and the [`Self::FromStr`] decode sweep
/// keyed on [`Self::label`]).
///
/// Adding a hypothetical seventh atomic kind (e.g. `Char` for
/// `#\x` reader syntax, `Bigint` for arbitrary-precision
/// integers) lands at one [`Self::ALL`] entry plus one arm per
/// projection — exhaustively checked by the compiler (the
/// `[Self; 6]` array literal forces the arity) AND by the
/// per-variant truth-table tests below.
///
/// Sibling closed-set lift to every other typed-shape enum the
/// substrate carries: this crate's own [`SexpShape::ALL`] (the
/// twelve reachable outer shapes — superset of this kind's six),
/// [`QuoteForm`] (the four homoiconic prefix wrappers — peer
/// projection on the SAME `Sexp` algebra), [`UnquoteForm`] (the
/// two template-substitution markers — proper subset of
/// `QuoteForm`), and the cross-crate `tatara-process` family
/// (`ConditionKind::ALL`, `ProcessPhase::ALL`,
/// `ProcessSignal::ALL`, `ChannelKind::ALL`, `IntentKind::ALL`,
/// …) every one of which paired its typed projection with `ALL`
/// before this lift.
///
/// Future consumers that compose against `ALL`: LSP / REPL
/// completion for the operator-facing rendered atom-kind label
/// (every `expected X, got Y` substring in `LispError`'s rendered
/// diagnostics for an atomic witness keys on this set's projection
/// through [`Self::label`]); `tatara-check` coverage assertions
/// over which atomic kinds reach a `TypeMismatch.got` arm at all
/// — the typed sweep replaces a per-callsite vocabulary of six
/// `&'static str` literals; any future audit-trail metric jointly
/// labeled by [`Self::label`] (e.g.
/// `tatara_lisp_atom_type_mismatch_total{got="symbol"}`) — the
/// metric label set IS [`Self::ALL`] mapped through
/// [`Self::label`]; any future structural rewriter (typed
/// analogue of MLIR's `op.walk<AtomKind::Symbol>()`) that wants
/// to sweep over every atomic kind in a typed sequence.
pub const ALL: [Self; 6] = [
Self::Symbol,
Self::Keyword,
Self::Str,
Self::Int,
Self::Float,
Self::Bool,
];
/// Canonical `&'static str` bytes for the [`Self::Symbol`] atomic-
/// payload marker — aliases [`SexpShape::SYMBOL_LABEL`] on the
/// AtomKind ⊂ SexpShape carving so the marker-level per-role bytes
/// bind at ONE `pub const` on the parent superset's atomic arm
/// rather than at TWO sites (the per-role `pub const` AND a
/// parallel inline literal). Per-role peer of `Self::Symbol` on the
/// closed-set atomic algebra; consumers reach for
/// `AtomKind::SYMBOL_LABEL` when the caller has a variant in hand
/// at compile time and wants the canonical diagnostic bytes without
/// runtime dispatch through [`Self::label`].
pub const SYMBOL_LABEL: &'static str = SexpShape::SYMBOL_LABEL;
/// Canonical `&'static str` bytes for the [`Self::Keyword`] atomic-
/// payload marker — aliases [`SexpShape::KEYWORD_LABEL`] on the
/// AtomKind ⊂ SexpShape carving. Per-role peer of `Self::Keyword`.
pub const KEYWORD_LABEL: &'static str = SexpShape::KEYWORD_LABEL;
/// Canonical `&'static str` bytes for the [`Self::Str`] atomic-
/// payload marker — aliases [`SexpShape::STRING_LABEL`] on the
/// AtomKind ⊂ SexpShape carving. Per-role peer of `Self::Str`; the
/// `Str → "string"` wire-shape rename matches
/// [`SexpShape::String`]'s label projection so the AtomKind marker
/// and its SexpShape peer emit byte-identical diagnostic bytes.
pub const STRING_LABEL: &'static str = SexpShape::STRING_LABEL;
/// Canonical `&'static str` bytes for the [`Self::Int`] atomic-
/// payload marker — aliases [`SexpShape::INT_LABEL`] on the
/// AtomKind ⊂ SexpShape carving. Per-role peer of `Self::Int`.
pub const INT_LABEL: &'static str = SexpShape::INT_LABEL;
/// Canonical `&'static str` bytes for the [`Self::Float`] atomic-
/// payload marker — aliases [`SexpShape::FLOAT_LABEL`] on the
/// AtomKind ⊂ SexpShape carving. Per-role peer of `Self::Float`.
pub const FLOAT_LABEL: &'static str = SexpShape::FLOAT_LABEL;
/// Canonical `&'static str` bytes for the [`Self::Bool`] atomic-
/// payload marker — aliases [`SexpShape::BOOL_LABEL`] on the
/// AtomKind ⊂ SexpShape carving. Per-role peer of `Self::Bool`.
pub const BOOL_LABEL: &'static str = SexpShape::BOOL_LABEL;
/// Closed-set forced-arity ALL array over the canonical atomic-
/// payload marker `&'static str` bytes, in declaration order
/// matching [`Self::ALL`] element-wise (pinned by
/// `atom_kind_labels_align_with_all_by_index`). Sibling posture to
/// [`SexpShape::LABELS`] (`[&'static str; 12]` — the superset
/// carving this AtomKind subset embeds into),
/// [`crate::error::ExpectedKwargShape::LABELS`] (`[&'static str; 7]`),
/// [`crate::error::KwargPathKind::LABELS`] (`[&'static str; 3]`),
/// [`crate::error::MacroDefHead::KEYWORDS`] (`[&'static str; 3]`),
/// [`Atom::BOOL_LITERALS`] (`[&'static str; 2]`), and
/// [`QuoteForm::PREFIXES`] (`[&'static str; 4]`) — every closed-set
/// outer projection on the substrate that carries an `&'static str`-
/// per-variant label now pins its per-role canonical bytes at ONE
/// `pub const` per role PLUS an ALL array for family-wide consumers.
///
/// Pre-lift the six atomic-payload marker bytes had NO per-role
/// primitive on this closed-set algebra — a consumer with an
/// `AtomKind` variant in hand at compile time reaching for the
/// canonical diagnostic bytes had to spell
/// `AtomKind::Symbol.label()` (runtime dispatch through the
/// composition [`Self::sexp_shape`] + [`SexpShape::label`]) OR
/// reach across the algebra boundary into
/// [`SexpShape::SYMBOL_LABEL`] and re-derive the AtomKind ⊂
/// SexpShape variant pairing at the call site. Post-lift the SIX
/// canonical bytes bind at ONE `pub const` per role on the typed
/// [`AtomKind`] algebra AND at [`Self::LABELS`] as a family-wide
/// forced-arity array — a future LSP / REPL completion bar keyed on
/// `AtomKind::LABELS`, a `tatara-check` coverage sweep over the
/// atomic-payload arms of a `TypeMismatch.got` corpus, or a Sekiban
/// audit-trail metric jointly labeled by the atomic marker
/// (`tatara_lisp_atom_type_mismatch_total{kind="symbol"}`) reads
/// through the typed constants on this subset algebra without
/// re-deriving the 6-of-12 carving inline.
///
/// Each entry is byte-for-byte identical to the corresponding
/// [`SexpShape`] atomic arm — an intentional cross-axis overlap
/// pinned by
/// `atom_kind_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte`
/// so a future label rename on EITHER side (a SexpShape `"string"`
/// → `"str"` drift, or an AtomKind rename that skips the alias)
/// fails-loudly at the alias test rather than as a silent
/// operator-facing vocabulary fracture. Adding a hypothetical
/// seventh atomic kind (e.g. `Char` for `#\x` reader syntax,
/// `Bigint` for arbitrary-precision integers) extends [`Self::ALL`]
/// AND [`Self::LABELS`] AND adds ONE per-role `pub const` alias in
/// lockstep — rustc's forced-arity check on the two `[_; N]` arrays
/// fails compilation if EITHER ALL array grows without the other.
///
/// Theory anchor: THEORY.md §III — the typescape; the six canonical
/// atomic-payload marker bytes bind at ONE typed
/// `[&'static str; 6]` array on the closed-set AtomKind algebra
/// rather than at zero-primitive-on-this-subset-plus-six-inline-
/// lookups scattered across the substrate. THEORY.md §V.1 —
/// knowable platform; the family's cardinality becomes a TYPE-level
/// constant on the substrate algebra rather than a per-consumer
/// runtime dispatch through the composition. THEORY.md §VI.1 —
/// generation over composition; the family-wide contract sweeps
/// (alignment with `ALL`, pairwise disjointness, membership through
/// [`Self::label`]) emerge from the composition of TWO substrate
/// primitives (this `pub const` array + the six per-role
/// `pub const *_LABEL` aliases) rather than as per-variant inline
/// assertions duplicated at each call site.
pub const LABELS: [&'static str; 6] = [
Self::SYMBOL_LABEL,
Self::KEYWORD_LABEL,
Self::STRING_LABEL,
Self::INT_LABEL,
Self::FLOAT_LABEL,
Self::BOOL_LABEL,
];
/// Canonical `u8` cache-key byte for [`Self::Symbol`]'s
/// [`Self::hash_discriminator`] arm — `0`. Per-role peer of
/// [`Self::Symbol`] on the closed-set atomic-payload cache-key-byte
/// axis; consumers reach for `AtomKind::SYMBOL_HASH_DISCRIMINATOR`
/// when the caller has a variant in hand at compile time and wants
/// the canonical byte without runtime dispatch through
/// [`Self::hash_discriminator`]. The byte is load-bearing because
/// the macro-expansion cache ([`crate::macro_expand::Expander`]'s
/// cache) keys on [`Hash for Atom`], and any renumbering silently
/// invalidates every cached expansion — post-lift the six canonical
/// bytes bind at ONE `pub(crate) const` per role rather than at
/// six inline `u8` literals scattered across
/// [`Self::hash_discriminator`]'s match arms.
///
/// Sibling posture to [`crate::error::QuoteForm::QUOTE_HASH_DISCRIMINATOR`]
/// on the quote-family sub-carving — both close their respective
/// closed-set cache-key algebras at ONE per-role constant per
/// variant PLUS a family-wide [`Self::HASH_DISCRIMINATORS`] array.
/// The two families partition their respective cache-key spaces
/// independently: `AtomKind` at `{0..=5}` NESTED inside
/// [`crate::ast::Sexp::Atom`]'s outer `1u8` byte (`Hash for Atom`
/// runs on the [`Atom`] type, not [`Sexp`]), `QuoteForm` at
/// `{3..=6}` at the outer [`Sexp`] cache-key space itself.
///
/// Theory anchor: THEORY.md §II.1 invariant 5 — composition
/// preserves proofs; the alias-chain composition law
/// `AtomKind::HASH_DISCRIMINATORS[i] ==
/// AtomKind::ALL[i].hash_discriminator()` binds the family-wide
/// array to the projection method at rustc time, pinned by byte
/// equality. THEORY.md §III — the typescape; the six canonical
/// cache-key bytes bind at ONE `pub(crate) const` per role on the
/// typed algebra rather than as inline `u8` literals in the
/// `hash_discriminator` match arms.
pub(crate) const SYMBOL_HASH_DISCRIMINATOR: u8 = 0;
/// Canonical `u8` cache-key byte for [`Self::Keyword`]'s
/// [`Self::hash_discriminator`] arm — `1`. Sibling of
/// [`Self::SYMBOL_HASH_DISCRIMINATOR`] on the closed-set per-role
/// atomic-payload cache-key-byte axis; see
/// [`Self::SYMBOL_HASH_DISCRIMINATOR`] for the algebra-level
/// round-trip + disjointness contracts every sibling shares.
pub(crate) const KEYWORD_HASH_DISCRIMINATOR: u8 = 1;
/// Canonical `u8` cache-key byte for [`Self::Str`]'s
/// [`Self::hash_discriminator`] arm — `2`. Sibling of
/// [`Self::SYMBOL_HASH_DISCRIMINATOR`] on the closed-set per-role
/// atomic-payload cache-key-byte axis.
pub(crate) const STR_HASH_DISCRIMINATOR: u8 = 2;
/// Canonical `u8` cache-key byte for [`Self::Int`]'s
/// [`Self::hash_discriminator`] arm — `3`. Sibling of
/// [`Self::SYMBOL_HASH_DISCRIMINATOR`] on the closed-set per-role
/// atomic-payload cache-key-byte axis.
pub(crate) const INT_HASH_DISCRIMINATOR: u8 = 3;
/// Canonical `u8` cache-key byte for [`Self::Float`]'s
/// [`Self::hash_discriminator`] arm — `4`. Sibling of
/// [`Self::SYMBOL_HASH_DISCRIMINATOR`] on the closed-set per-role
/// atomic-payload cache-key-byte axis.
pub(crate) const FLOAT_HASH_DISCRIMINATOR: u8 = 4;
/// Canonical `u8` cache-key byte for [`Self::Bool`]'s
/// [`Self::hash_discriminator`] arm — `5`. Sibling of
/// [`Self::SYMBOL_HASH_DISCRIMINATOR`] on the closed-set per-role
/// atomic-payload cache-key-byte axis. The HIGHEST byte on the
/// closed set — a future seventh atomic kind (e.g. `Char` for
/// `#\x` reader syntax, `Bigint` for arbitrary-precision integers)
/// would extend the partition to `{0..=6}` and land the new
/// discriminator at `6u8`.
pub(crate) const BOOL_HASH_DISCRIMINATOR: u8 = 5;
/// Closed-set forced-arity ALL array over the canonical atomic-
/// payload cache-key `u8` bytes, in declaration order matching
/// [`Self::ALL`] element-wise (pinned by
/// `atom_kind_hash_discriminators_align_with_all_by_index`).
/// Sibling posture to [`Self::LABELS`] (`[&'static str; 6]` — the
/// diagnostic-label `&'static str` axis on the SAME closed set) and
/// to [`crate::error::QuoteForm::HASH_DISCRIMINATORS`] (`[u8; 4]` —
/// the quote-family sub-carving's cache-key-byte peer). Every
/// closed-set outer projection on the substrate's [`AtomKind`]
/// algebra that carries a `u8` per-variant discriminator now pins
/// its per-role canonical bytes at ONE `pub(crate) const` per role
/// PLUS an ALL array for family-wide consumers.
///
/// Pre-lift the six cache-key bytes had NO per-role primitive on
/// this closed-set algebra — a consumer with an [`AtomKind`]
/// variant in hand at compile time reaching for the canonical byte
/// had to spell `AtomKind::Str.hash_discriminator()` (runtime
/// dispatch through the match arm) OR reach across into the inline
/// `2u8` at the pre-lift match arm's [`Self::Str`] branch and
/// re-derive the (variant, byte) pairing at the call site.
/// Post-lift the SIX canonical bytes bind at ONE `pub(crate) const`
/// per role on the typed [`AtomKind`] algebra AND at
/// [`Self::HASH_DISCRIMINATORS`] as a family-wide forced-arity
/// array — a future substrate-facing cache-key introspection tool
/// (a `tatara-check` predicate that asserts every atomic arm's
/// discriminator injective on the nested [`Atom`] axis, a Sekiban
/// audit-trail metric jointly labeled by the atomic cache-key
/// partition, a future `TypedRewriter<AtomKindOp>` sweep zipping
/// ALL / LABELS / HASH_DISCRIMINATORS in lockstep for a family-wide
/// (variant, label, byte) triple render) reads through the typed
/// constants without re-deriving the six-arm carving inline.
///
/// Each entry is byte-for-byte identical to the pre-lift inline
/// `u8` literal at the corresponding [`Self::hash_discriminator`]
/// arm — pinned by
/// `atom_kind_hash_discriminators_pin_legacy_cache_key_bytes` so
/// a regression that drifts ONE `pub(crate) const` from its pre-
/// lift byte silently invalidates every cached expansion of an
/// [`Atom`] participating in [`crate::macro_expand::Expander::cache`],
/// fails-loudly at the alias test rather than at a silent cache
/// mis-hash. Adding a hypothetical seventh atomic kind (e.g.
/// `Char` for `#\x` reader syntax, `Bigint` for arbitrary-
/// precision integers) extends [`Self::ALL`] AND
/// [`Self::HASH_DISCRIMINATORS`] AND adds ONE per-role
/// `pub(crate) const` in lockstep — rustc's forced-arity check on
/// the two `[_; N]` arrays fails compilation if EITHER array grows
/// without the other, closing the extensibility gap that pre-lift
/// silently allowed a discriminator collision on `6u8` (the next
/// free byte on the nested [`Atom`] cache-key space).
///
/// Theory anchor: THEORY.md §III — the typescape; the six
/// canonical cache-key bytes bind at ONE typed `[u8; 6]` array on
/// the closed-set [`AtomKind`] algebra rather than at zero-
/// primitive-plus-six-inline-`u8`-literals scattered across the
/// [`Self::hash_discriminator`] match arms. THEORY.md §V.1 —
/// knowable platform; the family's cardinality becomes a TYPE-
/// level constant on the substrate algebra rather than a per-
/// consumer runtime dispatch through the match table. THEORY.md
/// §V.3 — three-pillar attestation; the cache-key partition is
/// the substrate's nested [`Atom`] `intent_hash` composition axis
/// for every atomic arm — binding the six bytes on the typed
/// algebra makes attestation-key drift a compile error rather
/// than a silent BLAKE3 mis-hash. THEORY.md §VI.1 — generation
/// over composition; the family-wide contract sweeps (alignment
/// with `ALL`, pairwise disjointness, membership through
/// [`Self::hash_discriminator`]) emerge from the composition of
/// TWO substrate primitives (this `pub(crate) const` array + the
/// six per-role `pub(crate) const *_HASH_DISCRIMINATOR` aliases)
/// rather than as per-variant inline assertions duplicated at each
/// call site.
///
/// The `#[allow(dead_code)]` posture matches
/// [`crate::error::QuoteForm::HASH_DISCRIMINATORS`]: the substrate's
/// current [`Hash for Atom`] body composes through the per-variant
/// [`Self::hash_discriminator`] projection arm-by-arm rather than
/// sweeping the family-wide array, so no non-test caller currently
/// reaches this ALL array directly. The lift lands the substrate
/// primitive so future consumers keyed on the whole family (a
/// future [`crate::macro_expand::Expander`] cache-warmup pass that
/// hashes the atomic byte-set upfront, a future `tatara-check`
/// predicate `(check-atom-cache-key-partition-injective …)` that
/// verifies the `{0..=5}` partition structurally, a future
/// `TypedRewriter<AtomKindOp>` sweep zipping ALL / LABELS /
/// HASH_DISCRIMINATORS in lockstep for a family-wide (variant,
/// label, byte) triple render) bind to ONE `[u8; 6]` primitive
/// rather than re-deriving the array inline per callsite.
#[allow(dead_code)]
pub(crate) const HASH_DISCRIMINATORS: [u8; 6] = [
Self::SYMBOL_HASH_DISCRIMINATOR,
Self::KEYWORD_HASH_DISCRIMINATOR,
Self::STR_HASH_DISCRIMINATOR,
Self::INT_HASH_DISCRIMINATOR,
Self::FLOAT_HASH_DISCRIMINATOR,
Self::BOOL_HASH_DISCRIMINATOR,
];
/// Canonical `u8` OUTER-`Sexp` cache-key byte at which ALL SIX
/// atomic-payload shapes collapse when hashed at the outer
/// [`Hash for Sexp`](crate::ast::Sexp) level — `1`. The
/// outer-carve peer of [`Self::HASH_DISCRIMINATORS`] (the six
/// nested INNER cache-key bytes `{0..=5}` that specialise INSIDE
/// [`Hash for Atom`] after the outer marker byte is emitted).
/// The lift moves the byte the outer-Sexp cache-key algebra uses
/// to distinguish [`crate::ast::Sexp::Atom(_)`] from every other
/// outer-Sexp variant off inline `1u8` literals scattered across
/// [`crate::error::SexpShape::hash_discriminator`]'s six-arm
/// atomic collapse + the two structural-carve joint-partition
/// disjointness pins and onto ONE `pub(crate) const` on the
/// [`AtomKind`] algebra it names.
///
/// Where the byte appears at the outer-Sexp cache-key algebra:
/// [`crate::error::SexpShape::hash_discriminator`]'s atomic-arm
/// collapse `Self::Symbol | Self::Keyword | Self::String |
/// Self::Int | Self::Float | Self::Bool => 1` binds directly to
/// this constant; every one of the six atomic shapes routes
/// through the shape-level projection into the outer-Sexp cache
/// key at THIS byte. The nested inner
/// [`Self::HASH_DISCRIMINATORS`] `{0..=5}` bytes then specialise
/// the atomic payload INSIDE [`Hash for Atom`] via a second
/// discriminator emission (`self.hash_discriminator().hash(h)`
/// on the [`Atom`] value carrier), so the two byte spaces live
/// at different hash-sequence positions and do not collide.
///
/// Sibling posture to [`crate::error::StructuralKind::HASH_DISCRIMINATORS`]
/// (`[u8; 2]` at `{0, 2}` on the outer-Sexp cache-key space) and
/// to [`crate::error::QuoteForm::HASH_DISCRIMINATORS`] (`[u8; 4]`
/// at `{3, 4, 5, 6}` on the same space) — together with THIS
/// scalar the three sibling carvings' byte spaces jointly
/// partition the outer-Sexp discriminator space `{0..=6}`
/// injectively. Post-lift the outer-Sexp cache-key algebra
/// closes over FOUR typed byte primitives:
/// * [`Self::OUTER_HASH_DISCRIMINATOR`] (this constant) —
/// scalar `1u8` for the atomic-payload outer-carve;
/// * [`crate::error::StructuralKind::HASH_DISCRIMINATORS`] —
/// `{0, 2}` for the structural-residual carve;
/// * [`crate::error::QuoteForm::HASH_DISCRIMINATORS`] —
/// `{3..=6}` for the quote-family carve;
/// * [`Self::HASH_DISCRIMINATORS`] — the nested inner
/// `{0..=5}` byte-set INSIDE [`Hash for Atom`], NOT on the
/// outer-Sexp space.
///
/// The scalar shape (single `u8`, NOT an array) is intrinsic to
/// the carve: all six atomic-payload arms of
/// [`crate::error::SexpShape`] collapse to the SAME outer byte
/// (the outer-Sexp distinguisher is variant-level: `Sexp::Atom(_)`
/// vs the six sibling `Sexp` variants); per-atom-kind
/// specialisation lives at the nested inner
/// [`Self::HASH_DISCRIMINATORS`] carve inside [`Hash for Atom`].
/// The other two carvings' `HASH_DISCRIMINATORS` are arrays
/// because their shape-level arms each carry a DISTINCT outer
/// byte; the atomic carve is a scalar because its arms carry the
/// SAME outer byte.
///
/// `pub(crate)` because the byte is an implementation detail of
/// the substrate's `Hash for Sexp` cache-key contract; exposing
/// it publicly would leak the cache-key shape through the API
/// without enabling any external consumer the public projections
/// ([`Self::label`], [`Self::sexp_shape`]) don't already serve.
/// Same posture as [`Self::HASH_DISCRIMINATORS`] +
/// [`Self::SYMBOL_HASH_DISCRIMINATOR`] and the sibling carvings'
/// per-role `pub(crate) const` peers.
///
/// Pre-lift the outer-Atom marker byte lived at THREE sites: the
/// inline `1u8` literal at
/// [`crate::error::SexpShape::hash_discriminator`]'s six-arm
/// atomic collapse; the inline `1u8` literal at
/// `sexp_shape_hash_discriminator_atomic_arms_collapse_to_outer_atom_marker`'s
/// assertion body; the inline `1u8` literal at
/// `sexp_shape_hash_discriminator_partitions_by_three_way_carving_disjointly`'s
/// `expected_atomic` fixture; PLUS a duplicated local `const
/// ATOM_OUTER_CARVE_BYTE: u8 = 1` inside
/// `structural_kind_hash_discriminator_disjoint_from_atom_outer_carve_byte_and_quote_form_hash_discriminator_partition`.
/// The (byte, algebra) pairing had no typed home — a consumer
/// with a typed [`AtomKind`] identity in hand reaching for the
/// outer-Sexp cache-key byte the atomic arm collapses to had to
/// re-derive the byte from the shape-level projection method's
/// atomic collapse arm inline, OR re-derive the pre-lift local
/// `ATOM_OUTER_CARVE_BYTE` fixture at every joint-partition-check
/// site. Post-lift the byte binds at ONE `pub(crate) const` on
/// the closed-set [`AtomKind`] algebra it names; every downstream
/// consumer (the shape-level projection, the joint-partition
/// disjointness pins, the three-way carving image pin, a future
/// `tatara-check` predicate that verifies the outer-Sexp cache-
/// key partition structurally, a future
/// [`crate::macro_expand::Expander`] cache-warmup pass that
/// hashes the outer-Sexp byte-set upfront) picks up the same
/// canonical byte from ONE source of truth.
///
/// Theory anchor: THEORY.md §II.1 invariant 5 — composition
/// preserves proofs; the (AtomKind ⊂ SexpShape carve, outer-Sexp
/// cache-key byte) pairing binds at rustc time by byte equality
/// against the shape-level projection's atomic collapse arm.
/// THEORY.md §III — the typescape; the outer-Atom cache-key byte
/// binds at ONE `pub(crate) const` on the typed algebra rather
/// than as inline `1u8` literals at every joint-partition + shape-
/// level-collapse site. THEORY.md §V.1 — knowable platform; the
/// outer-Sexp cache-key space's four-way partition (this scalar
/// PLUS the three sibling carvings' arrays) becomes a TYPE-level
/// constant on the substrate algebra rather than a per-callsite
/// hand-rolled `{0, 1, 2, 3, 4, 5, 6}` re-enumeration. THEORY.md
/// §V.3 — three-pillar attestation; the outer-Sexp cache-key
/// partition is the substrate's outer [`Sexp`] `intent_hash`
/// composition axis — binding the four-way partition's atomic-
/// carve byte on the typed algebra makes attestation-key drift a
/// compile error rather than a silent BLAKE3 mis-hash. A future
/// eighth [`Sexp`] variant (e.g. `Vector` for `#(...)` reader
/// syntax, `Map` for `{...}`, `Char` for `#\x`) picks a fresh
/// cache-key byte outside `{0..=6}` (e.g. `7u8`), extends the
/// closed-set [`crate::error::SexpShape`] enum + its shape-level
/// `hash_discriminator` and either an existing carving OR a fresh
/// sub-algebra — the outer-Atom scalar itself stays untouched
/// unless the new variant is also an atomic-payload arm.
pub(crate) const OUTER_HASH_DISCRIMINATOR: u8 = 1;
/// Project the typed marker to the canonical `&'static str`
/// diagnostic label — `"symbol"` for [`Self::Symbol`],
/// `"keyword"` for [`Self::Keyword`], `"string"` for [`Self::Str`]
/// (the wire-shape rename `Str → "string"` matches the
/// [`SexpShape::String`] label projection), `"int"` for
/// [`Self::Int`], `"float"` for [`Self::Float`], `"bool"` for
/// [`Self::Bool`]. Each label is byte-for-byte identical to the
/// corresponding [`SexpShape`] variant's label — and post-lift this
/// agreement is STRUCTURAL rather than two literal-discipline sites
/// pinned by a cross-projection test.
///
/// Composition law: `AtomKind::label(k) ==
/// AtomKind::sexp_shape(k).label()` for every `k: AtomKind`. The
/// body composes [`Self::sexp_shape`] (the typed projection lifting
/// each AtomKind variant into its peer [`SexpShape`] variant) with
/// [`SexpShape::label`] (the canonical `&'static str` projection on
/// the supeset's twelve-variant closed set), so the six atomic-arm
/// labels live at ONE canonical site ([`SexpShape::label`]) rather
/// than at TWO ([`SexpShape::label`] AND a parallel six-arm match
/// here, pre-lift). Pre-lift the substrate-wide AtomKind ⊂ SexpShape
/// label-vocabulary agreement was enforced by literal discipline at
/// the two sites + a cross-projection test
/// (`atom_kind_label_agrees_with_sexp_shape_label_for_every_atom_arm`);
/// post-lift the agreement is a TYPED CONSEQUENCE of the composition
/// — a typo in `SexpShape::label`'s atomic arms is a typo in BOTH
/// projections, and the cross-projection test is true by
/// construction. Same lift posture as the prior-run
/// `Atom::as_X → Atom::as_X` algebra-lift commit (6935416), the
/// `from_lexeme` reader-atom lift commit (9b95e64), and the
/// `to_iac_forge_sexpr` Atom-arm lift commit (418be51): the typed
/// projection sits on the value, and the consumer composes through
/// the existing structural pairing rather than re-deriving the
/// per-variant literal.
///
/// The `&'static str` lifetime is load-bearing: it lets the
/// variant project through this method without an allocation,
/// parallel to how [`SexpShape::label`], [`QuoteForm::prefix`],
/// [`QuoteForm::iac_forge_tag`], [`UnquoteForm::marker`], and
/// [`crate::error::ExpectedKwargShape::label`] project their
/// respective closed-set surfaces. The composition preserves the
/// no-allocation contract: [`Self::sexp_shape`] returns a `Copy`
/// value and [`SexpShape::label`] yields `&'static str`, so the
/// `&'static str` projection through the composition allocates
/// nothing at runtime.
///
/// The bidirectional contract is anchored by tests:
/// `atom_kind_label_renders_canonical_string_for_every_variant`
/// pins each variant's canonical literal so a typo in
/// [`SexpShape::label`]'s atomic arms fails-loudly through this
/// projection too, `atom_kind_display_matches_label_for_every_variant`
/// pins Display-equals-label so any future
/// `#[error("... got {got}")]` annotation that threads through
/// this projection projects byte-for-byte, and
/// `atom_kind_label_round_trips_through_from_str` pins the
/// `label` ↔ [`Self::FromStr`] round-trip for every variant in
/// [`Self::ALL`] so the typed surface and the rendered diagnostic
/// literal cannot drift. The post-lift composition contract is
/// pinned by
/// `atom_kind_label_routes_through_sexp_shape_label_via_sexp_shape_projection`
/// — a regression that re-inlines the six atomic-arm literals here
/// and silently drifts ONE arm from the [`SexpShape::label`] axis
/// fails the routing pin loudly without needing a per-variant
/// cross-axis literal sweep.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the
/// AtomKind ⊂ SexpShape label-vocabulary containment becomes a
/// TYPED CONSEQUENCE of the [`Self::sexp_shape`] + [`SexpShape::label`]
/// composition rather than literal discipline at two sites. THEORY.md
/// §VI.1 — generation over composition; the six atomic-arm labels
/// live at ONE canonical site ([`SexpShape::label`]) and this method
/// generates its identity through the typed-projection composition.
/// THEORY.md §II.1 invariant 2 — free middle; FOUR consumers of the
/// [`AtomKind`] algebra ([`Hash for Atom`] via
/// [`Self::hash_discriminator`], [`crate::domain::sexp_shape`] via
/// [`Self::sexp_shape`], the diagnostic-rendering surface via this
/// method, and the `ClosedSet`-trait FromStr/Display surface via
/// `#[closed_set(via = "label")]`) now route through ONE typed
/// closed-set projection family with no per-consumer literal
/// duplication.
#[must_use]
pub fn label(self) -> &'static str {
self.sexp_shape().label()
}
/// Stable, per-variant byte discriminator that paired with the
/// recursive payload hash builds the substrate's [`Hash for Atom`]
/// projection — `0u8` for [`Self::Symbol`], `1u8` for
/// [`Self::Keyword`], `2u8` for [`Self::Str`], `3u8` for
/// [`Self::Int`], `4u8` for [`Self::Float`], `5u8` for
/// [`Self::Bool`]. The byte values are load-bearing because the
/// macro-expansion cache ([`crate::macro_expand::Expander`]'s
/// cache) keys on the hash of `(macro_name, args)`, and any
/// `Atom` participates in that hash — changing a discriminator
/// silently invalidates every cached expansion across the
/// substrate.
///
/// The closed set ensures the six arms partition `{0, 1, 2, 3,
/// 4, 5}` injectively. Disjointness from [`QuoteForm`]'s
/// `{3, 4, 5, 6}` is structural rather than overlap-induced
/// hash collision: [`Hash for Atom`] and the quote-family arms of
/// [`Hash for Sexp`] hash DISTINCT types (`Atom` vs `Sexp`), and
/// `Atom`'s discriminator lives nested INSIDE `Sexp::Atom`'s outer
/// `1u8` discriminator — the prefix-uniqueness contract that the
/// `Hash for Sexp` outer match maintains independently. A future
/// quote-family or atomic-kind extension must extend BOTH bodies'
/// arms in lockstep, with rustc binding the consistency through
/// exhaustiveness over BOTH closed enums.
///
/// `pub(crate)` because the byte-discriminator surface is an
/// implementation detail of the substrate's [`Hash for Atom`]
/// cache-key contract; exposing it publicly would leak the
/// cache-key shape through the API without enabling any external
/// consumer the public projections ([`Atom::kind`], [`Self::label`],
/// [`Self::sexp_shape`]) don't already serve. Same posture as
/// [`QuoteForm::hash_discriminator`] and its outer-value peer
/// [`Atom::hash_discriminator`] (the outer-`Atom` projection that
/// composes through this method via `self.kind().hash_discriminator()`
/// so the [`Hash for Atom`] callsite binds at ONE site on the
/// outer-`Atom` algebra rather than at the two-hop
/// `.kind().hash_discriminator()` chain).
#[must_use]
pub(crate) fn hash_discriminator(self) -> u8 {
match self {
Self::Symbol => Self::SYMBOL_HASH_DISCRIMINATOR,
Self::Keyword => Self::KEYWORD_HASH_DISCRIMINATOR,
Self::Str => Self::STR_HASH_DISCRIMINATOR,
Self::Int => Self::INT_HASH_DISCRIMINATOR,
Self::Float => Self::FLOAT_HASH_DISCRIMINATOR,
Self::Bool => Self::BOOL_HASH_DISCRIMINATOR,
}
}
/// Canonical [`SexpShape`] embed target for the [`Self::Symbol`]
/// atomic-payload arm on the AtomKind ⊂ SexpShape 6-of-12 carving —
/// [`SexpShape::Symbol`]. Per-role peer of `Self::Symbol` on the
/// closed-set atomic-payload → outer-shape embed axis; consumers
/// reach for `AtomKind::SYMBOL_SHAPE` when the caller has a variant
/// in hand at compile time and wants the canonical outer-shape
/// identity without runtime dispatch through [`Self::sexp_shape`].
///
/// Sibling posture to the six pre-existing per-role LABEL /
/// HASH_DISCRIMINATOR aliases on this same closed-set algebra
/// ([`Self::SYMBOL_LABEL`], [`Self::SYMBOL_HASH_DISCRIMINATOR`]) —
/// each closes a distinct per-role sub-vocabulary axis on the
/// AtomKind carving. This constant closes the THIRD per-role
/// axis on [`AtomKind`] (the `SexpShape`-embed axis, paired with
/// the pre-existing `&'static str` diagnostic-label axis + the
/// `u8` cache-key axis) at ONE typed alias through the peer
/// superset variant on the [`SexpShape`] closed set.
pub const SYMBOL_SHAPE: SexpShape = SexpShape::Symbol;
/// Canonical [`SexpShape`] embed target for the [`Self::Keyword`]
/// atomic-payload arm on the AtomKind ⊂ SexpShape carving —
/// [`SexpShape::Keyword`]. Per-role peer of `Self::Keyword`.
pub const KEYWORD_SHAPE: SexpShape = SexpShape::Keyword;
/// Canonical [`SexpShape`] embed target for the [`Self::Str`]
/// atomic-payload arm on the AtomKind ⊂ SexpShape carving —
/// [`SexpShape::String`]. Per-role peer of `Self::Str`; the
/// `Str → String` wire-shape rename matches the peer
/// [`Self::STRING_LABEL`] alias (both bind the AtomKind subset's
/// `Str` variant to the SexpShape superset's `String` variant on
/// their respective per-role sub-vocabulary axes).
pub const STR_SHAPE: SexpShape = SexpShape::String;
/// Canonical [`SexpShape`] embed target for the [`Self::Int`]
/// atomic-payload arm on the AtomKind ⊂ SexpShape carving —
/// [`SexpShape::Int`]. Per-role peer of `Self::Int`.
pub const INT_SHAPE: SexpShape = SexpShape::Int;
/// Canonical [`SexpShape`] embed target for the [`Self::Float`]
/// atomic-payload arm on the AtomKind ⊂ SexpShape carving —
/// [`SexpShape::Float`]. Per-role peer of `Self::Float`.
pub const FLOAT_SHAPE: SexpShape = SexpShape::Float;
/// Canonical [`SexpShape`] embed target for the [`Self::Bool`]
/// atomic-payload arm on the AtomKind ⊂ SexpShape carving —
/// [`SexpShape::Bool`]. Per-role peer of `Self::Bool`.
pub const BOOL_SHAPE: SexpShape = SexpShape::Bool;
/// Closed-set forced-arity ALL array over the canonical
/// [`SexpShape`] embed targets on the AtomKind ⊂ SexpShape
/// 6-of-12 carving, in declaration order matching [`Self::ALL`]
/// element-wise (pinned by
/// `atom_kind_shapes_align_with_all_by_index`). Sibling posture
/// to [`Self::LABELS`] (`[&'static str; 6]` — per-role diagnostic
/// bytes) and [`Self::HASH_DISCRIMINATORS`] (`[u8; 6]` — per-role
/// nested-Atom cache-key bytes) on the SAME closed-set AtomKind
/// algebra; where those two arrays lift the per-role
/// `&'static str` and `u8` sub-vocabularies onto the substrate,
/// this array lifts the per-role [`SexpShape`] embed-target
/// sub-vocabulary at the same `[_; 6]` forced arity.
///
/// Pre-lift the six [`SexpShape`] embed targets had NO per-role
/// primitive on this closed-set algebra — a consumer with an
/// `AtomKind` variant in hand at compile time reaching for the
/// canonical embed target had to spell
/// `AtomKind::Symbol.sexp_shape()` (runtime dispatch through the
/// six-arm match body) OR re-derive the AtomKind ⊂ SexpShape
/// variant pairing at the call site by importing both enums and
/// spelling `SexpShape::Symbol` inline. Post-lift the SIX
/// canonical embed targets bind at ONE `pub const` per role on
/// the typed [`AtomKind`] algebra AND at [`Self::SHAPES`] as a
/// family-wide forced-arity array — a future LSP / REPL
/// completion bar keyed on `AtomKind::SHAPES` for the "which
/// SexpShape does this AtomKind embed into?" outer-shape column,
/// a `tatara-check` coverage sweep zipping `AtomKind::ALL` /
/// `LABELS` / `HASH_DISCRIMINATORS` / `SHAPES` in lockstep for a
/// family-wide (variant, label, byte, embed-target) quadruple
/// render, or a Sekiban audit-trail metric jointly labeled by
/// the embed-target's SexpShape identity reads through the typed
/// constants on this subset algebra without re-deriving the
/// 6-of-12 carving inline.
///
/// Round-trip identity with the inverse projection
/// [`crate::error::SexpShape::as_atom_kind`]: for every index `i`,
/// `Self::SHAPES[i].as_atom_kind() == Some(Self::ALL[i])`
/// (pinned by
/// `atom_kind_shapes_align_with_all_by_index_through_as_atom_kind`) —
/// the embed / project section closes as a family-wide array-
/// indexed law rather than as a per-variant assertion sweep.
/// Adding a hypothetical seventh atomic kind (e.g. `Char` for
/// `#\x` reader syntax, `Bigint` for arbitrary-precision
/// integers) extends [`Self::ALL`] AND [`Self::SHAPES`] AND
/// [`SexpShape::ALL`] AND adds ONE per-role `pub const *_SHAPE`
/// in lockstep — rustc's forced-arity check on the two `[_; N]`
/// arrays fails compilation if EITHER ALL array grows without
/// the other, AND the peer [`SexpShape::as_atom_kind`] arm must
/// grow in lockstep to preserve the round-trip identity.
///
/// Theory anchor: THEORY.md §III — the typescape; the six
/// canonical [`SexpShape`] embed targets bind at ONE typed
/// `[SexpShape; 6]` array on the closed-set AtomKind algebra
/// rather than at zero-primitive-on-this-subset-plus-six-inline-
/// lookups scattered across the substrate. THEORY.md §V.1 —
/// knowable platform; the family's cardinality becomes a TYPE-
/// level constant on the substrate algebra rather than a per-
/// consumer runtime dispatch through the composition. THEORY.md
/// §II.1 invariant 2 — free middle; the (embed, project) pair
/// binds at THREE typed sites now — the projection method
/// [`Self::sexp_shape`], this family-wide array, AND the peer
/// inverse [`crate::error::SexpShape::as_atom_kind`] — with
/// rustc-enforced consistency across all three. THEORY.md §VI.1
/// — generation over composition; the family-wide contract
/// sweeps (alignment with `ALL`, round-trip through
/// `as_atom_kind`, membership through `sexp_shape`) emerge from
/// the composition of TWO substrate primitives (this `pub const`
/// array + the six per-role `pub const *_SHAPE` aliases) rather
/// than as per-variant inline assertions duplicated at each call
/// site.
pub const SHAPES: [SexpShape; 6] = [
Self::SYMBOL_SHAPE,
Self::KEYWORD_SHAPE,
Self::STR_SHAPE,
Self::INT_SHAPE,
Self::FLOAT_SHAPE,
Self::BOOL_SHAPE,
];
/// Project the typed marker into its matching [`SexpShape`]
/// variant — `Symbol → SexpShape::Symbol`, `Keyword →
/// SexpShape::Keyword`, `Str → SexpShape::String`, `Int →
/// SexpShape::Int`, `Float → SexpShape::Float`, `Bool →
/// SexpShape::Bool`. ONE projection on the closed-set atomic-
/// payload algebra that [`crate::domain::sexp_shape`]'s outer-shape
/// projection routes through for the six atom arms — so the
/// (Atom variant, SexpShape variant) pairing binds at ONE site on
/// the typed algebra rather than at six byte-identical inline arms
/// in [`crate::domain::sexp_shape`]. Direct sibling to
/// [`QuoteForm::sexp_shape`] — that closed enum carves the
/// quote-family arms of [`SexpShape`]'s twelve-variant closed set,
/// while this enum carves the atomic-payload arms.
///
/// Each arm routes through the per-role `pub const` on `impl Self`
/// ([`Self::SYMBOL_SHAPE`], [`Self::KEYWORD_SHAPE`],
/// [`Self::STR_SHAPE`], [`Self::INT_SHAPE`], [`Self::FLOAT_SHAPE`],
/// [`Self::BOOL_SHAPE`]) so the six canonical embed targets bind
/// at ONE typed source of truth per role rather than as inline
/// `SexpShape::X` literals scattered across the `match` body.
/// Sibling posture to [`Self::label`]'s composition through
/// [`Self::sexp_shape().label()`] and [`Self::hash_discriminator`]'s
/// per-role routing through [`Self::SYMBOL_HASH_DISCRIMINATOR`] …
/// [`Self::BOOL_HASH_DISCRIMINATOR`] — the three per-role axes on
/// the AtomKind algebra (embed target, diagnostic label, cache-key
/// byte) each surface their per-role bytes through the SAME
/// per-role `pub const` shape.
///
/// Composition law: for every [`Atom`] `a`,
/// `crate::domain::sexp_shape(&Sexp::Atom(a.clone())) ==
/// a.kind().sexp_shape()`. Pinned by the cross-projection round-trip
/// test in this module, so a regression that drifts either side
/// of the typed algebra (an [`Atom::kind`] arm or this
/// [`Self::sexp_shape`] arm) surfaces immediately rather than as a
/// silent operator-facing diagnostic drift at every
/// `LispError::TypeMismatch.got` slot for an atomic witness.
///
/// Post-lift routing pin
/// `atom_kind_sexp_shape_routes_through_typed_per_role_constants`
/// catches a regression that re-inlines the six `SexpShape::X`
/// arm literals here and silently drifts ONE arm from the per-role
/// `pub const` alias — the routing agreement is a TYPED CONSEQUENCE
/// of the composition rather than literal discipline at two sites.
///
/// Bidirectional dual: the inverse projection
/// [`crate::error::SexpShape::as_atom_kind`] (12→6, partial)
/// covers the 6-of-12 carving of [`SexpShape`] this embed
/// reaches. The pair `(AtomKind::sexp_shape,
/// SexpShape::as_atom_kind)` forms an `Iso(AtomKind, AtomShape ⊂
/// SexpShape)`: every typed marker round-trips through the embed
/// (`AtomKind::sexp_shape(k).as_atom_kind() == Some(k)` for every
/// `k: AtomKind`), every atom-shape pre-image recovers the typed
/// marker. The non-atom shapes (`Nil`, `List`, every quote-family
/// wrapper) form the kernel of the inverse — `as_atom_kind`
/// returns `None` for them. See [`crate::error::SexpShape::as_atom_kind`]'s
/// docstring for the composition law's other direction +
/// disjointness with the quote-family sibling
/// `SexpShape::as_quote_form`.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (Atom
/// variant, SexpShape variant) pairing becomes a TYPE projection
/// on the substrate algebra rather than six inline arms in
/// [`crate::domain::sexp_shape`]. A typo or swap at the shape-
/// projection site is no longer a runtime drift but a compile
/// error against the typed projection. THEORY.md §II.1 invariant
/// 2 — free middle; THREE consumers ([`Hash for Atom`] via
/// [`Self::hash_discriminator`], [`crate::domain::sexp_shape`]
/// via this method, and the future diagnostic / completion surface
/// via [`Self::label`]) now route through ONE typed closed-set
/// match family, so a regression that drifts ONE consumer's
/// pairing from the others cannot reach the substrate's runtime.
#[must_use]
pub fn sexp_shape(self) -> SexpShape {
match self {
Self::Symbol => Self::SYMBOL_SHAPE,
Self::Keyword => Self::KEYWORD_SHAPE,
Self::Str => Self::STR_SHAPE,
Self::Int => Self::INT_SHAPE,
Self::Float => Self::FLOAT_SHAPE,
Self::Bool => Self::BOOL_SHAPE,
}
}
}
// `impl fmt::Display for AtomKind` + `impl std::str::FromStr for AtomKind`
// + `impl tatara_closed_set::ClosedSet for AtomKind` + `pub struct UnknownAtomKind(pub
// String)` are generated by `#[derive(tatara_closed_set::DeriveClosedSet)]` on
// the enum declaration above. `label` delegates to the inherent
// `AtomKind::label` via `#[closed_set(via = "label")]` so the
// domain-canonical lowercase-vocabulary projection stays load-bearing (the
// six labels `"symbol" / "keyword" / "string" / "int" / "float" / "bool"`
// match the `SexpShape` atomic-subset labels byte-for-byte AND the
// diagnostic-rendering shape `LispError::TypeMismatch.got` keys on
// verbatim). The `display` flag emits the substrate-wide
// `f.write_str(Self::label(*self))` block. `#[closed_set(generate_unknown =
// "atom kind")]` emits the typed parse-rejection carrier with the
// substrate-wide `Debug + Clone + PartialEq + Eq + thiserror::Error`
// derives and the `#[error("unknown atom kind: {0}")]` annotation
// byte-for-byte; the explicit label pins the pre-lift wording even though
// the auto-derived `pascal_to_spaced_lowercase("AtomKind")` projects to
// the same `"atom kind"` literal.
impl Sexp {
/// Canonical `(` char that opens a [`Self::List`] rendering AND
/// (paired with [`Self::LIST_CLOSE`]) the empty [`Self::Nil`]
/// rendering `()`. Outer-structural peer of [`Atom::STR_DELIMITER`]
/// on the atomic-payload delimiter axis: where `STR_DELIMITER` is
/// the ONE `"` byte the reader's tokenizer's FOUR
/// `Token::Str`-round-trip sites bind to on the closed-set [`Atom`]
/// algebra, `LIST_OPEN` is the ONE `(` byte the reader's tokenizer's
/// `Token::LParen` outer-dispatch arm AND the bare-atom terminator
/// disjunct AND [`fmt::Display for Sexp`]'s list-opening emission
/// AND [`Self::Nil`]'s two-char `()` rendering all bind to on the
/// closed-set outer [`Sexp`] algebra.
///
/// Pre-lift the same `'('` byte lived inline at FOUR sites: two
/// outer-match arms in `crate::reader::tokenize` (the
/// `Token::LParen` construction arm AND the bare-atom terminator's
/// `|| ch == '('` disjunct), and two Display arms in [`fmt::Display
/// for Sexp`] (the `Self::List(_)` opener AND the `Self::Nil`
/// two-char `()` rendering's left char). Post-lift the (typed
/// structural role, canonical byte) pairing binds at ONE constant
/// on the [`Sexp`] algebra that every consumer routes through; a
/// refactor that swaps the byte (e.g. a Racket-style port to `[`
/// for square-bracket list literals, an S-expression-DSL port to
/// `{` for brace-list syntax) touches ONE constant rather than
/// four inline bytes that would silently drift out of round-trip
/// agreement if one was updated without the others.
///
/// Load-bearing paired-delimiter contract:
/// `Sexp::LIST_OPEN` MUST pair section-for-retraction with
/// [`Self::LIST_CLOSE`] at every round-trip site — the reader's
/// `Token::LParen` (from `LIST_OPEN`) MUST be closed by a
/// `Token::RParen` (from `LIST_CLOSE`) for a well-formed list,
/// and the Display impl's `Self::List(_)` arm MUST emit
/// `LIST_OPEN` at the opener AND `LIST_CLOSE` at the closer for
/// the reader-then-Display round trip
/// `parse(display(list)) == list` to hold. Guards the paired
/// disjointness across the closed-set outer [`Sexp`] algebra so a
/// future refactor that renames one constant without updating the
/// other fails at rustc / test time rather than as a silent list-
/// rendering asymmetry.
///
/// Cross-axis disjointness with the sibling delimiters (pinned
/// structurally at
/// `sexp_list_delimiters_distinct_from_every_other_algebra_marker`):
/// `LIST_OPEN`'s byte MUST differ from [`Atom::STR_DELIMITER`]
/// (`'"'`), [`Atom::KEYWORD_MARKER`] (`":"`), the two
/// [`Atom::bool_literal`] spellings (`"#t"` / `"#f"`) AND every
/// [`QuoteForm::lead_char`] projection (`'\''`, `` '`' ``, `','`)
/// on the substrate's outer-marker axes. Otherwise the reader's
/// `Token::LParen` outer-dispatch arm would ambiguously route
/// through a sibling algebra's arm.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (`Self::List` outer structure, canonical `(` opener) pairing
/// now binds at ONE constant on the closed-set outer [`Sexp`]
/// algebra regardless of which of the four consumer surfaces
/// reaches in. THEORY.md §VI.1 — generation over composition;
/// four byte-identical inline `'('` char literals across two
/// substrate files collapse onto ONE named constant, matching
/// the substrate's three-times rule. THEORY.md §V.1 — knowable
/// platform; the canonical list-opener byte becomes a
/// TYPE-level constant on the outer substrate algebra rather
/// than four inline bytes at four consumer surfaces across two
/// substrate files (`crate::reader` and `crate::ast`).
pub const LIST_OPEN: char = '(';
/// Canonical `)` char that closes a [`Self::List`] rendering AND
/// (paired with [`Self::LIST_OPEN`]) the empty [`Self::Nil`]
/// rendering `()`. See [`Self::LIST_OPEN`] for the substrate-wide
/// paired-delimiter contract, cross-axis disjointness, and theory
/// anchors — this constant is its section-for-retraction sibling
/// on the closer axis. Four consumer sites (the reader's
/// `Token::RParen` outer-dispatch arm, the bare-atom terminator's
/// `|| ch == ')'` disjunct, [`fmt::Display for Sexp`]'s
/// `Self::List(_)` closer, [`Self::Nil`]'s two-char `()`
/// rendering's right char) all bind here.
pub const LIST_CLOSE: char = ')';
/// Canonical paired list-delimiter closed-set ALL array — composes
/// [`Self::LIST_OPEN`] followed by [`Self::LIST_CLOSE`] in canonical
/// declaration order, forced-arity `[char; 2]` so a hypothetical
/// third list-delimiter row would extend this array + one algebra
/// constant in lockstep. Peer to [`Atom::SELF_ESCAPE_TABLE`]
/// (`[char; 2]` on the Str-payload self-escape sub-vocabulary axis
/// of the closed-set [`Atom`] algebra): where `SELF_ESCAPE_TABLE`
/// closes the two pattern-EQUALS-value inner-tokenizer arms of
/// `Atom::decode_str_escape` as ONE typed forced-arity array,
/// `LIST_DELIMITERS` closes the two outer-structural list-delimiter
/// arms of the reader's outer-dispatch as the analogous typed
/// forced-arity array one axis over on the closed-set outer
/// [`Sexp`] algebra.
///
/// Pre-lift the two-element `[Self::LIST_OPEN, Self::LIST_CLOSE]`
/// composition lived inline at TWO sites: the two `|| ch ==
/// Self::LIST_{OPEN,CLOSE}` disjuncts inside
/// [`Self::is_bare_atom_boundary`]'s reader-boundary projection
/// (spanning TWO of the SIX categories the projection carries), AND
/// the `[Sexp::LIST_OPEN, Sexp::LIST_CLOSE].iter().collect()` array
/// literal at the `Nil` Display composition-pin test that binds the
/// two-char `()` rendering to the two typed constants. Post-lift
/// the sub-vocabulary sweep binds at ONE typed forced-arity array
/// on the closed-set outer [`Sexp`] algebra rather than at two
/// inline algebra-constant enumerations per consumer. Adding a
/// hypothetical Racket-compat square-bracket list mode
/// (`[Self::LIST_OPEN, Self::LIST_CLOSE, Self::VEC_OPEN,
/// Self::VEC_CLOSE]`) would extend `LIST_DELIMITERS` ONCE +
/// `Self::is_bare_atom_boundary`'s sub-vocabulary sweep ONCE + two
/// new algebra constants (opener + closer) in lockstep; rustc's
/// forced-arity check on `[char; N]` binds the extension through
/// the array declaration site.
///
/// Structural invariant carried at the SHAPE level: `[char; 2]`
/// pairs section-for-retraction one-to-one with
/// [`Atom::SELF_ESCAPE_TABLE`]'s `[char; 2]` — the two arrays
/// sit on distinct closed-set algebras (outer-structural
/// list-delimiter vocabulary on [`Sexp`]; inner-Str-payload
/// self-escape vocabulary on [`Atom`]) but share the same
/// forced-arity shape at their respective sub-vocabulary
/// axes. A consumer that reaches for one of the two arrays
/// encodes its vocabulary's paired-role identity in the SHAPE
/// it iterates rather than in a per-site convention.
///
/// Composition law (round-trip): `LIST_DELIMITERS[0] ==
/// Self::LIST_OPEN` AND `LIST_DELIMITERS[1] == Self::LIST_CLOSE`
/// AND `LIST_DELIMITERS.len() == 2`. The forced-arity + canonical
/// declaration order together pin every downstream index-sweep
/// consumer to the (opener, closer) pairing at rustc time; a
/// reorder without reordering the underlying algebra constants
/// fails at the composition pin below.
///
/// Cross-axis disjointness pinned structurally at
/// [`sexp_list_delimiters_distinct_from_every_other_algebra_marker`]:
/// neither element aliases any sibling outer-marker char on the
/// substrate's other closed-set algebras — the Str-payload
/// delimiter (`Atom::STR_DELIMITER`), the Keyword-marker prefix
/// (`Atom::KEYWORD_MARKER_LEAD`), the Comment-lead byte
/// (`Self::COMMENT_LEAD`), every quote-family lead char
/// (`QuoteForm::lead_char`), and every Bool-literal spelling's
/// first char.
///
/// Theory anchor: THEORY.md §III — the typescape; the paired
/// (opener, closer) list-delimiter sub-vocabulary becomes a typed
/// forced-arity ALL array on the closed-set outer [`Sexp`]
/// algebra rather than as two inline algebra-constant
/// enumerations at every consumer that iterates the paired
/// delimiter axis. THEORY.md §V.1 — knowable platform; the
/// paired-delimiter sub-vocabulary now binds as load-bearing
/// typed data at the algebra level rather than as two per-site
/// disjuncts. THEORY.md §VI.1 — generation over composition; the
/// paired-delimiter (opener + closer) composition regenerates
/// identically through this ONE typed forced-arity array rather
/// than through two inline algebra-constant enumerations per
/// consumer.
pub const LIST_DELIMITERS: [char; 2] = [Self::LIST_OPEN, Self::LIST_CLOSE];
/// Canonical `;` char that begins a line-comment run in the reader's
/// tokenizer AND (as a bare-atom terminator disjunct) breaks a
/// `Token::Atom` accumulator when the byte is encountered mid-lexeme.
/// Outer-structural peer of [`Self::LIST_OPEN`] / [`Self::LIST_CLOSE`]
/// on the reader-discard axis: where `LIST_OPEN` / `LIST_CLOSE` are
/// the paired-delimiter constants that shape a `Sexp::List` payload
/// on the closed-set outer [`Sexp`] algebra, `COMMENT_LEAD` is the
/// ONE `;` byte the reader's tokenizer's TWO comment-boundary sites
/// bind to on the same outer algebra — the outer-dispatch arm that
/// begins a line-comment run (consuming through the trailing `\n`
/// which is itself absorbed by the whitespace disjunct in the outer
/// match) AND the bare-atom terminator disjunct that ends a
/// `Token::Atom` accumulator when it encounters this byte mid-lexeme
/// so a bare `foo;bar` source tokenizes as `Token::Atom("foo") @ 0`
/// followed by a discarded line-comment run rather than as ONE
/// `Token::Atom("foo;bar")` payload.
///
/// Pre-lift the same `';'` byte lived inline at TWO sites in
/// `crate::reader::tokenize`: the outer-match `';' => { … }`
/// line-comment arm AND the bare-atom terminator's `|| ch == ';'`
/// disjunct. Post-lift the (reader-discard role, canonical byte)
/// pairing binds at ONE constant on the [`Sexp`] algebra that both
/// consumer sites route through; a refactor that swaps the byte
/// (e.g. a Scheme R7RS-style port to `#;` datum-comment syntax, an
/// Emacs-style port to `#!` shebang-comment syntax) touches ONE
/// constant rather than two inline bytes that would silently drift
/// out of tokenizer agreement if one was updated without the other.
///
/// Reader-discard contract: `Sexp::COMMENT_LEAD` MUST NOT surface
/// as an atomic payload in any parsed [`Sexp`] — the outer-dispatch
/// arm consumes the byte AND every char up to (but not past) the
/// trailing `\n`, emitting NO token. The bare-atom terminator
/// disjunct breaks the `Token::Atom` accumulator EXACTLY on this
/// byte so the subsequent line-comment run reaches the outer arm
/// with its byte-offset intact. Both sites bind to ONE constant so
/// a regression that drifts ONE of the two disjuncts (e.g.
/// re-inlines `';'` at the outer arm while migrating the terminator
/// to a different byte) fails at rustc / test time rather than as
/// a silent tokenizer misclassification.
///
/// Cross-axis disjointness with the sibling markers (pinned
/// structurally at
/// `sexp_comment_lead_distinct_from_every_other_algebra_marker`):
/// `COMMENT_LEAD`'s byte MUST differ from [`Self::LIST_OPEN`]
/// (`'('`), [`Self::LIST_CLOSE`] (`')'`), [`Atom::STR_DELIMITER`]
/// (`'"'`), [`Atom::KEYWORD_MARKER`]'s lead byte (`':'`), the two
/// [`Atom::bool_literal`] spellings' lead byte (`'#'`) AND every
/// [`QuoteForm::lead_char`] projection (`'\''`, `` '`' ``, `','`)
/// on the substrate's outer-marker axes. Otherwise a bare `;foo`
/// lexeme would ambiguously route through the line-comment arm AND
/// a sibling algebra's arm at the reader's outer dispatch.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (reader-discard role, canonical `;` byte) pairing binds at ONE
/// constant on the closed-set outer [`Sexp`] algebra regardless of
/// which of the two consumer sites reaches in. THEORY.md §VI.1 —
/// generation over composition; two byte-identical inline `';'`
/// char literals across ONE substrate file collapse onto ONE named
/// constant, matching the substrate's three-times rule
/// (`\geq 2` PRIME-DIRECTIVE trigger). THEORY.md §V.1 — knowable
/// platform; the canonical comment-lead byte becomes a TYPE-level
/// constant on the outer substrate algebra rather than two inline
/// bytes at two consumer surfaces in `crate::reader`.
pub const COMMENT_LEAD: char = ';';
/// Canonical `\n` char that terminates a line-comment run in the
/// reader's tokenizer — the section-for-retraction sibling of
/// [`Self::COMMENT_LEAD`] on the reader-discard axis. Paired
/// opener/terminator peer of [`Self::LIST_OPEN`] /
/// [`Self::LIST_CLOSE`] on the outer-structural axis: where
/// [`Self::LIST_OPEN`] / [`Self::LIST_CLOSE`] are the two typed
/// constants that shape a `Sexp::List` payload, [`Self::COMMENT_LEAD`]
/// / [`Self::COMMENT_TERM`] are the two typed constants that shape
/// the reader's line-comment discard run. Both pairs live on the
/// closed-set outer [`Sexp`] algebra so the reader-discard axis
/// carries the same opener/closer discipline the outer-structural
/// axis has carried since the initial [`Self::LIST_OPEN`] /
/// [`Self::LIST_CLOSE`] lift.
///
/// Pre-lift the same `'\n'` byte lived inline at ONE site in
/// `crate::reader::tokenize` — the line-comment discard loop's
/// terminator check `if ch == '\n' { break; }`. Post-lift the
/// (reader-discard terminator role, canonical byte) pairing binds
/// at ONE constant on the [`Sexp`] algebra that the consumer site
/// routes through; a refactor that ports the reader to a different
/// line-break convention (e.g. Scheme R7RS `#;` datum-comment
/// terminated at the next well-formed datum, an Emacs-style port
/// with `\r\n` CRLF sequences, a Common-Lisp-style `#|…|#` block
/// comment closed by `|#`) touches ONE constant (or extends the
/// algebra by ONE peer method) rather than an inline byte.
///
/// Reader-discard contract: `Sexp::COMMENT_TERM` MUST NOT surface
/// as an atomic payload in any parsed [`Sexp`] — the reader's
/// [`Self::COMMENT_LEAD`] outer-dispatch arm consumes every byte
/// (INCLUDING this terminator) up to and including the FIRST
/// occurrence of [`Self::COMMENT_TERM`], emitting NO token. The
/// (lead, term) pair carries the SAME reader-discard invariant as
/// (LIST_OPEN, LIST_CLOSE) does on the outer-structural axis: both
/// bytes are structural markers that never appear in a token
/// payload.
///
/// Cross-axis disjointness with the sibling closed-set markers
/// (pinned structurally at
/// `sexp_comment_term_distinct_from_every_non_whitespace_algebra_marker`):
/// `COMMENT_TERM`'s byte MUST differ from every NON-whitespace
/// outer-marker char — [`Self::LIST_OPEN`], [`Self::LIST_CLOSE`],
/// [`Self::COMMENT_LEAD`], [`Atom::STR_DELIMITER`],
/// [`Atom::STR_ESCAPE_LEAD`], [`Atom::KEYWORD_MARKER`]'s lead byte,
/// the two [`Atom::bool_literal`] spellings' lead byte, AND every
/// [`QuoteForm::lead_char`] projection. The terminator IS a
/// whitespace char (it satisfies `char::is_whitespace`) so the
/// disjointness test explicitly excludes the whitespace-family
/// axis: the terminator's role IS to be whitespace-family, so the
/// disjointness contract binds only against the non-whitespace
/// outer-marker axes.
///
/// Interaction with the escape-decode codomain axis: the terminator
/// byte `'\n'` COINCIDES with the C0 control byte
/// [`Atom::decode_str_escape`]`('n')` produces — the two roles are
/// distinct algebraic axes (reader-discard structural marker on
/// the outer [`Sexp`] algebra vs. Str-escape shorthand codomain
/// value on the inner [`Atom`] algebra) so the collision at the
/// byte level is by design, NOT a disjointness violation. A `\n`
/// byte APPEARING inside a `Token::Str` payload's decoded output
/// (via `\n` shorthand) is orthogonal to a `\n` byte APPEARING as
/// the line-comment terminator at the reader's outer-dispatch
/// discard loop.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (reader-discard terminator role, canonical `\n` byte) pairing
/// binds at ONE constant on the closed-set outer [`Sexp`] algebra
/// regardless of which consumer reaches in. THEORY.md §II.1
/// invariant 5 — composition preserves proofs; the paired
/// (COMMENT_LEAD, COMMENT_TERM) shape now lives at the algebra
/// alongside (LIST_OPEN, LIST_CLOSE), so the reader-discard axis
/// carries the SAME opener/closer discipline as the outer-
/// structural axis. THEORY.md §VI.1 — generation over composition;
/// the reader's inline `'\n'` char literal at the line-comment
/// discard loop's terminator check collapses onto ONE named
/// constant on the substrate algebra. THEORY.md §V.1 — knowable
/// platform; the canonical line-comment terminator byte becomes
/// a TYPE-level constant on the outer substrate algebra rather
/// than an inline `'\n'` at one consumer surface in
/// `crate::reader::tokenize`.
pub const COMMENT_TERM: char = '\n';
/// Canonical paired line-comment delimiter closed-set ALL array —
/// composes [`Self::COMMENT_LEAD`] followed by [`Self::COMMENT_TERM`]
/// in canonical (opener, terminator) declaration order, forced-arity
/// `[char; 2]` so a hypothetical alternative comment convention (a
/// Scheme R7RS `#;` datum-comment lead paired with a next-datum
/// terminator, an Emacs-style CRLF paired terminator, a Common-Lisp
/// `#|…|#` block comment closed by `|#`) would extend this array +
/// one algebra constant per new row in lockstep — rustc's forced-
/// arity check on `[char; N]` binds the extension through the array
/// declaration site.
///
/// Cross-axis peer to [`Self::LIST_DELIMITERS`] (`[char; 2]` on the
/// outer-structural paired-delimiter axis of the SAME closed-set
/// outer [`Sexp`] algebra) — both close a paired-role byte
/// sub-vocabulary at the SAME shape (`[char; 2]`, `(opener,
/// closer_or_terminator)` canonical declaration order) but on
/// DISTINCT roles: [`Self::LIST_DELIMITERS`] closes the two typed
/// constants that shape a [`Self::List`] payload
/// ([`Self::LIST_OPEN`] / [`Self::LIST_CLOSE`], BOTH of which
/// classify as bare-atom boundaries and both non-whitespace);
/// [`Self::COMMENT_DELIMITERS`] closes the two typed constants that
/// shape the reader's line-comment discard run
/// ([`Self::COMMENT_LEAD`] / [`Self::COMMENT_TERM`], where the LEAD
/// row is a bare-atom boundary AND non-whitespace, and the TERM row
/// is a whitespace-family char absorbed by the reader's
/// `ch.is_whitespace()` outer-dispatch arm rather than a distinct
/// bare-atom boundary). The two arrays partition the SIX-category
/// outer-dispatch arm-set into a per-axis paired shape (2 rows for
/// list delimiters + 2 rows for comment delimiters + 1 row for
/// [`Atom::STR_DELIMITER`] + 3-of-4 rows for [`QuoteForm::LEADS`] +
/// the residual whitespace family), each axis carrying its own
/// forced-arity ALL array.
///
/// Also sibling-shape to [`Atom::SELF_ESCAPE_TABLE`] (`[char; 2]` on
/// the inner-Str-payload self-escape sub-vocabulary axis of the
/// closed-set [`Atom`] algebra), [`Atom::BOOL_LITERALS`]
/// (`[&'static str; 2]` on the Scheme-bool spelling axis), and
/// [`crate::error::UnquoteForm::MARKERS`] / [`crate::error::UnquoteForm::IAC_FORGE_TAGS`]
/// (`[&'static str; 2]` on the template-substitution subset algebra
/// — the 2-of-4 subset carving of [`QuoteForm`]) — every closed-set
/// outer projection on the substrate that carries a paired-role
/// two-row axis now pins its canonical bytes at ONE `pub const` per
/// role plus a forced-arity ALL array for family-wide consumers.
///
/// Pre-lift the two-element `[Self::COMMENT_LEAD, Self::COMMENT_TERM]`
/// composition had NO typed source of truth on the substrate — the
/// two constants each existed independently on the algebra
/// ([`Self::COMMENT_LEAD`] shipped in the initial reader-discard
/// lift; [`Self::COMMENT_TERM`] shipped in the follow-on paired-
/// terminator lift `bb1bd5e`) and consumers that wanted the
/// (opener, terminator) shape had to reach across the algebra
/// through TWO `pub const` sites. Post-lift the paired-role
/// sub-vocabulary binds at ONE forced-arity ALL array on the closed-
/// set outer [`Sexp`] algebra alongside the peer
/// [`Self::LIST_DELIMITERS`] array on the outer-structural axis; a
/// consumer that walks EITHER axis of the outer-structural /
/// reader-discard cross-product reads the paired-role identity off
/// the shared `[char; 2]` shape.
///
/// Structural invariant carried at the SHAPE level: [`char; 2`]
/// pairs section-for-retraction one-to-one with
/// [`Self::LIST_DELIMITERS`]'s `[char; 2]` — the two arrays sit at
/// distinct roles on the SAME closed-set outer [`Sexp`] algebra
/// (outer-structural payload-delimiter role for `LIST_DELIMITERS`;
/// reader-discard opener/terminator role for `COMMENT_DELIMITERS`)
/// but share the same forced-arity shape at their respective axes.
/// A consumer that reaches for one of the two arrays encodes its
/// axis's paired-role identity in the SHAPE it iterates rather than
/// in a per-site convention.
///
/// Composition law (round-trip): `COMMENT_DELIMITERS[0] ==
/// Self::COMMENT_LEAD` AND `COMMENT_DELIMITERS[1] ==
/// Self::COMMENT_TERM` AND `COMMENT_DELIMITERS.len() == 2`. The
/// forced-arity + canonical declaration order together pin every
/// downstream index-sweep consumer to the (opener, terminator)
/// pairing at rustc time; a reorder without reordering the
/// underlying algebra constants fails at the composition pin below.
///
/// Path-uniformity contract pinned per-row: `COMMENT_DELIMITERS[0]`
/// (the LEAD row) MUST classify as a bare-atom boundary via
/// [`Self::is_bare_atom_boundary`] (the reader's outer-dispatch's
/// dedicated line-comment arm is one of the SIX categories that
/// projection covers), AND `COMMENT_DELIMITERS[1]` (the TERM row)
/// MUST classify as a whitespace-family char via
/// [`char::is_whitespace`] (the reader's `ch.is_whitespace()` arm
/// absorbs the terminator so the discard loop's post-loop hand-off
/// to the outer-dispatch fires the whitespace arm rather than a
/// distinct comment-terminator arm). The per-row asymmetry is
/// LOAD-BEARING and structurally distinct from
/// [`Self::LIST_DELIMITERS`]'s BOTH-rows-are-bare-atom-boundaries
/// contract (both `(` and `)` are non-whitespace outer-dispatch
/// arms). Pinned by
/// `sexp_comment_delimiters_lead_row_is_bare_atom_boundary` +
/// `sexp_comment_delimiters_term_row_is_whitespace_family_char`.
///
/// Cross-axis disjointness pinned structurally at
/// `sexp_comment_delimiters_disjoint_from_list_delimiters`: no row
/// of `COMMENT_DELIMITERS` aliases any row of
/// [`Self::LIST_DELIMITERS`] — the reader-discard sub-vocabulary
/// and the outer-structural list-delimiter sub-vocabulary partition
/// their respective bytes disjointly on the SAME closed-set outer
/// [`Sexp`] algebra. Cross-algebra disjointness pinned at
/// `sexp_comment_delimiters_disjoint_from_str_delimiter`: no row
/// aliases [`Atom::STR_DELIMITER`] — the reader-discard arm and the
/// Str-payload arm partition their bytes across the two closed-set
/// algebras disjointly.
///
/// Future consumers that compose against [`Self::COMMENT_DELIMITERS`]:
/// a hypothetical `tatara_lisp_comment_delimiter_total{delimiter=";"|"\n"}`
/// Sekiban metric surface at Prometheus recording time — the
/// label-set generator sweeps this array verbatim rather than
/// re-typing the two paired bytes inline at each recorder, and
/// rustc-binds the metric-label set to the closed set through the
/// forced-arity ALL array; an LSP / structural-editor that
/// highlights line-comment runs — the (opener, terminator) pair the
/// editor spans over IS this array's two rows; a hypothetical
/// `Sexp::BLOCK_COMMENT_DELIMITERS` peer array for a future
/// `#|…|#` block-comment mode would follow the same shape
/// mechanically, extending the reader-discard axis by ONE peer
/// array without touching this one's shape.
///
/// Theory anchor: THEORY.md §III — the typescape; the paired
/// (opener, terminator) reader-discard sub-vocabulary of the
/// reader's outer-dispatch arm-set now binds at ONE typed `[char;
/// 2]` array on the closed-set outer [`Sexp`] algebra rather than
/// as two independent algebra constants (`Self::COMMENT_LEAD`,
/// `Self::COMMENT_TERM`) accessed independently at every consumer
/// that wants the paired-role shape. The shared `[char; 2]` shape
/// with [`Self::LIST_DELIMITERS`] encodes the paired-role identity
/// relation across the two axes of the SAME closed-set algebra at
/// the type system level. THEORY.md §V.1 — knowable platform; the
/// paired-discard-delimiter sub-vocabulary becomes load-bearing
/// typed data on the closed-set outer [`Sexp`] algebra. THEORY.md
/// §VI.1 — generation over composition; the paired-delimiter
/// (opener + terminator) composition regenerates identically
/// through this ONE typed forced-arity array rather than through
/// two independent algebra constants at every consumer. THEORY.md
/// §II.1 invariant 5 — composition preserves proofs; the two-axis
/// (outer-structural, reader-discard) cross-product on the closed-
/// set outer [`Sexp`] algebra now carries the SAME opener/closer
/// discipline on BOTH axes through two forced-arity ALL arrays
/// with byte-identical shape.
pub const COMMENT_DELIMITERS: [char; 2] = [Self::COMMENT_LEAD, Self::COMMENT_TERM];
/// Closed-set forced-arity ALL array over the SEVEN non-whitespace
/// category-leading chars the reader's outer-dispatch cascade
/// specialises on — the reader-level boundary sub-vocabulary that
/// paired with `char::is_whitespace()` closes the six-clause
/// [`Self::is_bare_atom_boundary`] disjunction. Composes through
/// seven typed `pub const` primitives spanning THREE type namespaces
/// on the SAME reader-outer-dispatch axis of the substrate:
/// * [`Self::LIST_OPEN`] (`'('`) — the outer-structural list-opening
/// delimiter on the outer [`Sexp`] algebra;
/// * [`Self::LIST_CLOSE`] (`')'`) — the outer-structural list-closing
/// delimiter on the outer [`Sexp`] algebra;
/// * [`QuoteForm::QUOTE_LEAD`] (`'\''`) — the [`QuoteForm::Quote`]
/// reader-punctuation lead byte on the quote-family sub-algebra;
/// * [`QuoteForm::QUASIQUOTE_LEAD`] (`` '`' ``) — the
/// [`QuoteForm::Quasiquote`] reader-punctuation lead byte;
/// * [`QuoteForm::UNQUOTE_LEAD`] (`','`) — the shared
/// [`QuoteForm::Unquote`] / [`QuoteForm::UnquoteSplice`] reader-
/// punctuation lead byte (disambiguated at the second-char peek
/// via [`QuoteForm::promote_via_next_char`]);
/// * [`Atom::STR_DELIMITER`] (`'"'`) — the Str-payload opening /
/// closing delimiter on the closed-set [`Atom`] algebra;
/// * [`Self::COMMENT_LEAD`] (`';'`) — the line-comment opener on
/// the outer [`Sexp`] algebra (paired with [`Self::COMMENT_TERM`]
/// inside the discard loop — but the TERM is a run-boundary
/// marker inside a comment run, NOT a reader-outer-dispatch
/// category-leading char, so it is intentionally omitted from
/// this ALL array).
///
/// Cross-axis peer to [`Self::LIST_DELIMITERS`] (`[char; 2]` on the
/// outer-structural payload-delimiter axis) and [`Self::COMMENT_DELIMITERS`]
/// (`[char; 2]` on the reader-discard opener/terminator axis) at
/// ONE algebra level up: those two arrays close their respective
/// paired-role sub-vocabularies (opener + closer, opener + terminator)
/// on the reader-INNER axis of the outer [`Sexp`] algebra; this
/// array closes the reader-OUTER-dispatch category-leading char
/// sub-vocabulary across the SAME closed-set outer [`Sexp`] algebra
/// PLUS its two sibling sub-algebras ([`QuoteForm`], [`Atom`]) at
/// ONE family-wide `[char; 7]` primitive. Sibling-shape peer of the
/// intra-algebra sub-vocabulary array [`QuoteForm::LEADS`]
/// (`[char; 3]` — the three DISTINCT quote-family reader-lead
/// bytes) which this array embeds as its middle three positions:
/// where [`QuoteForm::LEADS`] closes the quote-family sub-carving's
/// reader-lead sub-vocabulary at ONE forced-arity array on ONE
/// closed-set algebra, this array closes the FULL reader-outer-
/// dispatch non-whitespace category-leading char sub-vocabulary at
/// ONE forced-arity array on the outer [`Sexp`] algebra by
/// composing through the three-arm quote-family sub-carving + the
/// two-arm structural-delimiter sub-carving + the two-arm atomic-
/// carve delimiter + comment-lead singletons.
///
/// Pre-lift the seven category-leading chars had NO family-wide
/// array on the outer [`Sexp`] algebra — [`Self::is_bare_atom_boundary`]
/// carried them as three sub-expressions (`Self::LIST_DELIMITERS.contains(&ch)`
/// on the structural-delimiter axis, `QuoteForm::from_lead_char(ch).is_some()`
/// on the quote-family axis, `ch == Atom::STR_DELIMITER || ch ==
/// Self::COMMENT_LEAD` on the singleton axes) unified through boolean
/// disjunction. Post-lift the WHOLE non-whitespace terminator sub-
/// vocabulary binds at ONE `pub const [char; 7]` array on the outer
/// [`Sexp`] algebra so [`Self::is_bare_atom_boundary`] collapses to
/// `ch.is_whitespace() || Self::NON_WHITESPACE_BARE_ATOM_TERMINATORS.contains(&ch)`
/// — TWO clauses (one whitespace-partial predicate + one
/// contains-check on the family-wide ARRAY) rather than five
/// sub-clauses spanning three type namespaces. Consumers keyed on
/// the whole family (a `tatara-check` predicate `(check-reader-
/// outer-dispatch-terminator-partition-injective …)` that verifies
/// the seven-arm partition structurally, a future REPL / LSP
/// tokenizer-boundary hint that scans the source for the reader-
/// outer-dispatch category-leading chars upfront, a future
/// completion generator that suggests the seven bytes at every
/// bare-atom-lexeme insertion site) read through
/// [`Self::NON_WHITESPACE_BARE_ATOM_TERMINATORS`] without re-deriving
/// the three-part sub-expression composition inline.
///
/// Composition law (forward): for every `ch: char`,
/// `Self::NON_WHITESPACE_BARE_ATOM_TERMINATORS.contains(&ch) ==
/// (Self::LIST_DELIMITERS.contains(&ch) ||
/// QuoteForm::from_lead_char(ch).is_some() ||
/// ch == Atom::STR_DELIMITER || ch == Self::COMMENT_LEAD)` — pinned
/// by `sexp_non_whitespace_bare_atom_terminators_agree_with_pre_lift_sub_expression_disjunction`.
/// Boundary-predicate composition law:
/// `Self::is_bare_atom_boundary(ch) == (ch.is_whitespace() ||
/// Self::NON_WHITESPACE_BARE_ATOM_TERMINATORS.contains(&ch))` —
/// pinned by `sexp_is_bare_atom_boundary_agrees_with_terminators_array_on_non_whitespace_partition`.
///
/// Adding a hypothetical seventh reader-outer-dispatch category
/// (e.g. `#|…|#` block-comment lead byte, `#\` char-literal prefix,
/// `#[` vector-literal prefix — each pinning a new lead byte on
/// [`Self`] or a fresh sub-algebra) extends this array AND
/// [`Self::is_bare_atom_boundary`]'s indirect coverage in
/// LOCKSTEP — rustc's forced-arity check on `[char; 7]` fails
/// compilation if the algebra grows without the array (or the
/// array without the algebra).
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (reader-outer-dispatch category, canonical char) family-wide
/// pairing binds at ONE typed `[char; 7]` array on the outer
/// [`Sexp`] algebra regardless of which of the three sub-algebras
/// the individual chars name their per-role `pub const` primitive
/// on. THEORY.md §III — the typescape; the seven canonical
/// reader-outer-dispatch category-leading bytes bind at ONE typed
/// `[char; 7]` array on the outer [`Sexp`] algebra rather than at
/// three-part sub-expression composition inline at
/// [`Self::is_bare_atom_boundary`]. THEORY.md §V.1 — knowable
/// platform; the family's cardinality becomes a TYPE-level constant
/// on the substrate algebra rather than a per-consumer hand-rolled
/// enumeration of the seven chars. THEORY.md §VI.1 — generation over
/// composition; the family-wide contract sweeps (routing through
/// typed sub-algebra `pub const` primitives, pairwise distinctness,
/// agreement with the pre-lift sub-expression disjunction) emerge
/// from the composition of EIGHT substrate primitives (this
/// `pub const [char; 7]` array + the seven sub-algebra `pub const`
/// primitives) rather than as inline disjunctions at each call site.
pub const NON_WHITESPACE_BARE_ATOM_TERMINATORS: [char; 7] = [
Self::LIST_OPEN,
Self::LIST_CLOSE,
QuoteForm::QUOTE_LEAD,
QuoteForm::QUASIQUOTE_LEAD,
QuoteForm::UNQUOTE_LEAD,
Atom::STR_DELIMITER,
Self::COMMENT_LEAD,
];
/// Reader-level boundary predicate — returns `true` iff `ch` is one
/// of the SIX outer-dispatch category-leading chars the reader's
/// tokenizer specialises on: whitespace, [`Self::LIST_OPEN`],
/// [`Self::LIST_CLOSE`], any [`QuoteForm::lead_char`] (via the
/// closed-set [`QuoteForm::from_lead_char`] decode),
/// [`Atom::STR_DELIMITER`], AND [`Self::COMMENT_LEAD`]. The ONE
/// typed projection on the outer [`Sexp`] algebra that names the
/// disjunction of "the char would start a NEW reader-level token
/// (or a discarded run) rather than feed the current bare-atom
/// accumulator."
///
/// Structural dual of the reader's outer-dispatch cascade in
/// `crate::reader::tokenize`: the outer-dispatch has FIVE specific
/// arms (`ws if ws.is_whitespace()`, `Self::COMMENT_LEAD`,
/// `Self::LIST_OPEN`, `Self::LIST_CLOSE`, `Atom::STR_DELIMITER`)
/// plus ONE pre-match `QuoteForm::from_lead_char(c).is_some()`
/// gate — SIX categories in total. The default `_ => { …
/// bare-atom accumulator … }` arm fires EXACTLY when every specific
/// arm rejects. This method is the typed projection of that
/// implicit disjunction: `Sexp::is_bare_atom_boundary(ch) == true`
/// iff `ch` would trigger one of the SIX specific arms, and
/// `false` iff `ch` would fall through to the bare-atom
/// accumulator's default arm. The two consumer sites in
/// `crate::reader::tokenize` — the outer-dispatch's implicit "no
/// specific arm fires" residual predicate AND the bare-atom
/// accumulator's terminator disjunct — now share ONE typed source
/// of truth on the closed-set outer [`Sexp`] algebra.
///
/// Pre-lift the SIX-clause boolean chain
/// (`ch.is_whitespace() || ch == Sexp::LIST_OPEN || ch ==
/// Sexp::LIST_CLOSE || QuoteForm::from_lead_char(ch).is_some() ||
/// ch == Atom::STR_DELIMITER || ch == Sexp::COMMENT_LEAD`) lived
/// inline at the bare-atom accumulator's terminator gate in
/// `crate::reader::tokenize`, spanning THREE type namespaces
/// ([`Sexp`], [`Atom`], [`QuoteForm`]) at ONE consumer site.
/// Post-lift the WHOLE disjunction binds at ONE typed projection
/// on the outer [`Sexp`] algebra so a refactor that adds a
/// SEVENTH outer-dispatch category (e.g. `#|…|#` block-comment
/// lead byte, `#\` char-literal prefix, `#[` vector-literal
/// prefix) extends the algebra ONCE (via a new arm on THIS method
/// AND a matching outer-dispatch arm in the reader) rather than
/// mutating an inline six-clause boolean chain that would silently
/// drift out of tokenizer agreement if one clause was added
/// without the other. Sibling-shape peer of the outer-dispatch's
/// closed-set per-category projections
/// ([`QuoteForm::from_lead_char`] on the quote-family axis;
/// [`Atom::decode_str_escape`] on the Str-escape axis): where those
/// two methods each lift ONE outer-dispatch category's decode onto
/// its typed algebra, THIS method lifts the DISJUNCTION of ALL SIX
/// outer-dispatch categories onto the outer [`Sexp`] algebra as
/// a bool predicate.
///
/// Composition law (forward): for every char `ch` and every
/// substrate-marker enumeration
/// `Self::{LIST_OPEN, LIST_CLOSE, COMMENT_LEAD}`,
/// `Atom::STR_DELIMITER`, `QuoteForm::from_lead_char(ch).is_some()`,
/// `is_bare_atom_boundary` returns `true`; for every char that
/// isn't whitespace AND isn't listed on any marker axis, returns
/// `false`. Reader-level composition law:
/// `read(format!("foo{ch}"))` tokenizes as `[Token::Atom("foo"),
/// …trailing token(s) from `ch`]` when
/// `Self::is_bare_atom_boundary(ch)` is `true`, and as
/// `[Token::Atom(format!("foo{ch}"))]` (ONE token) when it is
/// `false`.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (reader-level boundary role, canonical char) pairing binds at
/// ONE typed projection on the outer [`Sexp`] algebra regardless
/// of which of the SIX outer-dispatch category-leading chars is
/// under test. THEORY.md §VI.1 — generation over composition; a
/// SIX-clause inline boolean disjunction spanning THREE type
/// namespaces collapses onto ONE named method — the substrate's
/// three-times rule saturated at the outer-dispatch's disjunction.
/// THEORY.md §V.1 — knowable platform; the canonical reader-level
/// boundary predicate becomes a TYPE-level method on the outer
/// substrate algebra rather than an inline six-clause boolean
/// chain at ONE consumer site inside `crate::reader::tokenize`.
#[must_use]
pub fn is_bare_atom_boundary(ch: char) -> bool {
ch.is_whitespace() || Self::NON_WHITESPACE_BARE_ATOM_TERMINATORS.contains(&ch)
}
/// Canonical [`Self::Atom`]-[`Atom::Symbol`] outer constructor —
/// composes [`Atom::symbol`] (the typed-construct method on the
/// closed-set [`Atom`] algebra) under the [`Self::Atom`] outer
/// wrapper. The first of six `Self::Atom(Atom::X(_))` outer
/// constructors all routing through the typed [`Atom`] construct
/// family at the inner algebra so the `.into()` coercion + tuple-
/// variant constructor pair lives at ONE site per kind on the
/// [`Atom`] algebra rather than at this outer constructor's body.
/// Sibling-shape lift to the [`Atom::as_X`] /
/// [`Self::as_X`] composition through [`Self::as_atom`] on the
/// projection axis: where projections route OUTER `Self::as_X`
/// through `self.as_atom().and_then(Atom::as_X)`, constructions
/// route OUTER `Self::X` through `Self::Atom(Atom::X(payload))`.
///
/// Composition law (forward): `Sexp::symbol(s) ==
/// Sexp::Atom(Atom::symbol(s))` for every `s: impl Into<String>`.
/// Round-trip law (with the soft-projection sibling): for every
/// `s: &str`, `Sexp::symbol(s).as_symbol() == Some(s)` — the inner
/// algebra's section-for-retraction surfaces through the outer
/// algebra without re-derivation. Same posture across the six
/// sibling pairs.
#[must_use]
pub fn symbol(s: impl Into<String>) -> Self {
Self::Atom(Atom::symbol(s))
}
/// Canonical [`Self::Atom`]-[`Atom::Keyword`] outer constructor —
/// composes [`Atom::keyword`] under [`Self::Atom`]. See
/// [`Self::symbol`] for the outer-algebra docstring.
#[must_use]
pub fn keyword(s: impl Into<String>) -> Self {
Self::Atom(Atom::keyword(s))
}
/// Canonical [`Self::Atom`]-[`Atom::Str`] outer constructor —
/// composes [`Atom::string`] under [`Self::Atom`].
#[must_use]
pub fn string(s: impl Into<String>) -> Self {
Self::Atom(Atom::string(s))
}
/// Canonical [`Self::Atom`]-[`Atom::Int`] outer constructor —
/// composes [`Atom::int`] under [`Self::Atom`].
#[must_use]
pub fn int(n: i64) -> Self {
Self::Atom(Atom::int(n))
}
/// Canonical [`Self::Atom`]-[`Atom::Float`] outer constructor —
/// composes [`Atom::float`] under [`Self::Atom`].
#[must_use]
pub fn float(n: f64) -> Self {
Self::Atom(Atom::float(n))
}
/// Canonical [`Self::Atom`]-[`Atom::Bool`] outer constructor —
/// composes [`Atom::boolean`] under [`Self::Atom`].
#[must_use]
pub fn boolean(b: bool) -> Self {
Self::Atom(Atom::boolean(b))
}
/// Canonical [`Self::Quote`] outer constructor — composes
/// [`QuoteForm::wrap`] on the [`QuoteForm::Quote`] marker so the
/// `Box::new(inner)` allocation + tuple-variant pair lives at ONE
/// site on the closed-set [`QuoteForm`] algebra rather than at
/// this outer-constructor body. The first of four `Self::Quote*`
/// outer constructors all routing through the typed
/// [`QuoteForm::wrap`] family at the inner algebra — the
/// quote-family-axis section peer of the six `Self::Atom(Atom::X(_))`
/// outer constructors ([`Self::symbol`], [`Self::keyword`],
/// [`Self::string`], [`Self::int`], [`Self::float`],
/// [`Self::boolean`]) all routing through the typed [`Atom`]
/// construct family on the atomic-payload axis. Sibling-shape lift
/// to the [`Self::as_quote_form`] soft-projection sibling on the
/// projection axis: where the projection soft-decomposes a
/// quote-family wrapper into `Option<(QuoteForm, &Sexp)>` (surfacing
/// the typed marker alongside the borrowed inner body), each of
/// these four typed constructors embeds a fresh inner body under
/// the typed marker into the matching tuple-variant wrapper.
///
/// Composition law (forward): `Sexp::quote(inner) ==
/// QuoteForm::Quote.wrap(inner) == Sexp::Quote(Box::new(inner))`
/// for every `inner: Sexp`. Round-trip law (section-for-retraction
/// with the soft-projection sibling): `Sexp::quote(inner)
/// .as_quote_form() == Some((QuoteForm::Quote, &inner))` for every
/// `inner: Sexp` — the inner algebra's typed constructor pairs
/// section-for-retraction with the outer algebra's soft
/// projection, and the marker + inner body cross-projection
/// preserves identity. Same posture across the four sibling
/// pairs (`Sexp::quote` / `Sexp::quasiquote` / `Sexp::unquote` /
/// `Sexp::unquote_splice`).
///
/// Pre-lift the `Self::Quote(Box::new(inner))` welded triple
/// (`Self::Quote`, `Box::new`, `inner`) appeared inline at every
/// consumer that builds a quote-family wrapper — well past the ≥2
/// PRIME-DIRECTIVE trigger once the structural shape is named. The
/// welded triple already lives at ONE site on the closed-set
/// [`QuoteForm::wrap`] algebra for the marker-driven consumer path;
/// this outer constructor binds the per-variant `Sexp::X(Box::new(
/// inner))` welded triple to ONE typed-algebra method per marker on
/// the outer [`Sexp`] algebra, so consumers that know the marker at
/// compile time bind to the typed method directly rather than
/// re-deriving the `Self::X(Box::new(_))` pair inline. A future
/// allocation-policy change (e.g. arena-allocated wrappers for
/// span-aware [`Sexp`]) lands as ONE edit at [`QuoteForm::wrap`]
/// (the single site the allocation composition lives) and
/// propagates through these four typed constructors byte-for-byte.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (QuoteForm variant, [`Sexp`] tuple-variant constructor) pairing
/// binds at ONE typed-algebra method per marker on the outer
/// [`Sexp`] algebra regardless of which consumer reaches in.
/// THEORY.md §VI.1 — generation over composition; the welded
/// `Self::X(Box::new(_))` triple at every quote-family construct
/// site regenerates through `QuoteForm::X.wrap(_)` composition over
/// the typed algebra rather than per-site re-derivation. THEORY.md
/// §V.1 — knowable platform; the typed-construct family becomes a
/// TYPE projection on the substrate's outer [`Sexp`] algebra sitting
/// next to the typed-project family [`Self::as_quote_form`] rather
/// than as bare tuple-variant constructor + per-site `Box::new`
/// discipline. A future fifth homoiconic prefix syntax (e.g. syntax
/// quotation `#'x` for hygienic macros) extends [`QuoteForm::ALL`] +
/// [`QuoteForm::wrap`]'s arm + this construct family in lockstep,
/// rustc-enforced through the closed-set exhaustiveness.
///
/// Frontier inspiration: Racket's `(quote x)` /
/// `(quasiquote x)` / `(unquote x)` / `(unquote-splicing x)` typed
/// syntactic-form construct face paired one-for-one with the
/// [`Self::as_quote_form`] closed-set soft-projection sibling on
/// the outer syntax algebra — the typed-construct + typed-project
/// algebra dual is closed at one method per direction per marker
/// on Racket's surface, and the [`Self::quote`] /
/// [`Self::quasiquote`] / [`Self::unquote`] / [`Self::unquote_splice`]
/// family is the Rust-typed peer on the closed-set outer [`Sexp`]
/// algebra with [`QuoteForm::wrap`] standing in for Racket's typed
/// dispatch face. MLIR's `mlir::OpBuilder::create<QuoteOp>(loc,
/// inner)` typed-IR wrapper construction paired with
/// `mlir::dyn_cast<QuoteOp>(op)` on the projection face — the typed
/// factory + typed downcast pair the IR algebra closes over on
/// every wrapper op; [`Self::quote`] / [`Self::as_quote_form`] is
/// the Rust-typed peer on the outer [`Sexp`] algebra with the
/// closed-set [`QuoteForm`] standing in for MLIR's `OperationName`
/// taxonomy over the wrapper-op family.
#[must_use]
pub fn quote(inner: Sexp) -> Self {
QuoteForm::Quote.wrap(inner)
}
/// Canonical [`Self::Quasiquote`] outer constructor — composes
/// [`QuoteForm::wrap`] on the [`QuoteForm::Quasiquote`] marker.
/// See [`Self::quote`] for the outer-algebra docstring.
#[must_use]
pub fn quasiquote(inner: Sexp) -> Self {
QuoteForm::Quasiquote.wrap(inner)
}
/// Canonical [`Self::Unquote`] outer constructor — composes
/// [`QuoteForm::wrap`] on the [`QuoteForm::Unquote`] marker.
/// See [`Self::quote`] for the outer-algebra docstring.
#[must_use]
pub fn unquote(inner: Sexp) -> Self {
QuoteForm::Unquote.wrap(inner)
}
/// Canonical [`Self::UnquoteSplice`] outer constructor — composes
/// [`QuoteForm::wrap`] on the [`QuoteForm::UnquoteSplice`] marker.
/// See [`Self::quote`] for the outer-algebra docstring.
#[must_use]
pub fn unquote_splice(inner: Sexp) -> Self {
QuoteForm::UnquoteSplice.wrap(inner)
}
/// Canonical marker-driven quote-family outer constructor — routes
/// through [`QuoteForm::wrap`] on the caller-supplied [`QuoteForm`]
/// marker at ONE site on the closed-set [`Sexp`] algebra. The outer-
/// algebra section-for-retraction sibling of the existing
/// [`Self::as_quote_form`] soft-projection ([`Option<(QuoteForm,
/// &Sexp)>`]): where the projection soft-decomposes a quote-family
/// wrapper into its typed [`QuoteForm`] marker + borrowed inner body
/// on the (marker, borrowed-inner) product, this constructor embeds
/// a typed [`QuoteForm`] marker + owned inner body pair into the
/// matching tuple-variant wrapper on the (marker, owned-inner)
/// product. Marker-driven parent of the four per-variant siblings
/// [`Self::quote`] / [`Self::quasiquote`] / [`Self::unquote`] /
/// [`Self::unquote_splice`] — each of the four is `Self::quote_form(
/// QuoteForm::X, inner)` restricted to a compile-time-known marker;
/// this constructor is the marker-abstracted parent every consumer
/// that binds the marker as a runtime value routes through.
///
/// Sibling posture across the outer-algebra construct-family layer:
/// where [`Self::call`](Self::call) and [`Self::named_call`](Self::named_call)
/// close the (construct, project) dual on the call-form + named-
/// call-form typed decompositions of the residual-axis List arm,
/// and [`Self::list`](Self::list) closes it on the residual-axis
/// List arm itself, this constructor closes it on the quote-family-
/// axis wrapper decomposition — the outer [`Sexp`] algebra now
/// carries a (marker, project) construct-family dual pair for every
/// axis of the [`SexpShape`] closed set at ONE typed method per
/// corner, with `Sexp::quote_form(qf, inner)` as the marker-driven
/// quote-family construct entry and [`Self::as_quote_form`] as its
/// marker-recovering projection sibling.
///
/// Composition law (forward): `Sexp::quote_form(marker, inner) ==
/// marker.wrap(inner)` for every `marker: QuoteForm` and every
/// `inner: Sexp`. The body routes through the SAME closed-set
/// `QuoteForm::wrap` method the four per-variant siblings
/// ([`Self::quote`] / [`Self::quasiquote`] / [`Self::unquote`] /
/// [`Self::unquote_splice`]) already reach for, so the (marker,
/// [`Sexp`] tuple-variant constructor) pairing binds at ONE closed-
/// set match on the substrate algebra — a regression that drifts
/// one consumer's marker→wrapper mapping from the others (e.g. a
/// copy-edit that pairs [`QuoteForm::Quote`] with the
/// [`Sexp::Quasiquote`] tuple variant, or that drops a
/// [`QuoteForm::UnquoteSplice`] value through the
/// [`Sexp::Unquote`] tuple variant) cannot reach the substrate's
/// runtime.
///
/// Round-trip law (section-for-retraction with the outer-algebra
/// soft-projection): for every `marker: QuoteForm` and every
/// `inner: Sexp`, `Sexp::quote_form(marker, inner.clone())
/// .as_quote_form() == Some((marker, &inner))` — the outer
/// algebra's marker-driven quote-family constructor pairs section-
/// for-retraction with the outer algebra's soft quote-family
/// projection, and the (marker, inner body) cross-projection
/// preserves identity for every `QuoteForm` variant.
///
/// Marker-recovering projection composition: `Sexp::quote_form(
/// marker, inner).as_quote_form_marker() == Some(marker)` for every
/// input — the marker-only projection sibling
/// ([`Self::as_quote_form_marker`]) recovers the constructor's
/// marker byte-for-byte. Outer-shape composition law:
/// `Sexp::quote_form(marker, inner).shape() == marker.sexp_shape()`
/// — the outer-shape identity binds through the typed-shape lattice
/// at ONE arm per [`QuoteForm`] variant, symmetric with the atomic
/// construct family's `Sexp::X_atom(payload).shape() ==
/// AtomKind::X.sexp_shape()` composition and the residual construct
/// family's `Sexp::list(items).shape() == SexpShape::List`
/// composition.
///
/// Per-variant restriction laws (structural identity between the
/// marker-driven parent + the four per-variant siblings):
/// * `Sexp::quote_form(QuoteForm::Quote, inner) == Sexp::quote(inner)`
/// * `Sexp::quote_form(QuoteForm::Quasiquote, inner) == Sexp::quasiquote(inner)`
/// * `Sexp::quote_form(QuoteForm::Unquote, inner) == Sexp::unquote(inner)`
/// * `Sexp::quote_form(QuoteForm::UnquoteSplice, inner) == Sexp::unquote_splice(inner)`
///
/// The four per-variant constructors ARE the marker-driven parent
/// specialized on a compile-time-known marker; the marker-abstracted
/// parent binds every consumer that routes a runtime `QuoteForm`
/// value through a quote-family construct to ONE typed method on
/// the outer [`Sexp`] algebra rather than a four-arm inline
/// `match qf { QuoteForm::X => Sexp::x(inner), … }` dispatch.
///
/// Pre-lift consumers with a runtime `QuoteForm` marker routed
/// through `marker.wrap(inner)` directly (the reader's
/// `read_quoted` production consumer at `reader.rs`, the domain
/// module's quote-family round-trip test site) — well past the ≥2
/// PRIME-DIRECTIVE trigger once the marker-driven pattern is
/// named. Post-lift consumers bind to ONE typed-algebra method on
/// the outer [`Sexp`] algebra sitting next to the typed-project
/// family ([`Self::as_quote_form`] / [`Self::as_quote_form_marker`])
/// rather than reaching into the closed-set [`QuoteForm::wrap`]
/// method directly. A future allocation-policy change (e.g. arena-
/// allocated wrappers for span-aware [`Sexp`]) lands as ONE edit at
/// the single [`QuoteForm::wrap`] composition site and propagates
/// through this constructor byte-for-byte.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// (typed [`QuoteForm`] marker, owned inner body, [`QuoteForm::wrap`]
/// composition) triple binds at ONE typed-algebra method on the
/// outer [`Sexp`] algebra, closing the marker-driven quote-family
/// (construct, project) algebra dual pair with
/// [`Self::as_quote_form`] on the projection side. THEORY.md §II.1
/// invariant 2 — free middle; every consumer that has a runtime
/// [`QuoteForm`] marker + an owned inner body and wants to build a
/// quote-family wrapper routes through the SAME typed method, so a
/// regression that drifts one consumer's marker→wrapper mapping
/// cannot reach the substrate's runtime. THEORY.md §V.1 — knowable
/// platform; the marker-driven quote-family typed-construct becomes
/// a TYPE projection on the substrate's outer [`Sexp`] algebra
/// sitting next to the typed-project family
/// [`Self::as_quote_form`] / [`Self::as_quote_form_marker`] rather
/// than the closed-set [`QuoteForm::wrap`] method threaded as a
/// method call on a bound-marker value. THEORY.md §VI.1 —
/// generation over composition; the marker-driven quote-family
/// pair emerges from ONE typed-algebra composition through
/// [`QuoteForm::wrap`] rather than from per-consumer marker→wrapper
/// dispatch literals; a future fifth homoiconic prefix syntax
/// (e.g. `#'x` for hygienic macros) extends [`QuoteForm::ALL`] +
/// [`QuoteForm::wrap`]'s match arm + [`Self::as_quote_form`]'s
/// match arm in lockstep — rustc-enforced through the closed-set
/// exhaustiveness — with THIS constructor inheriting the extension
/// through the [`QuoteForm::wrap`] composition site without a per-
/// site edit.
///
/// Frontier inspiration: Racket's `(datum->syntax stx (list #'qf
/// inner))` marker-abstracted quote-family construct paired one-
/// for-one with `syntax-e` on the projection face — the typed-
/// construct + typed-project algebra dual is closed on Racket's
/// syntax algebra at one method per direction, and
/// `Sexp::quote_form` / `Sexp::as_quote_form` is the Rust-typed peer
/// on the closed-set outer [`Sexp`] algebra with [`QuoteForm`]
/// standing in for Racket's syntactic-form taxonomy over the four
/// homoiconic prefix wrappers. MLIR's typed-IR
/// `mlir::OpBuilder::create(loc, OperationName, operands)` marker-
/// driven op construction paired with `mlir::Operation::getName()`
/// on the projection face — the typed factory + typed downcast pair
/// the IR algebra closes over on every op kind at one method per
/// direction; `Sexp::quote_form` / [`Self::as_quote_form_marker`]
/// is the Rust-typed peer on the outer [`Sexp`] algebra with the
/// closed-set [`QuoteForm`] standing in for MLIR's `OperationName`
/// taxonomy over the four homoiconic prefix-wrapper op kinds.
#[must_use]
pub fn quote_form(marker: QuoteForm, inner: Sexp) -> Self {
marker.wrap(inner)
}
/// Canonical marker-driven template-substitution outer constructor —
/// routes through [`UnquoteForm::wrap`] on the caller-supplied
/// [`UnquoteForm`] marker at ONE site on the closed-set [`Sexp`]
/// algebra. Subset-algebra peer of the marker-driven quote-family
/// parent [`Self::quote_form`]: where [`Self::quote_form`] embeds a
/// caller-supplied [`QuoteForm`] marker + owned inner body on the
/// 4-of-12 quote-family carving through the closed-set
/// [`QuoteForm::wrap`] composition site, THIS constructor embeds a
/// caller-supplied [`UnquoteForm`] marker + owned inner body on the
/// 2-of-12 template-substitution subset carving through the
/// [`UnquoteForm::wrap`] composition site (which itself composes
/// [`UnquoteForm::to_quote_form`] then [`QuoteForm::wrap`], so the
/// welded `Sexp::X(Box::new(_))` triple ultimately still binds at
/// the ONE canonical [`QuoteForm::wrap`] site the four per-variant
/// siblings [`Self::quote`] / [`Self::quasiquote`] / [`Self::unquote`]
/// / [`Self::unquote_splice`] and the marker-driven parent
/// [`Self::quote_form`] all route through). Closes the (construct,
/// project) algebra dual on the (`UnquoteForm`, `Sexp`) product
/// against the pre-existing projection sibling [`Self::as_unquote`]
/// (soft-decomposition into `Option<(UnquoteForm, &Sexp)>`) and its
/// marker-only peer [`Self::as_unquote_form`] (soft-decomposition
/// into `Option<UnquoteForm>`) — post-lift the outer [`Sexp`]
/// algebra carries a marker-driven (construct, project) dual pair
/// `Sexp::unquote_form` / `Sexp::as_unquote` at ONE typed method per
/// direction on the template-substitution subset alongside the
/// marker-only projection sibling [`Self::as_unquote_form`],
/// symmetric with the pair `Sexp::quote_form` / `Sexp::as_quote_form`
/// / `Sexp::as_quote_form_marker` the superset carries.
///
/// Sibling posture across the outer-algebra construct-family layer:
/// where [`Self::call`](Self::call) and [`Self::named_call`](Self::named_call)
/// close the (construct, project) dual on the call-form + named-call-
/// form typed decompositions of the residual-axis List arm,
/// [`Self::list`](Self::list) closes it on the residual-axis List
/// arm itself, and [`Self::quote_form`](Self::quote_form) closes it
/// on the quote-family-axis marker-driven decomposition (the parent
/// 4-of-12 quote-family carving), THIS constructor closes it on the
/// template-substitution-subset marker-driven decomposition (the
/// 2-of-4 subset of the quote-family carving, equivalently the
/// 2-of-12 substitution carving of the outer [`SexpShape`] closed
/// set) — the outer [`Sexp`] algebra now carries a marker-driven
/// construct-family dual pair for every closed-set carving on the
/// quote-family axis at ONE typed method per corner.
///
/// Composition law (forward): `Sexp::unquote_form(marker, inner) ==
/// marker.wrap(inner)` for every `marker: UnquoteForm` and every
/// `inner: Sexp`. The body routes through the SAME
/// [`UnquoteForm::wrap`] method the subset-algebra consumer path
/// already reaches for, so the (subset marker, [`Sexp`] tuple-variant
/// wrapper) pairing binds at ONE closed-set composition site on the
/// substrate — a regression that drifts one consumer's subset
/// marker → wrapper mapping from the others (e.g. a copy-edit that
/// pairs [`UnquoteForm::Unquote`] with the [`Sexp::UnquoteSplice`]
/// tuple variant, or that drops a [`UnquoteForm::Splice`] value
/// through the [`Sexp::Unquote`] tuple variant) cannot reach the
/// substrate's runtime.
///
/// Round-trip law (section-for-retraction with the outer-algebra
/// soft-projection): for every `marker: UnquoteForm` and every
/// `inner: Sexp`, `Sexp::unquote_form(marker, inner.clone())
/// .as_unquote() == Some((marker, &inner))` — the outer algebra's
/// marker-driven template-substitution constructor pairs section-
/// for-retraction with the outer algebra's soft template-substitution
/// projection, and the (subset marker, inner body) cross-projection
/// preserves identity for every [`UnquoteForm`] variant.
///
/// Marker-recovering projection composition: `Sexp::unquote_form(
/// marker, inner).as_unquote_form() == Some(marker)` for every input
/// — the marker-only projection sibling [`Self::as_unquote_form`]
/// recovers the constructor's subset marker byte-for-byte. Outer-
/// shape composition law: `Sexp::unquote_form(marker, inner).shape()
/// == marker.sexp_shape()` — the outer-shape identity binds through
/// the typed-shape lattice at ONE arm per [`UnquoteForm`] variant,
/// symmetric with the quote-family construct family's
/// `Sexp::quote_form(marker, inner).shape() == marker.sexp_shape()`
/// composition and the atomic construct family's
/// `Sexp::X_atom(payload).shape() == AtomKind::X.sexp_shape()`
/// composition. Superset-routing composition law:
/// `Sexp::unquote_form(marker, inner) == Sexp::quote_form(
/// marker.to_quote_form(), inner)` for every input — the subset-
/// algebra construct routes through the same closed-set
/// [`QuoteForm::wrap`] composition site the superset construct
/// routes through, threaded via the typed 2-of-4 subset → superset
/// projection [`UnquoteForm::to_quote_form`]. A regression that
/// drifts either direction of this composition fails at the
/// superset-routing pin.
///
/// Per-variant restriction laws (structural identity between the
/// marker-driven parent + the two per-variant siblings):
/// * `Sexp::unquote_form(UnquoteForm::Unquote, inner) == Sexp::unquote(inner)`
/// * `Sexp::unquote_form(UnquoteForm::Splice, inner) == Sexp::unquote_splice(inner)`
///
/// The two per-variant constructors ARE the marker-driven parent
/// specialized on a compile-time-known subset marker; the marker-
/// abstracted parent binds every consumer that routes a runtime
/// [`UnquoteForm`] value through a template-substitution construct
/// to ONE typed method on the outer [`Sexp`] algebra rather than a
/// two-arm inline `match uf { UnquoteForm::Unquote => Sexp::unquote(
/// inner), UnquoteForm::Splice => Sexp::unquote_splice(inner) }`
/// dispatch.
///
/// Pre-lift consumers with a runtime `UnquoteForm` marker routed
/// through `marker.wrap(inner)` directly (reaching into the
/// [`UnquoteForm::wrap`] subset-algebra method) OR through the two-
/// step `Sexp::quote_form(marker.to_quote_form(), inner)`
/// composition (routing via the superset marker-driven parent).
/// Post-lift consumers bind to ONE typed-algebra method on the outer
/// [`Sexp`] algebra sitting next to the typed-project family
/// ([`Self::as_unquote`] / [`Self::as_unquote_form`]) rather than
/// reaching into the closed-set [`UnquoteForm::wrap`] method
/// directly or composing the superset parent with the subset →
/// superset projection. A future allocation-policy change (e.g.
/// arena-allocated wrappers for span-aware [`Sexp`]) lands as ONE
/// edit at the single [`QuoteForm::wrap`] composition site and
/// propagates through this constructor byte-for-byte (via the
/// [`UnquoteForm::wrap`] composition).
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// (typed [`UnquoteForm`] marker, owned inner body,
/// [`UnquoteForm::wrap`] composition) triple binds at ONE typed-
/// algebra method on the outer [`Sexp`] algebra, closing the marker-
/// driven template-substitution (construct, project) algebra dual
/// pair with [`Self::as_unquote`] on the projection side. THEORY.md
/// §II.1 invariant 2 — free middle; every consumer that has a
/// runtime [`UnquoteForm`] marker + an owned inner body and wants to
/// build a template-substitution wrapper routes through the SAME
/// typed method, so a regression that drifts one consumer's subset
/// marker → wrapper mapping cannot reach the substrate's runtime.
/// THEORY.md §V.1 — knowable platform; the marker-driven template-
/// substitution typed-construct becomes a TYPE projection on the
/// substrate's outer [`Sexp`] algebra sitting next to the typed-
/// project family [`Self::as_unquote`] / [`Self::as_unquote_form`]
/// rather than the closed-set [`UnquoteForm::wrap`] method threaded
/// as a method call on a bound-marker value or the two-step subset
/// → superset then [`Self::quote_form`] composition. THEORY.md
/// §VI.1 — generation over composition; the marker-driven template-
/// substitution pair emerges from ONE typed-algebra composition
/// through [`UnquoteForm::wrap`] rather than from per-consumer
/// subset-marker → wrapper dispatch literals; a future third
/// template-substitution marker (e.g. a `,~` reverse-unquote)
/// extends [`UnquoteForm::ALL`] + [`UnquoteForm::to_quote_form`]'s
/// dispatch table in lockstep — rustc-enforced through the closed-
/// set exhaustiveness — with THIS constructor inheriting the
/// extension through the [`UnquoteForm::wrap`] composition site
/// without a per-site edit.
///
/// Frontier inspiration: Racket's `(datum->syntax stx (list #'uf
/// inner))` marker-abstracted template-substitution construct
/// restricted to the substitution-subset of syntactic-form kinds,
/// paired one-for-one with `syntax-e` on the projection face — the
/// typed-construct + typed-project algebra dual is closed on
/// Racket's syntax algebra at one method per direction per subset,
/// and `Sexp::unquote_form` / `Sexp::as_unquote` is the Rust-typed
/// peer on the closed-set outer [`Sexp`] algebra with
/// [`UnquoteForm`] standing in for Racket's substitution-subset
/// syntactic-form taxonomy. MLIR's typed factory
/// `mlir::OpBuilder::create<UnquoteFamilyOp>(loc, marker, operands)`
/// paired with the projection sibling
/// `mlir::dyn_cast<UnquoteFamilyOp>(op)` — the typed factory + typed
/// downcast pair the IR algebra closes over on every op-family
/// subset at one method per direction; `Sexp::unquote_form` /
/// [`Self::as_unquote_form`] is the Rust-typed peer on the outer
/// [`Sexp`] algebra with the closed-set [`UnquoteForm`] standing in
/// for MLIR's `OperationName` subset taxonomy over the template-
/// substitution op family.
#[must_use]
pub fn unquote_form(marker: UnquoteForm, inner: Sexp) -> Self {
marker.wrap(inner)
}
pub fn is_list(&self) -> bool {
matches!(self, Self::List(_))
}
pub fn as_list(&self) -> Option<&[Sexp]> {
match self {
Self::List(xs) => Some(xs),
_ => None,
}
}
/// Canonical [`Self::List`] outer constructor — collects an
/// `impl IntoIterator<Item = Sexp>` into the tuple-variant payload
/// `Vec<Sexp>` at ONE site on the closed-set [`Sexp`] algebra. The
/// residual-axis section-for-retraction sibling of the existing
/// [`Self::as_list`] soft-projection ([`Option<&[Sexp]>`]): where
/// the projection soft-decomposes a [`Self::List`] arm into its
/// borrowed inner slice, this constructor embeds a fresh owned
/// item sequence into the matching tuple-variant wrapper. Sibling
/// of the atomic-payload construct family ([`Self::symbol`],
/// [`Self::keyword`], [`Self::string`], [`Self::int`],
/// [`Self::float`], [`Self::boolean`] — all routing through the
/// typed [`Atom`] construct family on the 6-of-12 atomic-payload
/// carving) and the quote-family construct family ([`Self::quote`],
/// [`Self::quasiquote`], [`Self::unquote`], [`Self::unquote_splice`]
/// — all routing through the typed [`QuoteForm::wrap`] family on
/// the 4-of-12 quote-family carving); closes the (construct,
/// project) algebra dual on the third and final structural carving
/// of the outer [`Sexp`] closed set — the 2-of-12 residual axis
/// covering [`Self::Nil`] and [`Self::List`]. [`Self::Nil`] is a
/// unit variant carrying no payload — the residual-axis
/// construct family closes at ONE constructor (this method) for
/// the sole payload-bearing residual arm.
///
/// Composition law (forward): `Sexp::list(items) ==
/// Sexp::List(items.into_iter().collect::<Vec<Sexp>>())` for every
/// `items: impl IntoIterator<Item = Sexp>`. Round-trip law
/// (section-for-retraction with the soft-projection sibling): for
/// every `items: Vec<Sexp>`, `Sexp::list(items.clone()).as_list()
/// == Some(items.as_slice())` — the outer algebra's typed
/// constructor pairs section-for-retraction with the outer
/// algebra's soft projection, and the borrowed-slice cross-
/// projection preserves identity. Sibling posture across the
/// three axis-construct families on the outer [`Sexp`] algebra
/// (atomic + quote-family + residual).
///
/// Outer-shape composition law: `Sexp::list(items).shape() ==
/// SexpShape::List` for every `items: impl IntoIterator<Item =
/// Sexp>` — the residual-arm outer-shape identity binds through
/// the typed-shape lattice at ONE arm, symmetric with the
/// quote-family construct family's outer-shape composition
/// `Sexp::X_variant(inner).shape() == QuoteForm::X.sexp_shape()`
/// and the atomic construct family's `Sexp::X_atom(payload).shape()
/// == AtomKind::X.sexp_shape()`. Structural-carving-marker
/// composition law: `Sexp::list(items).as_structural_kind() ==
/// Some(StructuralKind::List)` for every `items: impl
/// IntoIterator<Item = Sexp>` — the residual-axis carving marker
/// binds through the closed-set [`StructuralKind`] algebra at ONE
/// arm, symmetric with the atomic-axis's `Sexp::X_atom(payload)
/// .as_atom_kind() == Some(AtomKind::X)` marker composition.
///
/// Pre-lift the [`Self::List(Vec<Sexp>)`] welded pair
/// ([`Self::List`] tuple-variant constructor + `Vec<Sexp>`
/// payload) appeared inline at every consumer that builds a
/// list-shaped [`Sexp`] value — well past the ≥2 PRIME-DIRECTIVE
/// trigger once the structural shape is named. Post-lift the
/// welded pair binds at ONE typed-algebra method on the outer
/// [`Sexp`] algebra with an `impl IntoIterator<Item = Sexp>`
/// bound so consumers that have a `Vec<Sexp>`, a `[Sexp; N]`
/// array, an `iter().cloned()` sequence, a
/// `.map(...).collect()`-worthy chain, or a
/// `once(head).chain(tail)` composition can hand the sequence
/// directly to the algebra without a per-site `.collect::<Vec<
/// Sexp>>()` coercion. A future allocation-policy change (e.g.
/// arena-allocated lists for span-aware [`Sexp`]) lands as ONE
/// edit at this method site and propagates through consumers
/// byte-for-byte.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// (list-shaped inner sequence, [`Self::List`] tuple-variant
/// constructor) pairing binds at ONE typed-algebra method on the
/// outer [`Sexp`] algebra, closing the outer-algebra construct
/// family across ALL THREE structural carvings of the [`SexpShape`]
/// closed set (atomic-payload + quote-family + residual). THEORY.md
/// §II.1 invariant 2 — free middle; every consumer that has an
/// owned or iterable sequence of [`Sexp`] and wants to build a
/// list-shaped wrapper routes through the SAME typed method, so a
/// regression that drifts one consumer's construction from the
/// others cannot reach the substrate's runtime. THEORY.md §V.1 —
/// knowable platform; the typed-construct family becomes a TYPE
/// projection on the substrate's outer [`Sexp`] algebra sitting
/// next to the typed-project family [`Self::as_list`] rather than
/// bare tuple-variant constructor + per-site `Vec<Sexp>` discipline.
/// THEORY.md §VI.1 — generation over composition; the residual-
/// arm outer-shape + carving-marker pairings emerge from ONE
/// typed-algebra composition on the outer [`Sexp`] algebra rather
/// than from per-consumer per-variant literals.
///
/// Frontier inspiration: Racket's `(list x y z)` typed list-
/// construct primitive paired one-for-one with `(list? v)` /
/// `(car v)` / `(cdr v)` predicate/projection siblings on the
/// same closed-set list shape — the typed-construct + typed-
/// project algebra dual is closed at one method per direction on
/// Racket's surface, and [`Self::list`] / [`Self::as_list`] is
/// the Rust-typed peer on the closed-set outer [`Sexp`] algebra
/// with `impl IntoIterator<Item = Sexp>` standing in for Racket's
/// variadic collect face. MLIR's `mlir::OpBuilder::create<
/// ListOp>(loc, elements)` typed-IR list-op construction paired
/// with `mlir::dyn_cast<ListOp>(op)` on the projection face —
/// the typed factory + typed downcast pair the IR algebra closes
/// over on every list-shaped op; [`Self::list`] / [`Self::as_list`]
/// is the Rust-typed peer on the outer [`Sexp`] algebra with
/// [`StructuralKind::List`] standing in for MLIR's `OperationName`
/// taxonomy over the list-shaped op family.
#[must_use]
pub fn list<I: IntoIterator<Item = Sexp>>(items: I) -> Self {
Self::List(items.into_iter().collect())
}
/// Soft projection onto the closed-set [`StructuralKind`] residual
/// carving marker — the 2-of-12 carving of the [`SexpShape`] algebra
/// covering [`Self::Nil`] and [`Self::List`] (the outer shapes that
/// lie OUTSIDE both the atomic-payload carving
/// [`AtomKind`](crate::error::SexpShape::as_atom_kind) and the
/// quote-family carving
/// [`QuoteForm`](crate::error::SexpShape::as_quote_form)). Returns
/// `Some(StructuralKind::Nil)` for [`Self::Nil`],
/// `Some(StructuralKind::List)` for [`Self::List`], `None` for
/// every other outer shape (every [`Self::Atom`] variant, every
/// quote-family wrapper: [`Self::Quote`], [`Self::Quasiquote`],
/// [`Self::Unquote`], [`Self::UnquoteSplice`]).
///
/// Sibling soft-projection peer of [`Self::as_quote_form`] (the
/// soft-decomposition of the four homoiconic prefix wrappers into
/// `(QuoteForm, &Sexp)`) and [`Self::as_unquote`] (the
/// soft-decomposition of the two template-substitution wrappers
/// into `(UnquoteForm, &Sexp)`). Direct value-level peer of the
/// shape-level projection
/// [`SexpShape::as_structural_kind`](crate::error::SexpShape::as_structural_kind)
/// — the pair `(Sexp::as_structural_kind, SexpShape::as_structural_kind)`
/// binds the (Sexp value, StructuralKind carving marker) pairing at
/// ONE typed method on each algebra, symmetric with the existing
/// (Sexp value → AtomKind via
/// `Sexp::as_atom().map(Atom::kind)`) atomic-axis composition and
/// the direct (Sexp value → QuoteForm) marker projection
/// [`Self::as_quote_form`] returns.
///
/// Composition law: `s.as_structural_kind() ==
/// s.shape().as_structural_kind()` for every `s: &Sexp`. Pre-lift
/// the residual-carving marker at the value level was reachable
/// only via the two-step composition
/// `s.shape().as_structural_kind()` (walking through the full
/// 12-variant [`SexpShape`] closed set to arrive at the 2-of-12
/// carving marker); post-lift the composition lands at ONE typed
/// method on the value algebra — the Nil arm returns `Some(Nil)`
/// directly and the List arm returns `Some(List)` directly,
/// matching the residual-carving membership at the value level.
/// The composition law is pinned by
/// `sexp_as_structural_kind_agrees_with_shape_as_structural_kind_for_every_variant`
/// in this module, so a regression that drifts either projection
/// from the other surfaces immediately.
///
/// Sibling-shape lift to [`Self::is_list`] (the bare List-arm
/// predicate) and [`Self::is_kwargs_list`] (the narrower
/// kwargs-shaped List cohort predicate): where `is_list` returns
/// `true` iff the value inhabits the List arm of the residual
/// carving, `as_structural_kind` returns the typed carving marker
/// that binds BOTH residual arms (Nil and List) at ONE typed
/// projection — the operator answering "which residual arm?"
/// rather than the bare "is this the List arm?" predicate.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the
/// (Sexp variant, StructuralKind carving marker) pairing becomes a
/// TYPE projection on the substrate `Sexp` algebra rather than a
/// two-step composition through the shape-level projection. A typo
/// or swap at the value-projection site is no longer a runtime
/// drift but a compile error against the typed projection.
/// THEORY.md §VI.1 — generation over composition; the
/// residual-carving marker projection now lives on the typed
/// `Sexp` algebra alongside [`Self::as_atom`], [`Self::as_list`],
/// [`Self::as_quote_form`], [`Self::as_unquote`], completing the
/// (Sexp value → closed-set carving marker) family at the residual
/// axis. THEORY.md §II.1 invariant 2 — free middle; every consumer
/// that needs the residual-carving marker at the value level (a
/// future `tatara-check` predicate keyed on the Nil/List cohort, a
/// future LSP structural-navigation filter that keys on the
/// residual carving, a future typed-rewriter walk over the
/// residual arm) binds to ONE typed method on the value algebra
/// rather than a two-step composition through the shape-level
/// projection.
///
/// Frontier inspiration: MLIR's `mlir::dyn_cast<StructuralOp>(val)`
/// typed soft-downcast on the residual carving of a closed-set
/// value algebra — the (value, typed carving marker) pairing lives
/// at ONE typed projection on the outer value-algebra sibling. The
/// Rust-typed peer here uses the substrate's outer `Sexp` algebra
/// with `Sexp::as_structural_kind` closing the residual-carving
/// cell of the value-level soft-projection surface, symmetric with
/// the atomic-axis composition through [`Self::as_atom`] and the
/// quote-family projection [`Self::as_quote_form`].
#[must_use]
pub fn as_structural_kind(&self) -> Option<StructuralKind> {
match self {
Self::Nil => Some(StructuralKind::Nil),
Self::List(_) => Some(StructuralKind::List),
_ => None,
}
}
/// Structural-shape predicate — `true` iff this is a [`Self::List`]
/// whose items form a non-empty, even-length `(:k v :k v …)` kwargs
/// sequence with every even-indexed item being an [`Atom::Keyword`].
/// `false` for every other outer shape ([`Self::Nil`], every
/// [`Self::Atom`] variant, every quote-family wrapper) and for every
/// [`Self::List`] that fails the kwargs convention (empty list, odd
/// length, or any even-indexed non-keyword).
///
/// The structural witness that [`Self::to_json`] will project this
/// value as [`serde_json::Value::Object`] rather than
/// [`serde_json::Value::Array`] at the [`Self::List`] arm — the
/// `(Sexp variant + kwargs shape, JSON canonical-form)` pairing
/// binds at ONE inherent method on the algebra rather than at a
/// free function consumers must reach into the `domain` module
/// path to invoke. Inverse round-trip law: every
/// [`Self::from_json`] projection of a [`serde_json::Value::Object`]
/// satisfies this predicate (the [`Self::List`] arm
/// [`Self::from_json`] builds for an `Object` is non-empty by the
/// `Object`'s non-empty-keys invariant when present, even-length by
/// the alternating `:k v` build, and keyword-headed at every even
/// index by the `Self::keyword(camel_to_kebab(k))` build — except
/// for the structurally degenerate empty `Object` which projects to
/// `Sexp::List(vec![])` and returns `false` here, matching
/// [`Self::to_json`]'s "empty-list ↛ kwargs" gate).
///
/// Composes through [`Self::as_list`] (the structural soft-projection
/// onto `&[Sexp]`) and [`Atom::as_keyword`] (the typed soft-projection
/// onto the keyword payload from the [`Atom`] algebra) — the predicate
/// is rebuilt from already-lifted algebra primitives rather than
/// inline-matching the [`Self::List`] arm. Sibling-shape predicate
/// peer of [`Self::is_list`] (the unconditional [`Self::List`]-arm
/// predicate), with this method narrowing the structural witness to
/// the kwargs-shaped sub-cohort. The two predicates partition the
/// list-typed cell of the algebra: every [`Self::List`] either
/// satisfies `is_kwargs_list` (projects as [`serde_json::Value::Object`]
/// through [`Self::to_json`]) or does not (projects as
/// [`serde_json::Value::Array`]).
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// kwargs-shape predicate, previously a `pub(crate)` free function in
/// `domain.rs` reached across the module boundary by [`Self::to_json`],
/// is lifted ONE algebra level higher onto the inherent method on
/// the [`Sexp`] algebra — completing the structural-predicate family
/// alongside [`Self::is_list`] and the soft-projection family
/// ([`Self::as_atom`], [`Self::as_list`], [`Self::as_quote_form`]).
/// THEORY.md §II.1 invariant 2 — free middle; every consumer that
/// queries "would [`Self::to_json`] project this as `Object`?" (the
/// `Self::to_json` arm itself, future authoring-tool diagnostics, a
/// future LSP completion fallback, a future REPL pretty-printer that
/// chooses between `(…)` and `{…}` rendering, a future `tatara-check`
/// typed-pattern matcher) routes through ONE inherent algebra method
/// rather than reaching into the `domain` module path for a free
/// function. THEORY.md §V.1 — knowable platform; the JSON-format
/// witness becomes a TYPE projection on the substrate `Sexp` algebra
/// next to its sibling `Sexp::is_list` / `Sexp::as_list` pair rather
/// than living in a `domain.rs` `pub(crate)` helper consumers must
/// import via module path.
///
/// Frontier inspiration: MLIR's `mlir::Operation::hasTrait<T>()` —
/// typed-IR operations carry their structural traits as inherent
/// methods on the operation algebra rather than as free functions
/// in a sibling module; `Sexp::is_kwargs_list` is the
/// unstructured-Rust peer on the `Sexp` algebra for the
/// "would-this-project-as-Object" structural trait. Racket's
/// `(keyword-apply-procedure? stx)` — the syntax-class predicate
/// that gates a kwargs-style application form's printer / expander
/// path on the syntax algebra; `Sexp::is_kwargs_list` is the
/// substrate's peer at the [`Sexp`] layer, with the `as_list().
/// is_some_and(…)` composition standing in for Racket's
/// `syntax-parse` pattern matcher.
#[must_use]
pub fn is_kwargs_list(&self) -> bool {
self.as_list().is_some_and(|items| {
!items.is_empty()
&& items.len().is_multiple_of(2)
&& items.iter().step_by(2).all(|s| s.as_keyword().is_some())
})
}
/// Soft projection onto the inner [`Atom`] payload — `Some(&Atom)`
/// iff this is a [`Self::Atom`] variant, `None` for every other
/// outer shape (`Nil`, `List`, `Quote`, `Quasiquote`, `Unquote`,
/// `UnquoteSplice`). The structural-lift face of the per-atomic-
/// payload soft-projection family — composes with the typed
/// [`Atom::as_symbol`] / [`Atom::as_keyword`] / [`Atom::as_string`]
/// / [`Atom::as_int`] / [`Atom::as_float`] / [`Atom::as_bool`]
/// projections to give the six `Sexp::as_X` consumers ONE typed
/// boundary instead of six inline `Self::Atom(Atom::X(s)) => Some(s)`
/// arms.
///
/// Sibling soft-projection peer of [`Self::as_quote_form`] (the
/// soft-decomposition of the four homoiconic prefix wrappers into
/// `(QuoteForm, &Sexp)`) and [`Self::as_list`] (the soft-decomposition
/// of the structural list constructor into `&[Sexp]`). Together the
/// three projections (`as_atom`, `as_list`, `as_quote_form`) and
/// their nullary peer ([`Self::Nil`] via `matches!(self, Self::Nil)`)
/// cover every outer-shape arm of the `Sexp` algebra: Nil + Atom +
/// List + 4 quote-family arms = 7 outer shapes, with the typed-
/// projection set partitioning them by structural axis.
///
/// Composition law binding `Sexp::as_X` to the typed `Atom` algebra:
/// for every [`Sexp`] `s`,
/// `s.as_symbol()` (and each `as_keyword` / `as_string` / `as_int` /
/// `as_bool` sibling) `== s.as_atom().and_then(Atom::as_<variant>)`.
/// The `Sexp::as_float` consumer specializes through the widening
/// inline composition `s.as_atom().and_then(|a| a.as_float()
/// .or_else(|| a.as_int().map(|n| n as f64)))` so the algebra-level
/// `Atom::as_float` stays strict and the typed-identity
/// distinction `Int(1)` vs `Float(1.0)` is preserved at the algebra
/// layer (see [`Atom::as_int`]'s docstring for the discipline).
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition;
/// the six inline `Self::Atom(Atom::X(s)) => Some(_)` arms across
/// the `Sexp::as_X` family is past the three-times rule. THEORY.md
/// §II.1 invariant 2 — free middle; SIX consumers (`as_symbol`,
/// `as_keyword`, `as_string`, `as_int`, `as_float`, `as_bool`) now
/// route through ONE typed structural lift (this method) AND ONE
/// per-variant projection family on the closed-set `Atom` algebra
/// rather than six byte-identical outer-arm matches each.
/// THEORY.md §V.1 — knowable platform; the (Sexp variant, inner
/// payload kind) pairing becomes a TYPE projection on the substrate
/// algebra rather than six inline arms scattered across the six
/// `Sexp::as_X` consumers.
#[must_use]
pub fn as_atom(&self) -> Option<&Atom> {
match self {
Self::Atom(a) => Some(a),
_ => None,
}
}
/// Soft projection onto the closed-set [`AtomKind`] atomic-payload
/// carving marker — the 6-of-12 carving of the [`SexpShape`] algebra
/// covering [`Self::Atom`]'s six per-payload variants ([`Atom::Symbol`],
/// [`Atom::Keyword`], [`Atom::Str`], [`Atom::Int`], [`Atom::Float`],
/// [`Atom::Bool`]). Returns `Some(a.kind())` iff this is a
/// [`Self::Atom`] variant, `None` for every other outer shape
/// ([`Self::Nil`], [`Self::List`], every quote-family wrapper:
/// [`Self::Quote`], [`Self::Quasiquote`], [`Self::Unquote`],
/// [`Self::UnquoteSplice`]).
///
/// Direct value-level peer of the shape-level projection
/// [`SexpShape::as_atom_kind`](crate::error::SexpShape::as_atom_kind)
/// — the pair `(Sexp::as_atom_kind, SexpShape::as_atom_kind)` binds
/// the (Sexp value, AtomKind carving marker) pairing at ONE typed
/// method on each algebra, closing the atomic-axis cell of the
/// (Sexp value → carving marker) matrix. Sibling soft-projection
/// peer of [`Self::as_structural_kind`] (the 2-of-12 residual
/// carving returning `Option<StructuralKind>`) and
/// [`Self::as_quote_form`] (the 4-of-12 quote-family carving
/// returning `Option<(QuoteForm, &Sexp)>`) — post-lift ALL THREE
/// carvings that partition the twelve outer shapes of the
/// [`SexpShape`] algebra have a marker-only value-level projection
/// on `Sexp`: `as_atom_kind` (atomic axis), `as_quote_form`
/// (quote-family axis, marker + inner), `as_structural_kind`
/// (residual axis). The `Sexp::as_atom` projection stays available
/// for consumers that need the inner [`Atom`] payload for further
/// per-variant typed projection ([`Atom::as_symbol`] et al.); this
/// projection is the shortcut for consumers that only need the
/// carving-marker identity.
///
/// Composition laws (dual bindings): `s.as_atom_kind() ==
/// s.as_atom().map(Atom::kind) == s.shape().as_atom_kind()` for
/// every `s: &Sexp`. Pre-lift the atomic carving marker at the
/// value level was reachable only via one of these two-step
/// compositions — either through the [`Atom`] algebra
/// (`as_atom().map(Atom::kind)`) or through the shape algebra
/// (`shape().as_atom_kind()`). Post-lift the projection lands at
/// ONE typed method on the value algebra, and both compositions
/// are pinned as agreement laws (see
/// `sexp_as_atom_kind_agrees_with_as_atom_map_kind_for_every_variant`
/// and
/// `sexp_as_atom_kind_agrees_with_shape_as_atom_kind_for_every_variant`
/// in this module). A regression that drifts any of the three
/// projections from the others surfaces immediately.
///
/// Symmetric with [`Self::as_structural_kind`]'s shape (returns
/// just the marker, no inner-payload borrow) — where
/// [`Self::as_quote_form`] and [`Self::as_unquote`] surface both
/// the marker AND the wrapped inner `&Sexp` (because the four
/// quote-family arms and the two substitution arms structurally
/// carry a boxed inner value), `as_atom_kind` and
/// `as_structural_kind` return marker-only projections (the atomic
/// arm's inner payload is heterogeneous across the six variants —
/// `String` / `i64` / `f64` / `bool` — and the residual arms
/// carry no or list-heterogeneous payload). Consumers that need
/// the payload compose through [`Self::as_atom`] +
/// [`Atom::as_symbol`] et al. (atomic axis) or [`Self::as_list`]
/// (residual axis); this projection is the payload-agnostic
/// carving-marker cell.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (Sexp
/// variant, AtomKind carving marker) pairing becomes a TYPE
/// projection on the substrate `Sexp` algebra rather than a
/// two-step composition through either the [`Atom`] algebra or the
/// shape algebra. A typo or swap at the value-projection site is
/// no longer a runtime drift but a compile error against the
/// typed projection. THEORY.md §VI.1 — generation over composition;
/// the atomic-carving marker projection now lives on the typed
/// `Sexp` algebra alongside [`Self::as_atom`], [`Self::as_list`],
/// [`Self::as_quote_form`], [`Self::as_unquote`],
/// [`Self::as_structural_kind`], completing the (Sexp value →
/// closed-set carving marker) family across ALL THREE axes
/// (atomic + quote-family + structural-residual). THEORY.md §II.1
/// invariant 2 — free middle; every consumer that needs the
/// atomic-carving marker at the value level (a future
/// `tatara-check` predicate keyed on the atomic cohort, a future
/// LSP structural-navigation filter that keys on the atomic
/// carving, a future typed-rewriter walk over the atomic arm)
/// binds to ONE typed method on the value algebra rather than a
/// two-step composition.
///
/// Sibling posture across the value-level marker family — the
/// three projections (`as_atom_kind`, `as_quote_form`,
/// `as_structural_kind`) form a partition of the seven outer-shape
/// variants of the `Sexp` algebra: for every `s: &Sexp`, EXACTLY
/// ONE returns `Some(_)` (pinned by the joint sweep
/// `sexp_as_atom_kind_partitions_outer_shapes_jointly_with_as_quote_form_and_as_structural_kind`
/// in this module, sibling to the pre-existing partition sweep
/// keyed on `as_atom` rather than `as_atom_kind`). The value-level
/// partition-total invariant across the three carvings is the
/// value-level peer of the shape-level partition-total invariant
/// (`sexp_shape_partition_is_total_across_atom_quote_structural_carvings`
/// in error.rs); each axis has BOTH invariants pinned.
///
/// Frontier inspiration: MLIR's `mlir::dyn_cast<AtomOp>(val)` typed
/// soft-downcast onto the atomic carving of a closed-set value
/// algebra — the (value, typed carving marker) pairing lives at
/// ONE typed projection on the outer value-algebra sibling. The
/// Rust-typed peer here uses the substrate's outer `Sexp` algebra
/// with `Sexp::as_atom_kind` closing the atomic-carving cell of
/// the value-level soft-projection surface, symmetric with the
/// residual-carving projection [`Self::as_structural_kind`] and
/// the quote-family projection [`Self::as_quote_form`]. Racket's
/// `(atom? stx)` predicate paired with `(syntax->datum stx)` on
/// the atomic branch — the substrate's `as_atom_kind` surfaces the
/// typed witness (`AtomKind`) alongside the predicate verdict in
/// ONE `Option<AtomKind>` projection.
#[must_use]
pub fn as_atom_kind(&self) -> Option<AtomKind> {
self.as_atom().map(Atom::kind)
}
/// Project this [`Sexp`] to its closed-set [`SexpShape`] outer-shape
/// marker — `Nil → SexpShape::Nil`, `Atom(a) → a.kind().sexp_shape()`,
/// `List(_) → SexpShape::List`, and each quote-family wrapper routes
/// through `as_quote_form().map(|(qf, _)| qf.sexp_shape())`. The
/// outer-shape peer on the [`Sexp`] algebra of [`Atom::kind`] (the
/// atomic-payload axis) and [`QuoteForm::sexp_shape`] (the
/// quote-family axis) — completes the substrate's Sexp-shape
/// projection family by lifting the free-function dispatcher
/// [`crate::domain::sexp_shape`] onto the typed `Sexp` algebra
/// alongside its [`Atom`] / [`QuoteForm`] peers.
///
/// Composition law: `s.shape() == crate::domain::sexp_shape(s)` for
/// every `s: &Sexp`. The free function continues to exist as a thin
/// delegate (its callers in `domain.rs`'s diagnostic-builder paths,
/// `compile.rs`'s `TypeMismatch.got` builder, and downstream tests
/// route through `s.shape()` after this lift), so the (Sexp variant,
/// SexpShape variant) pairing now binds at ONE inherent method on
/// the algebra rather than at a free function `domain` consumers
/// must reach into the module path to invoke.
///
/// Sibling-shape lift to the typed-EXIT projection trio on [`Atom`]
/// ([`fmt::Display for Atom`], [`Atom::to_json`],
/// `Atom::to_iac_forge_sexpr` (removed)) and the typed-ENTRY classifier
/// ([`Atom::from_lexeme`]): where the atomic-payload algebra carries
/// its own per-variant projection family at the atomic-payload
/// level, the `Sexp` algebra carries this single outer-shape
/// projection that composes through [`Self::as_atom`] +
/// [`Atom::kind`] (atomic axis) and [`Self::as_quote_form`] (quote-
/// family axis) — every other arm (`Nil`, `List`) projects to its
/// own [`SexpShape`] variant directly.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the
/// (Sexp variant, SexpShape variant) pairing becomes an inherent
/// algebra projection rather than a free function in `domain.rs`,
/// so the projection sits next to the rest of the typed `Sexp`
/// algebra ([`Self::as_atom`], [`Self::as_list`],
/// [`Self::as_quote_form`], [`Self::head_symbol`],
/// [`Self::as_call`]) the substrate carries. THEORY.md §II.1
/// invariant 2 — free middle; every consumer that needs the
/// outer shape (diagnostic builders at
/// [`crate::domain::sexp_witness`] / [`crate::domain::missing_head_err`],
/// [`crate::compile`]'s `TypeMismatch.got` projection, future LSP /
/// REPL / `tatara-check` typed-pattern matchers) now reaches a
/// method on the value rather than a free function imported from
/// `domain`. THEORY.md §VI.1 — generation over composition; the
/// inline dispatch lifted to [`crate::domain::sexp_shape`] is now
/// lifted ONE algebra level higher — from the free function to
/// the inherent method — so a future `Sexp` variant lands at the
/// algebra's match site without a module-path indirection. A
/// future extension (e.g. `Sexp::Vector` for `#(...)` reader
/// syntax, `Sexp::Map` for `{...}`) extends THIS method + the
/// `SexpShape` algebra + the free function's delegation in
/// lockstep — exhaustively checked by rustc across the `Sexp`
/// match.
///
/// Frontier inspiration: MLIR's `mlir::Operation::getName()` —
/// the typed-IR operation projects through an inherent method
/// to its closed-set name on the operation algebra; `Sexp::shape`
/// is the unstructured-Rust peer on the [`Sexp`] algebra for the
/// outer-shape projection surface, with [`SexpShape`] standing in
/// for MLIR's `OperationName` taxonomy. Racket's `(syntax-e stx)`
/// composed with a datum-prim classifier on the closed-set
/// syntax-taxonomy projects a syntax object to its outer shape via
/// a single primitive on the syntax algebra; `Sexp::shape` is the
/// substrate's typed-Rust peer.
#[must_use]
pub fn shape(&self) -> SexpShape {
// Each variant routes through its closed-set carving-marker's
// `sexp_shape` projection — the atomic-payload carving via
// `AtomKind::sexp_shape`, the structural-residual carving via
// `StructuralKind::sexp_shape`, the quote-family carving via
// `QuoteForm::sexp_shape`. Post-lift the twelve outer-shape
// arms of the SexpShape closed set are reached through THREE
// carving-marker `sexp_shape` projections (6 + 2 + 4 = 12),
// symmetric across the partition — no arm hits a raw
// `SexpShape::*` literal here. A future thirteenth variant
// (e.g. `Sexp::Vector` for `#(...)` reader syntax) extends the
// carving-marker family the same way and lands at one arm
// here + one carving-marker `sexp_shape` arm in lockstep.
match self {
Self::Nil => StructuralKind::Nil.sexp_shape(),
Self::Atom(a) => a.kind().sexp_shape(),
Self::List(_) => StructuralKind::List.sexp_shape(),
Self::Quote(_) | Self::Quasiquote(_) | Self::Unquote(_) | Self::UnquoteSplice(_) => {
let (qf, _) = self.expect_quote_form();
qf.sexp_shape()
}
}
}
/// Project this `Sexp` to its [`SexpWitness`] — the typed joint
/// identity pairing the structural [`SexpShape`] with the
/// renderable [`Sexp::Display`] projection in ONE owned value.
/// The joint-identity peer on the [`Sexp`] algebra of
/// [`Self::shape`] (the structural-shape-only projection) and
/// [`fmt::Display for Sexp`] (the rendered-literal-only
/// projection) — completes the substrate's Sexp-projection
/// family by lifting the free-function dispatcher
/// [`crate::domain::sexp_witness`] onto the typed `Sexp` algebra
/// alongside its [`Self::shape`] peer.
///
/// Composition law: `s.witness() ==
/// crate::domain::sexp_witness(s)` for every `s: &Sexp`. The
/// free function continues to exist as a thin delegate (its
/// callers in `macro_expand.rs`'s 8 typed-entry rejection
/// builders, `domain.rs`'s `missing_head_err` caller +
/// `rewriter_non_list_err` typed-exit builder, and downstream
/// tests route through `s.witness()` after this lift), so the
/// (Sexp variant, SexpWitness identity) pairing now binds at
/// ONE inherent method on the algebra rather than at a free
/// function `domain` consumers must reach into the module path
/// to invoke. Body composes the two algebra-level projections
/// — `self.shape()` for the structural identity, `self.to_string()`
/// for the renderable identity — into ONE
/// [`SexpWitness::new`] call. Pre-lift the dispatcher lived as
/// a free function in `domain.rs`; post-lift the canonical site
/// is the inherent method and the free function delegates
/// (mirrors the [`Self::shape`] lift in 121bb60 exactly).
///
/// Sibling-shape lift to [`Self::shape`] (the structural-shape
/// projection): where `shape()` carries the typed-shape axis on
/// the `Sexp` algebra, `witness()` carries the JOINT typed-shape
/// and renderable-literal axis — the typed identity an authoring
/// tool diagnostic owes the operator AT the typed-entry or
/// typed-exit rejection boundary. Every rejection-builder
/// helper in `macro_expand.rs` that previously projected `&Sexp`
/// through `crate::domain::sexp_witness(_)` at the variant
/// boundary now reaches a method on the value rather than a
/// free function imported from `domain`.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the
/// (Sexp variant, SexpWitness identity) pairing becomes an
/// inherent algebra projection rather than a free function in
/// `domain.rs`, so the projection sits next to the rest of the
/// typed `Sexp` algebra ([`Self::shape`], [`Self::as_atom`],
/// [`Self::as_list`], [`Self::as_quote_form`],
/// [`Self::head_symbol`], [`Self::as_call`]) the substrate
/// carries. THEORY.md §II.1 invariant 2 — free middle; every
/// consumer that needs the typed joint identity at a
/// rejection-boundary slot (`NonSymbolUnquoteTarget.got`,
/// `SpliceOutsideList.got`, `NonSymbolParam.got`,
/// `RestParamMissingName.got`, `RestParamTrailingTokens.first`,
/// `OptionalParamMalformed.got`, `DefmacroNonSymbolName.got`,
/// `DefmacroNonListParams.got`, `MissingHeadSymbol.got`,
/// `RewriterNonList.got`, future LSP / REPL / `tatara-check`
/// typed-pattern matchers) now reaches a method on the value
/// rather than a free function imported from `domain`.
/// THEORY.md §VI.1 — generation over composition; the inline
/// dispatch lifted to [`crate::domain::sexp_witness`] is now
/// lifted ONE algebra level higher — from the free function
/// to the inherent method — completing the Sexp-projection
/// family alongside [`Self::shape`]. A future `Sexp` variant
/// extension (e.g. `Sexp::Vector` for `#(...)` reader syntax,
/// `Sexp::Map` for `{...}`) reaches this method through the
/// already-lifted [`Self::shape`] + [`fmt::Display for Sexp`]
/// pair — no new arm needed here.
///
/// Frontier inspiration: MLIR's diagnostic builder pattern —
/// `op.emitOpError() << op` projects the offending operation
/// through inherent methods (`getName()`, `print()`) into ONE
/// diagnostic value; `Sexp::witness` is the unstructured-Rust
/// peer on the [`Sexp`] algebra for the joint typed-shape +
/// renderable-literal projection surface, with [`SexpWitness`]
/// standing in for MLIR's `InFlightDiagnostic` typed payload.
#[must_use]
pub fn witness(&self) -> SexpWitness {
SexpWitness::new(self.shape(), self.to_string())
}
/// Project this `Sexp` to its stable, human-readable outer-shape
/// label — the `&'static str` axis on the [`Sexp`] algebra. Lifts
/// the free-function dispatcher [`crate::domain::sexp_type_name`]
/// onto the typed `Sexp` algebra alongside its [`Self::shape`] /
/// [`Self::witness`] / [`Self::to_json`] / [`Self::from_json`]
/// sibling projections, completing the substrate's
/// Sexp-projection family at the canonical-label axis the way
/// [`Self::shape`] completes the typed-shape axis and
/// [`fmt::Display for Sexp`] completes the canonical-string axis.
///
/// Composition law: `s.type_name() == s.shape().label() ==
/// crate::domain::sexp_type_name(s)` for every `s: &Sexp`.
/// Pre-lift the projection lived as a free function in
/// `domain.rs` consumers (in particular the `LispError::TypeMismatch`
/// `got` slot in `compile.rs` and the legacy substring-grep
/// rejection-message tests) reached across module boundaries to
/// invoke; post-lift the canonical site is the inherent method on
/// the [`Sexp`] algebra and the free function delegates so existing
/// callers continue to compile. Body composes through
/// [`Self::shape`] + [`SexpShape::label`] so a future `Sexp`
/// variant (e.g. `Sexp::Vector` for `#(...)` reader syntax,
/// `Sexp::Map` for `{...}`) lands at one extension site
/// ([`Self::shape`]'s exhaustive arm) rather than a parallel
/// `&'static str` match — the projection is structurally derived,
/// not duplicated.
///
/// Sibling-shape lift to [`Self::shape`] (the typed-shape
/// projection): where `shape()` carries the typed
/// [`SexpShape`] identity (matchable, exhaustive across `Sexp`
/// variants), `type_name()` carries the `&'static str` literal
/// the rendered diagnostic surface wants (still derived from
/// the typed identity, but flattened through
/// [`SexpShape::label`] for substring-grep callers and the
/// `TypeMismatch.got` slot). The `&'static str` lifetime makes
/// the projection cheap to embed in any error variant without
/// allocation.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the
/// (Sexp variant, `&'static str` label) pairing becomes an
/// inherent algebra projection rather than a free function in
/// `domain.rs`, so the projection sits next to the rest of the
/// typed `Sexp` algebra ([`Self::shape`], [`Self::witness`],
/// [`Self::to_json`], [`Self::from_json`], [`Self::as_atom`],
/// [`Self::as_list`], [`Self::as_quote_form`],
/// [`Self::head_symbol`], [`Self::as_call`]) the substrate
/// carries. THEORY.md §II.1 invariant 2 — free middle; every
/// consumer that needs the outer-shape label
/// (`LispError::TypeMismatch.got` projection in `compile.rs`,
/// legacy substring-grep rejection-message tests, future LSP /
/// REPL diagnostic surfaces) now reaches a method on the value
/// rather than a free function imported from `domain`.
/// THEORY.md §VI.1 — generation over composition; the inline
/// `s.shape().label()` recipe lifted to
/// [`crate::domain::sexp_type_name`] is now lifted ONE algebra
/// level higher — from the free function to the inherent
/// method — completing the Sexp-projection family alongside
/// [`Self::shape`] / [`Self::witness`] / [`Self::to_json`] /
/// [`Self::from_json`]. The `domain.rs` `sexp_*` free-function
/// namespace is now structurally reserved for free functions
/// that genuinely need a `domain`-module reach (registry
/// dispatch, kwargs gates, registry suggestions), not
/// algebra-layer projections.
///
/// Frontier inspiration: MLIR's `mlir::Operation::getName()`
/// composed with `OperationName::getStringRef()` — the typed-IR
/// operation projects through inherent methods to its closed-set
/// label on the operation algebra; `Sexp::type_name` is the
/// unstructured-Rust peer on the [`Sexp`] algebra for the
/// canonical-label projection surface, with [`SexpShape::label`]
/// standing in for MLIR's `OperationName::getStringRef` second
/// hop. Racket's `(syntax-name stx)` — the typed inverse of
/// `(syntax-e stx)` on the syntax algebra; `Sexp::type_name`
/// composes the typed-shape projection with its closed-set
/// label projection at the inherent-method site rather than
/// the typeclass-method site, matching pleme-io's
/// "rust-typed, not trait-typed" idiom for closed-set algebras.
#[must_use]
pub fn type_name(&self) -> &'static str {
self.shape().label()
}
/// Project this `Sexp` to its canonical [`serde_json::Value`]
/// rendering — the typed-algebra peer of [`Atom::to_json`] at the
/// `Sexp` layer. Lifts the free-function dispatcher
/// [`crate::domain::sexp_to_json`] onto the typed `Sexp` algebra
/// alongside its [`Self::shape`] / [`Self::witness`] sibling
/// projections, completing the JSON-projection axis at the
/// algebra layer the way [`fmt::Display for Sexp`] completes the
/// canonical-string axis. The free function continues to exist
/// as a thin delegate (its callers in `tatara-lisp-derive`'s
/// derive output route through it via the
/// `crate::domain::sexp_to_json` import); the
/// `from_value_with_path` private helper in `domain.rs` and the
/// recursive sub-calls inside this method route through the
/// inherent method directly so the canonical-site indirection
/// disappears at every internal callsite.
///
/// Rules (preserve byte-identical pre-lift behavior at the
/// `sexp_to_json` callsite):
/// - [`Self::Nil`] → [`serde_json::Value::Null`].
/// - [`Self::Atom`] → [`Atom::to_json`] (the typed-algebra
/// peer at the atomic-payload layer; pinned by
/// `sexp_to_json_atom_arms_route_through_atom_to_json` in
/// `domain.rs`).
/// - [`Self::List`] with kwargs shape `(:k v :k v …)` →
/// [`serde_json::Value::Object`] keyed by
/// [`crate::domain::kebab_to_camel`] of each `:k`'s name.
/// A duplicate kebab→camel key inside any nested kwargs-list
/// fails with [`crate::domain::duplicate_kwarg`] — same
/// typed-entry posture
/// [`crate::domain::parse_kwargs`] takes at the top level.
/// - [`Self::List`] otherwise → [`serde_json::Value::Array`]
/// mapping each element through this method recursively.
/// - [`Self::Quote`] / [`Self::Quasiquote`] / [`Self::Unquote`]
/// / [`Self::UnquoteSplice`] → recurse on the inner via
/// [`Self::expect_quote_form`] (strips the wrapper; the
/// round-trip via [`crate::domain::json_to_sexp`] re-emits
/// the inner without an enclosing wrapper). All four arms
/// route through ONE [`Self::as_quote_form`]-derived
/// projection so the per-variant pairing binds at ONE site
/// on the [`QuoteForm`] algebra rather than four
/// byte-identical inline arms.
///
/// Composition law: `s.to_json() == crate::domain::sexp_to_json(s)`
/// for every `s: &Sexp`. Pre-lift the dispatcher lived as a free
/// function in `domain.rs`; post-lift the canonical site is the
/// inherent method and the free function delegates (same lift
/// posture as [`Self::shape`] in 121bb60 and [`Self::witness`]
/// in a427e3b).
///
/// Sibling-shape lift to [`Self::shape`] (the structural-shape
/// projection), [`Self::witness`] (the joint structural-shape +
/// renderable-literal projection), and [`fmt::Display for Sexp`]
/// (the renderable-literal projection): where those three carry
/// the Lisp-canonical-form / structural-identity axes on the
/// algebra, `to_json` carries the JSON canonical-form axis. The
/// substrate's `Sexp` algebra now binds ALL THREE canonical-form
/// projection surfaces (Lisp Display, JSON, and the feature-gated
/// iac-forge `From<&Sexp> for SExpr`) at the algebra layer, with
/// per-variant atomic rendering composed through the corresponding
/// [`Atom`] projection family (`Atom::Display`, [`Atom::to_json`],
/// `Atom::to_iac_forge_sexpr`).
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition;
/// the inline dispatch the prior runs lifted onto
/// [`crate::domain::sexp_to_json`] (the free function) is now
/// lifted ONE algebra level higher — from the free function to
/// the inherent method — completing the Sexp-projection family
/// alongside [`Self::shape`] and [`Self::witness`]. THEORY.md
/// §II.1 invariant 2 — free middle; the typed-exit JSON
/// projection (every consumer that round-trips a Sexp through
/// `serde_json::from_value::<T>` for typed-domain
/// deserialization, the typed-rewriter at
/// [`crate::domain::TypedRewriter`], the derive macro's
/// `compile_from_args` fallthrough, and any future canonical-
/// form surface) all route through ONE inherent algebra method
/// rather than reach into the `domain` module path for a free
/// function. THEORY.md §V.1 — knowable platform; a future
/// `Sexp` variant extension (e.g. `Sexp::Vector` for `#(...)`
/// reader syntax, `Sexp::Map` for `{...}`) reaches this method
/// through the already-lifted [`Self::as_quote_form`] +
/// [`Atom::to_json`] pair — one arm added here for the new
/// outer-shape variant; rustc enforces the per-variant body is
/// named.
///
/// Frontier inspiration: MLIR's `mlir::AsmPrinter::printOp` —
/// the typed-IR printer dispatches on the closed-set `Op` so
/// every printer body for an op lives at ONE implementation site;
/// `Sexp::to_json` is the unstructured-Rust peer on the `Sexp`
/// algebra for the JSON canonical-form surface (where
/// [`fmt::Display for Sexp`] is the Lisp-canonical-form peer
/// and `From<&Sexp> for iac_forge::SExpr` is the
/// canonical-attestation-form peer). Racket's `(syntax->datum
/// stx)` then a serializer over the datum prim — `to_json` is
/// the substrate's serializer at the Sexp layer composed
/// through [`Atom::to_json`] at the atomic-payload layer, with
/// the closed-set [`AtomKind`] standing in for Racket's
/// datum-prim taxonomy.
pub fn to_json(&self) -> crate::error::Result<serde_json::Value> {
Ok(match self {
Self::Nil => serde_json::Value::Null,
Self::Atom(a) => a.to_json(),
Self::List(items) => {
if self.is_kwargs_list() {
let mut map = serde_json::Map::with_capacity(items.len() / 2);
let mut i = 0;
while i + 1 < items.len() {
if let Some(k) = items[i].as_keyword() {
let value = items[i + 1].to_json()?;
if map
.insert(crate::domain::kebab_to_camel(k), value)
.is_some()
{
return Err(crate::domain::duplicate_kwarg(k));
}
i += 2;
} else {
break;
}
}
serde_json::Value::Object(map)
} else {
serde_json::Value::Array(
items
.iter()
.map(Self::to_json)
.collect::<crate::error::Result<Vec<_>>>()?,
)
}
}
Self::Quote(_) | Self::Quasiquote(_) | Self::Unquote(_) | Self::UnquoteSplice(_) => {
let (_, inner) = self.expect_quote_form();
inner.to_json()?
}
})
}
/// Inverse of [`Self::to_json`] — project a [`serde_json::Value`] back
/// onto a [`Sexp`]. The closed-set [`serde_json::Value`] discriminator
/// maps directly onto the corresponding [`Sexp`] constructor:
///
/// - [`serde_json::Value::Null`] → [`Self::Nil`].
/// - [`serde_json::Value::Bool`] → [`Self::boolean`].
/// - [`serde_json::Value::Number`] → [`Self::int`] when the value
/// fits an [`i64`], otherwise [`Self::float`] when it fits an
/// [`f64`]; the structural impossibility "neither i64 nor f64"
/// collapses to [`Self::int(0)`](Self::int) as a typed floor —
/// [`serde_json::Number`]'s closed-set discriminator excludes
/// this case in practice (every [`serde_json::Number`] is either
/// i64-fitting, u64-fitting projected through f64, or f64-fitting
/// directly), but the typed floor stays explicit so a future
/// `serde_json` extension does not silently misroute. Mirror of
/// [`Atom::to_json`]'s [`Self::int`] / [`Self::float`] bifurcation.
/// - [`serde_json::Value::String`] → [`Self::string`]. The
/// `serde_json::Value::String` discriminator is type-erased — a
/// serde-projected symbol AND a serde-projected keyword AND a
/// genuine string literal ALL inhabit it on the JSON side — so
/// the back-projection chooses [`Self::string`] as the lossless
/// floor for the `Atom::Symbol` / `Atom::Keyword` / `Atom::Str`
/// three-way collapse. Consumers that need the symbol-vs-string
/// distinction must preserve it BEFORE the JSON round-trip
/// (e.g. through a typed enum's serde projection rather than a
/// raw `Sexp`-to-`JValue` round-trip).
/// - [`serde_json::Value::Array`] → [`Self::List`] mapping each
/// element through this method recursively.
/// - [`serde_json::Value::Object`] → [`Self::List`] of alternating
/// `:key value` pairs in [`serde_json::Map`]'s iteration order
/// (sorted by key under `serde_json`'s default `BTreeMap`
/// backing; insertion order under the optional `preserve_order`
/// feature, which the substrate does NOT enable today), with
/// each JSON key projected through
/// [`crate::domain::camel_to_kebab`] to recover the `:k`'s
/// kebab-case authoring shape and each JSON value recursed
/// through this method. Inverse of [`Self::to_json`]'s
/// [`Self::List`] kwargs-shape arm: that arm projects
/// `:k v :k v …` into a JSON object via
/// [`crate::domain::kebab_to_camel`]; this arm projects the
/// object back into a `Self::List` of alternating keyword /
/// value via the inverse [`crate::domain::camel_to_kebab`].
///
/// Composition law: `Self::from_json(&s.to_json()?)` projects back
/// to a `Sexp` whose [`Self::to_json`] re-projection produces the
/// SAME `JValue` (modulo the lossy `Symbol` / `Keyword` / `Str`
/// three-way collapse documented above; for the round-trippable
/// subset, `Sexp::Nil`, the six [`Atom`] kinds within their
/// discriminator class, and recursively `Sexp::List` of round-
/// trippable elements, the law holds byte-for-byte).
///
/// Sibling-lift posture: this method mirrors the prior
/// [`crate::domain::sexp_to_json`] → [`Self::to_json`] (commit
/// 875ee3b) / [`crate::domain::sexp_shape`] → [`Self::shape`]
/// (commit 121bb60) / [`crate::domain::sexp_witness`] →
/// [`Self::witness`] (commit a427e3b) family of lifts, all of which
/// promoted a free function in `domain.rs` to the inherent-method
/// canonical site on the [`Sexp`] algebra. Pre-lift the
/// `json_to_sexp` dispatcher lived in `domain.rs` as the canonical
/// site; post-lift this inherent method is the canonical site and
/// the free function delegates so every existing caller continues
/// to compile.
///
/// Sibling-shape lift on the round-trip closure: the substrate's
/// `Sexp` ↔ `serde_json::Value` round-trip now lives entirely as
/// two inherent methods on the [`Sexp`] algebra — [`Self::to_json`]
/// (forward) and [`Self::from_json`] (inverse). Consumers that
/// previously round-tripped a typed value through Lisp forms via
/// `domain::sexp_to_json` + `domain::json_to_sexp` now bind to ONE
/// algebra (the inherent-method family) rather than reaching across
/// the `domain` module path for two free functions. A future
/// canonical-form surface (e.g., a YAML round-trip via
/// [`serde_yaml`], a Nix-expression round-trip via the typed Nix
/// surface in `tatara-nix`) hangs off the SAME `Sexp` algebra at
/// `Self::to_yaml` / `Self::from_yaml` / `Self::to_nix` /
/// `Self::from_nix` — the naming pattern is now structurally
/// established by this pair.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition;
/// the inline `json_to_sexp` dispatcher in `domain.rs` is lifted
/// ONE algebra level higher (from free function to inherent
/// method), completing the Sexp ↔ JValue round-trip closure
/// alongside [`Self::to_json`]. THEORY.md §V.1 — knowable
/// platform; the inverse projection becomes a NAMED primitive on
/// the substrate's `Sexp` algebra rather than a `domain`-module
/// free function consumers reach across module boundaries to call.
/// THEORY.md §II.1 invariant 2 — free middle; every consumer that
/// round-trips through JSON (the typed-rewriter at
/// [`crate::domain::TypedRewriter`], the derive macro's
/// `compile_from_args` JSON fallthrough, the test round-trip
/// fixtures) routes through ONE inherent algebra method — the
/// typed round-trip closure is structurally complete on the
/// `Sexp` algebra.
///
/// Frontier inspiration: MLIR's `mlir::parseAttribute(str, ctx)` —
/// the typed-IR parser inverse of `printAttribute` lives on the
/// same `Attribute` algebra as its printer dual; the substrate's
/// [`Self::from_json`] is the unstructured-Rust peer on the
/// `Sexp` algebra for the JSON canonical-form inverse, paired
/// with [`Self::to_json`] as the closed round-trip. Racket's
/// `(datum->syntax stx datum)` — the round-trip inverse of
/// `(syntax->datum stx)`, projected at the `datum` algebra layer;
/// `Self::from_json` is the substrate's peer at the `Sexp` layer
/// (one algebra level lower than Racket's `syntax` wrapper).
#[must_use]
pub fn from_json(v: &serde_json::Value) -> Self {
match v {
serde_json::Value::Null => Self::Nil,
serde_json::Value::Bool(b) => Self::boolean(*b),
// Numeric arm — the (JSON `Number` → typed [`Atom`]
// numeric variant) bifurcation lifts onto the closed-set
// [`Atom`] algebra via [`Atom::from_json_number`]. Pre-lift
// this arm carried its own inline three-branch cascade
// (`n.as_i64()` sink to [`Self::int`] then `n.as_f64()`
// sink to [`Self::float`] then a `Self::int(0)` typed
// floor for the structural-impossibility residual);
// post-lift the WHOLE cascade binds at ONE typed projection
// on the algebra so a delimiter swap of the numeric axis
// (e.g. adding a `u64`-fitting arm for the
// `serde-preserve-order` feature's `arbitrary_precision`
// mode, extending [`Atom`] with a `Bigint` variant) extends
// [`Atom::from_json_number`] ONCE — the outer [`Self::from_json`]
// arm here delegates through the algebra with zero edits.
// Structural dual of [`Atom::to_json`]'s [`Atom::Int`] /
// [`Atom::Float`] arms one algebra layer over: the paired
// FORWARD (typed variant → `JValue::Number`) AND INVERSE
// (`JValue::Number` → typed variant) numeric-axis
// projections both live on the closed-set [`Atom`] algebra,
// and this outer [`Self::from_json`] arm binds to the
// inverse peer at ONE typed method. Sibling-shape pin to
// [`Self::Atom`]'s general delegation posture — the outer
// `Sexp` layer wraps the atomic algebra's typed projection
// via [`Self::Atom`] rather than re-deriving the
// per-variant construction at this consumer.
serde_json::Value::Number(n) => Self::Atom(Atom::from_json_number(n)),
serde_json::Value::String(s) => Self::string(s.clone()),
serde_json::Value::Array(items) => {
Self::List(items.iter().map(Self::from_json).collect())
}
serde_json::Value::Object(map) => {
let mut out = Vec::with_capacity(map.len() * 2);
for (k, v) in map {
out.push(Self::keyword(crate::domain::camel_to_kebab(k)));
out.push(Self::from_json(v));
}
Self::List(out)
}
}
}
pub fn as_symbol(&self) -> Option<&str> {
self.as_atom().and_then(Atom::as_symbol)
}
pub fn as_keyword(&self) -> Option<&str> {
self.as_atom().and_then(Atom::as_keyword)
}
pub fn as_string(&self) -> Option<&str> {
self.as_atom().and_then(Atom::as_string)
}
pub fn as_int(&self) -> Option<i64> {
self.as_atom().and_then(Atom::as_int)
}
/// `Some(f)` for `Atom::Float(f)`, AND `Some(n as f64)` for
/// `Atom::Int(n)` — caller convenience at the numeric-kwarg
/// boundary. The Int-widening face lives at this consumer layer
/// rather than at [`Atom::as_float`] (strict per the typed-identity
/// discipline pinned at [`Atom::as_int`]'s docstring); the typed
/// soft-projection algebra on `Atom` stays strict, and the
/// `Sexp::as_float` consumer composes the strict typed projection
/// with a fallback widening branch on `Atom::as_int`.
pub fn as_float(&self) -> Option<f64> {
let a = self.as_atom()?;
a.as_float().or_else(|| a.as_int().map(|n| n as f64))
}
pub fn as_bool(&self) -> Option<bool> {
self.as_atom().and_then(Atom::as_bool)
}
/// `foo` or `"foo"` — useful for names that may be authored either way.
///
/// Structural-lift composition: routes through [`Sexp::as_atom`] + the
/// algebra-level [`Atom::as_symbol_or_string`] union projection — the
/// same `as_atom().and_then(Atom::as_X)` composition pattern
/// [`Sexp::as_symbol`] / [`Sexp::as_keyword`] / [`Sexp::as_string`] /
/// [`Sexp::as_int`] / [`Sexp::as_bool`] route through on the
/// per-variant axis. Lifts the disjunctive
/// `self.as_symbol().or_else(|| self.as_string())` composition at this
/// site's pre-lift body (TWO `Sexp::as_atom` traversals — one per
/// per-variant projection) onto ONE typed-algebra union projection
/// reached via ONE `Sexp::as_atom` traversal.
///
/// Composition law: `s.as_symbol_or_string() == s.as_atom().and_then(Atom::as_symbol_or_string)`
/// for every [`Sexp`] `s`. See [`Atom::as_symbol_or_string`] for the
/// algebra-level peer's docstring (per-variant family completion +
/// theory grounding).
pub fn as_symbol_or_string(&self) -> Option<&str> {
self.as_atom().and_then(Atom::as_symbol_or_string)
}
/// The symbol in operator position — `Some(s)` iff this is a non-empty
/// list whose first element is a symbol (`(defpoint …)` → `Some("defpoint")`).
/// `None` for every other shape: a non-list (`foo`, `5`, `:kw`), the
/// empty list `()`, and a list whose head is not a symbol (`(5 …)`,
/// `(:kw …)`, `((nested) …)`).
///
/// This is the *operator-position projection* — the structural query
/// every form-dispatch site in the substrate keys on: "what operator
/// does this form invoke?" Macroexpansion (`Expander::expand` looks up
/// the head against the macro table; `macro_def_from` reads it to
/// recognize a `defmacro` head) and the typed compilers
/// (`compile_typed` / `compile_named_from_forms` match it against
/// `T::KEYWORD`) all asked the same `self.as_list()?.first()?.as_symbol()`
/// question inline. Naming it once makes "operator position" a primitive
/// of the `Sexp` algebra rather than four byte-identical inline chains.
///
/// This is the SOFT face of operator-position dispatch — it answers
/// "is this form an invocation of some operator?" and yields `None`
/// (skip / fall through) for everything that isn't, with no diagnostic.
/// Its STRICT sibling is `TataraDomain::compile_from_sexp`, which on a
/// matched-arity form distinguishes the empty-list and
/// present-but-not-a-symbol head sub-modes to emit a rich
/// `MissingHeadSymbol` rejection. The two are the dispatch (`head_symbol`)
/// and the gate (`compile_from_sexp`) faces of the same projection;
/// keeping both lets a site choose "skip silently" or "reject loudly"
/// without re-deriving the head.
///
/// `head_symbol` is the operator projection of [`Sexp::as_call`]: it
/// keeps the head and discards the argument tail. The
/// `as_list()?.first()?.as_symbol()` chain lives in ONE place
/// (`as_call`); this is its first component.
pub fn head_symbol(&self) -> Option<&str> {
self.as_call().map(|(head, _)| head)
}
/// Decompose a call form into its operator and argument tail —
/// `Some((op, args))` iff this is a non-empty list whose first element
/// is a symbol, where `op` is that head symbol and `args` is the
/// remaining elements (`&self[1..]`, possibly empty). `None` for every
/// shape `head_symbol` rejects: a non-list, the empty list, and a list
/// whose head is present but not a symbol.
///
/// This is the *call-form decomposition* — the structural shape of a
/// Lisp invocation: an operator applied to an argument tail. It pairs
/// the operator-position projection (`head_symbol`) with the argument
/// tail every dispatch site reads immediately after matching the
/// operator. Macroexpansion (`Expander::expand`) applies the matched
/// macro to `&list[1..]`; the typed compilers (`compile_typed`,
/// `compile_named_from_forms`) feed `&list[1..]` into
/// `T::compile_from_args`. Before this query each site bound
/// `as_list()` for the tail AND independently called `head_symbol()`
/// (which itself re-derives `as_list().first()`) for the operator —
/// two traversals of the same list, two projections. `as_call` yields
/// both from one match, so the operator and its arguments can never
/// drift out of agreement at a dispatch site.
///
/// Soft face, like `head_symbol`: it answers "is this an invocation of
/// some operator, and what are its arguments?" and yields `None` (skip
/// / fall through) for everything that isn't, with no diagnostic. The
/// strict gate sibling is `TataraDomain::compile_from_sexp`, which
/// distinguishes the empty-list and non-symbol-head sub-modes to reject
/// loudly.
pub fn as_call(&self) -> Option<(&str, &[Sexp])> {
let list = self.as_list()?;
let head = list.first()?.as_symbol()?;
Some((head, &list[1..]))
}
/// Canonical call-form outer constructor — composes the atomic-
/// payload construct family's [`Self::symbol`] (the head-position
/// construct on the 6-of-12 atomic carving of [`SexpShape`]) with
/// the residual-axis construct family's [`Self::list`] (via
/// `std::iter::once(head_sexp).chain(args)`) to build a symbol-
/// headed list-shaped [`Sexp`] value at ONE site on the closed-set
/// [`Sexp`] algebra. The call-form section-for-retraction sibling
/// of the existing [`Self::as_call`] soft-projection ([`Option<(&
/// str, &[Sexp])>`]): where the projection soft-decomposes a
/// symbol-headed list into its head symbol and argument tail, this
/// constructor embeds a fresh (head string, item sequence) pair
/// into the matching call-shaped wrapper.
///
/// Composition sibling of the atomic-payload construct family
/// ([`Self::symbol`], [`Self::keyword`], [`Self::string`],
/// [`Self::int`], [`Self::float`], [`Self::boolean`] — routing
/// through the typed [`Atom`] family on the 6-of-12 atomic carving),
/// the quote-family construct family ([`Self::quote`],
/// [`Self::quasiquote`], [`Self::unquote`], [`Self::unquote_splice`]
/// — routing through the typed [`QuoteForm::wrap`] family on the
/// 4-of-12 quote-family carving), and the residual-axis construct
/// [`Self::list`] (routing owned or iterable item sequences into
/// the tuple-variant on the 2-of-12 residual carving): those close
/// the (construct, project) algebra dual on their respective
/// STRUCTURAL carvings; this closes the (construct, project)
/// algebra dual on the SYMBOL-HEADED-LIST TYPED DECOMPOSITION — the
/// load-bearing shape every Lisp invocation, every `(defX …)`
/// typed-domain call form, and every macroexpander template head
/// takes on the outer [`Sexp`] algebra.
///
/// Composition law (forward, through the outer algebra's atomic +
/// residual construct families): `Sexp::call(head, args) ==
/// Sexp::list(std::iter::once(Sexp::symbol(head)).chain(args))` for
/// every `head: impl Into<String>` + `args: impl IntoIterator<Item
/// = Sexp>`. The body binds through the SAME two construct methods
/// consumers already reach for when threading a head-then-rest
/// sequence into a call form — the composition law lifts that
/// two-method inline pattern to ONE named query on the outer
/// [`Sexp`] algebra.
///
/// Round-trip law (section-for-retraction with the soft-projection
/// sibling): for every `head: &str` + `args: Vec<Sexp>`,
/// `Sexp::call(head, args.clone()).as_call() == Some((head,
/// args.as_slice()))` — the outer algebra's call-form typed
/// constructor pairs section-for-retraction with the outer
/// algebra's soft call-form projection, and the (head symbol,
/// args slice) cross-projection preserves identity. Keyword-
/// matched round-trip law: for every `head: &str` + `args:
/// Vec<Sexp>`, `Sexp::call(head, args.clone()).as_call_to(head) ==
/// Some(args.as_slice())` — the keyword-typed projection recovers
/// the args tail iff its argument keyword matches the constructor's
/// head. Head-symbol composition law: `Sexp::call(head,
/// args).head_symbol() == Some(head.as_str())` for every `head:
/// impl Into<String>` + `args: impl IntoIterator<Item = Sexp>` —
/// the head-position projection recovers the constructor's head
/// byte-for-byte.
///
/// Outer-shape composition law: `Sexp::call(head, args).shape() ==
/// SexpShape::List` for every input — a call form is a list-shaped
/// [`Sexp`], and the outer-shape identity binds through the typed-
/// shape lattice at the residual arm. Structural-carving-marker
/// composition law: `Sexp::call(head, args).as_structural_kind()
/// == Some(StructuralKind::List)` — the residual-axis carving
/// marker binds through the closed-set [`StructuralKind`] algebra
/// at ONE arm, symmetric with the atomic-axis's `Sexp::X_atom(
/// payload).as_atom_kind() == Some(AtomKind::X)` marker
/// composition.
///
/// Pre-lift the `Sexp::List(std::iter::once(Sexp::symbol(head))
/// .chain(args).collect())` composition (or equivalently the
/// `Sexp::List(vec![Sexp::symbol(head), args...])` welded triple)
/// appeared inline at every consumer that builds a call-shaped
/// [`Sexp`] value — well past the ≥2 PRIME-DIRECTIVE trigger once
/// the call-form shape is named. Post-lift consumers that have a
/// head string + an owned or iterable sequence of args bind to ONE
/// typed-algebra method on the outer [`Sexp`] algebra with the
/// `impl Into<String>` bound on the head absorbing `&str` /
/// `String` / `&String` and the `impl IntoIterator<Item = Sexp>`
/// bound on the args absorbing `Vec<Sexp>` / `[Sexp; N]` /
/// `.map(...)` chains without a per-site `.collect::<Vec<Sexp>>()`
/// coercion.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// (head string, args sequence, [`Self::List`] tuple-variant
/// constructor) triple binds at ONE typed-algebra method on the
/// outer [`Sexp`] algebra, closing the call-form (construct,
/// project) algebra dual pair with [`Self::as_call`] /
/// [`Self::as_call_to`] / [`Self::head_symbol`]. THEORY.md §II.1
/// invariant 2 — free middle; every consumer that has a head
/// string + an owned or iterable sequence of args and wants to
/// build a call-shaped [`Sexp`] routes through the SAME typed
/// method, so a regression that drifts one consumer's construction
/// from the others (e.g. a copy-edit that emits `Sexp::keyword(
/// head)` for the head position, or that swaps in a `Sexp::string`
/// head that [`Self::as_call`] then rejects at the projection
/// site) cannot reach the substrate's runtime. THEORY.md §V.1 —
/// knowable platform; the call-form typed-construct becomes a TYPE
/// projection on the substrate's outer [`Sexp`] algebra sitting
/// next to the typed-project family [`Self::as_call`] /
/// [`Self::as_call_to`] rather than bare tuple-variant constructor
/// paired with per-site `Sexp::List(vec![Sexp::symbol(...), ...])`
/// discipline. THEORY.md §VI.1 — generation over composition; the
/// call-form pair emerges from ONE typed-algebra composition
/// through [`Self::list`] composed with [`Self::symbol`] rather
/// than from per-consumer per-callsite literals; a future call-
/// form shape extension (e.g. a keyword-headed call form for a
/// Kernel-style applicative-vs-operative split) lands as ONE peer
/// constructor on this algebra alongside the residual, quote-
/// family, and atomic-payload construct families.
#[must_use]
pub fn call<H, I>(head: H, args: I) -> Self
where
H: Into<String>,
I: IntoIterator<Item = Sexp>,
{
Self::list(std::iter::once(Self::symbol(head)).chain(args))
}
/// Canonical named-call-form outer constructor — composes the call-
/// form typed constructor [`Self::call`] with the atomic-payload
/// construct family's [`Self::symbol`] (for the NAME slot) via
/// `std::iter::once(Self::symbol(name)).chain(spec_args)` to build a
/// `(head NAME spec_args…)` symbol-headed named list-shaped [`Sexp`]
/// value at ONE site on the closed-set [`Sexp`] algebra. The named-
/// call-form section-for-retraction sibling of the existing
/// [`Self::as_named_call_to`] soft-projection ([`Option<crate::error::
/// Result<(&str, &[Sexp])>>`]): where the projection soft-decomposes
/// a `(<keyword> NAME spec_args…)` symbol-headed list into its NAME
/// symbol and spec args tail through the named-form gate
/// ([`crate::compile::split_name_slot`]), this constructor embeds a
/// fresh `(head string, name string, spec_args sequence)` triple
/// into the matching named-call-shaped wrapper. Composition sibling
/// of the call-form construct [`Self::call`] on the outer algebra:
/// where [`Self::call`] closes the (construct, project) dual on the
/// CALL-FORM TYPED DECOMPOSITION (`(head args…)`), this closes the
/// dual on the NAMED-CALL-FORM TYPED DECOMPOSITION (`(head NAME
/// spec_args…)`) — the load-bearing shape every `(defX NAME …)`
/// typed-domain named authoring form takes on the outer [`Sexp`]
/// algebra, and the section-for-retraction dual of the
/// [`crate::compile::split_name_slot`] gate at the value level.
///
/// Composition law (forward, through the call-form + atomic-payload
/// construct families): `Sexp::named_call(head, name, spec_args) ==
/// Sexp::call(head, std::iter::once(Sexp::symbol(name)).chain(
/// spec_args))` for every `head: impl Into<String>` + `name: impl
/// Into<String>` + `spec_args: impl IntoIterator<Item = Sexp>`. The
/// body binds through the SAME two construct methods consumers
/// already reach for when threading a head-then-name-then-rest
/// sequence into a named call form — the composition law lifts that
/// two-method inline pattern to ONE named query on the outer
/// [`Sexp`] algebra.
///
/// Round-trip law (section-for-retraction with the named-form soft-
/// projection): for every `head: &'static str` + `name: &str` +
/// `spec_args: Vec<Sexp>`, `Sexp::named_call(head, name, spec_args
/// .clone()).as_named_call_to(head) == Some(Ok((name, spec_args
/// .as_slice())))` — the outer algebra's named-call-form typed
/// constructor pairs section-for-retraction with the outer
/// algebra's soft named-call-form projection, and the (head symbol,
/// NAME symbol, spec args slice) cross-projection preserves
/// identity. Call-form projection composition: `Sexp::named_call(
/// head, name, spec_args).as_call() == Some((head,
/// once(Sexp::symbol(name)).chain(spec_args).collect().as_slice()
/// ))` — the call-form soft-projection recovers `(head, [name,
/// spec_args…])` with the NAME symbol as the first arg, mirroring
/// the [`Self::call`] round-trip on the encompassing call algebra.
/// Keyword-matched round-trip law: for every `head: &'static str` +
/// `name: &str` + `spec_args: Vec<Sexp>`, `Sexp::named_call(head,
/// name, spec_args.clone()).as_call_to(head) == Some(
/// [Sexp::symbol(name), spec_args…].as_slice())` — the keyword-
/// typed projection recovers the NAME-headed args tail iff its
/// argument keyword matches the constructor's head. Head-symbol
/// composition law: `Sexp::named_call(head, name, spec_args)
/// .head_symbol() == Some(head.as_str())` — the head-position
/// projection recovers the constructor's head byte-for-byte.
///
/// Outer-shape composition law: `Sexp::named_call(head, name,
/// spec_args).shape() == SexpShape::List` for every input — a
/// named call form is a list-shaped [`Sexp`], the outer-shape
/// identity binds through the typed-shape lattice at the residual
/// arm. Structural-carving-marker composition law: `Sexp::
/// named_call(head, name, spec_args).as_structural_kind() ==
/// Some(StructuralKind::List)` — the residual-axis carving marker
/// binds through the closed-set [`StructuralKind`] algebra at ONE
/// arm, symmetric with [`Self::call`]'s residual-arm marker
/// composition.
///
/// Named-form gate composition law: `crate::compile::split_name_slot(
/// &Sexp::named_call(head, name, spec_args).as_call_to(head)
/// .unwrap(), head) == Ok((name, spec_args.as_slice()))` — the
/// substrate's named-form arity + NAME-shape gate accepts every
/// output of this constructor byte-for-byte, closing the section-
/// for-retraction pair at the gate level as well as at the
/// projection level. A constructor emission that drifts into a
/// missing-NAME shape (empty spec_args yields `(head)`, which the
/// call-form projection recovers but the named-form gate rejects
/// with `NamedFormMissingName`) or a non-symbol-NAME shape
/// (`Sexp::keyword(name)` for the NAME position, which the gate
/// rejects with `NamedFormNonSymbolName`) becomes structurally
/// impossible — the `impl Into<String>` NAME bound admits string
/// payloads only, and the [`Self::symbol`] wrap routes to the
/// symbol atom variant `as_symbol_or_string` accepts.
///
/// Pre-lift the `Sexp::call(head, std::iter::once(Sexp::symbol(
/// name)).chain(spec_args))` composition (or equivalently the
/// `Sexp::List(vec![Sexp::symbol(head), Sexp::symbol(name),
/// spec_args...])` welded quadruple) appeared inline at every
/// consumer that builds a `(defX NAME …)`-shaped [`Sexp`] value
/// — well past the ≥2 PRIME-DIRECTIVE trigger once the named
/// call-form shape is named. Post-lift consumers that have a head
/// string + a NAME string + an owned or iterable sequence of spec
/// args bind to ONE typed-algebra method on the outer [`Sexp`]
/// algebra with the two `impl Into<String>` bounds absorbing `&str`
/// / `String` / `&String` on both string positions and the
/// `impl IntoIterator<Item = Sexp>` bound on the spec args
/// absorbing `Vec<Sexp>` / `[Sexp; N]` / `.map(...)` chains without
/// a per-site `.collect::<Vec<Sexp>>()` coercion.
///
/// Frontier inspiration: Racket's `syntax-parse`
/// `(~datum keyword) name:id spec ...` pattern binds the NAME slot
/// through the `name:id` capture binder and consumers reference it
/// downstream; the constructor peer on the same surface is
/// `syntax-e` composed with `datum->syntax` wrapping a
/// `(list #'keyword name-id spec-list ...)` triple. `Sexp::
/// named_call` is the unstructured-Rust peer — a section-for-
/// retraction constructor on the outer algebra that mirrors the
/// `~datum keyword name:id spec ...` pattern's NAME capture on the
/// construct side. Tree-sitter's `query`-matched named captures
/// have the same shape on the tree side: the query pattern
/// binds a NAME capture, the constructor peer (`ts_node_new`
/// composed with `ts_node_field_set`) embeds a fresh NAME child at
/// the corresponding field slot. The typed structural rejection
/// chain the substrate's named-form gate emits
/// ([`crate::error::LispError::NamedFormMissingName`],
/// [`crate::error::LispError::NamedFormNonSymbolName`]) is
/// preserved by construction — the constructor cannot emit a
/// value the gate rejects, symmetric with the `~datum` /
/// `name:id` reader-side rejection that fires BEFORE any
/// downstream binding sees the drifted shape.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// (head string, NAME string, spec args sequence, [`Self::call`]
/// call-form constructor) quadruple binds at ONE typed-algebra
/// method on the outer [`Sexp`] algebra, closing the named-call-
/// form (construct, project) algebra dual pair with
/// [`Self::as_named_call_to`] / [`Self::as_named_call_to_any`] on
/// the projection side and [`crate::compile::split_name_slot`] on
/// the gate side. THEORY.md §II.1 invariant 2 — free middle;
/// every consumer that has a head + NAME + spec args and wants to
/// build a named-call-shaped [`Sexp`] routes through the SAME
/// typed method, so a regression that drifts one consumer's
/// construction from the others (e.g. a copy-edit that emits
/// `Sexp::keyword(name)` for the NAME position, which the
/// named-form gate would reject with `NamedFormNonSymbolName`)
/// cannot reach the substrate's runtime. THEORY.md §V.1 —
/// knowable platform; the named-call-form typed-construct becomes
/// a TYPE projection on the substrate's outer [`Sexp`] algebra
/// sitting next to the typed-project family [`Self::
/// as_named_call_to`] / [`Self::as_named_call_to_any`] +
/// [`crate::ast::iter_named_calls_to`] /
/// [`crate::ast::iter_named_calls_to_any`] rather than a per-site
/// inline composition. THEORY.md §VI.1 — generation over
/// composition; the named-call-form pair emerges from ONE typed-
/// algebra composition through [`Self::call`] composed with
/// [`Self::symbol`] rather than from per-consumer per-callsite
/// literals; a future named-form shape extension (e.g. a
/// dotted-NAME form, or a typed-NAME form where the NAME slot
/// carries a compile-time-decoded typed witness) lands as ONE
/// peer constructor on this algebra alongside the call-form,
/// residual, quote-family, and atomic-payload construct
/// families.
#[must_use]
pub fn named_call<H, N, I>(head: H, name: N, spec_args: I) -> Self
where
H: Into<String>,
N: Into<String>,
I: IntoIterator<Item = Sexp>,
{
Self::call(head, std::iter::once(Self::symbol(name)).chain(spec_args))
}
/// Decompose a call form into its argument tail IFF the head matches the
/// supplied `keyword` — `Some(args)` iff this is a non-empty list whose
/// first element is a symbol equal to `keyword`, where `args` is the
/// remaining elements (`&self[1..]`, possibly empty). `None` for every
/// shape `as_call` rejects AND for every call whose head is present but
/// differs from `keyword`.
///
/// This is the *keyword-typed call decomposition* — the natural
/// extension of [`Sexp::as_call`] for the "is this a call to ONE
/// specific operator?" question every typed-domain dispatch site asks
/// after macroexpansion. [`compile_typed`](crate::compile::compile_typed)
/// and [`compile_named_from_forms`](crate::compile::compile_named_from_forms)
/// both opened the same two-step chain inline —
/// `if let Some((head, args)) = form.as_call() { if head == T::KEYWORD { … } }`
/// — at every form they walked; the chain IS this projection. Naming
/// it lifts "is this form a call to T?" from a two-step inline pattern
/// to ONE structural query on the `Sexp` algebra. A regression that
/// drifts one consumer's comparison from `==` to `!= `, or that
/// compares against a different label than `T::KEYWORD` (e.g.
/// substring-grepping the rendered head), becomes structurally
/// impossible: there is exactly one implementation both dispatchers
/// route through.
///
/// Soft face, like the rest of the `as_*` family: it answers "is this
/// a call to `keyword`, and what are its arguments?" and yields `None`
/// for everything that isn't (skip / fall through), with no
/// diagnostic. The strict gate sibling is
/// `TataraDomain::compile_from_sexp`, which distinguishes the
/// not-a-list / empty-list / non-symbol-head / wrong-keyword
/// sub-modes to reject loudly. The two are the dispatch
/// (`as_call_to`) and the gate (`compile_from_sexp`) faces of the
/// same projection; keeping both lets a site choose "skip silently"
/// or "reject loudly" without re-deriving the head.
///
/// Structural identity binding it to its siblings:
/// * `as_call_to(keyword) == as_call().and_then(|(h, args)| (h == keyword).then_some(args))`
/// * `as_call_to(keyword).is_some() == (head_symbol() == Some(keyword))`
///
/// The returned `&[Sexp]` borrows from the list's tail verbatim — no
/// copy, no allocation, same lifetime as [`Sexp::as_call`]'s tail.
///
/// Slice-side sibling: [`iter_calls_to`] lifts this per-form projection
/// onto a `&[Sexp]`, yielding the args slices of every matching form in
/// source order — the substrate's typed-keyword filter over a batch of
/// forms, structurally bound to this per-form projection via the
/// closed-form composition
/// `iter_calls_to(forms, k) == forms.iter().filter_map(|f| f.as_call_to(k))`.
pub fn as_call_to(&self, keyword: &str) -> Option<&[Sexp]> {
let (head, args) = self.as_call()?;
(head == keyword).then_some(args)
}
/// Decompose a call form whose head decodes through a caller-supplied
/// classifier — `Some((decoded, args))` iff this is a non-empty list
/// whose first element is a symbol AND `decode(head)` returns
/// `Some(decoded)`, where `args` is the remaining elements
/// (`&self[1..]`, possibly empty). `None` for every shape
/// [`Sexp::as_call`] rejects AND for every call whose head is present
/// but `decode` rejects.
///
/// This is the *typed-decoded call decomposition* — the closure-typed
/// extension of [`Sexp::as_call_to`] for the "is this a call whose head
/// belongs to a CLOSED SET (or a LIVE REGISTRY) that decodes to a typed
/// witness?" question. Where [`Sexp::as_call_to`] filters by ONE
/// constant keyword, `as_call_to_any` filters AND TYPES by a caller-
/// supplied projection — every dispatch site that asks "is this form
/// an invocation of any of N operators, decoded as a typed enum or
/// resolved against a runtime table?" binds to ONE structural query
/// on the `Sexp` algebra. Two consumers route through it:
///
/// * The macro-expander's `macro_def_from` — closed-set classifier:
/// `as_call_to_any(MacroDefHead::from_keyword)` decides which of
/// `{defmacro, defpoint-template, defcheck}` a top-level form
/// invokes, decoded to the typed `MacroDefHead` enum. Pre-lift the
/// site opened the same three-step chain inline — `let Some(list)
/// = form.as_list()…; let Some(head) = form.head_symbol()…; let
/// Some(decoded) = MacroDefHead::from_keyword(head)…`.
/// * The macro-expander's `Expander::expand` — live-registry
/// classifier: `as_call_to_any(|h| self.macros.get(h))` decides
/// which of the registered macros (a `HashMap<String, MacroDef>`
/// populated by `expand_program`'s `defmacro` recognition) a form
/// invokes, decoded to `&MacroDef`. Pre-lift the site opened the
/// same `as_list() + as_call() + self.macros.get(head)` chain
/// inline — `as_list()` for the children-walk fallthrough,
/// `as_call()` for the (head, args) pair (which itself re-derives
/// `as_list()` internally), and `self.macros.get(head)` for the
/// registry lookup.
///
/// Naming the projection lifts "is this form a call to any of N
/// operators, decoded to T?" from the three-step inline pattern to
/// ONE structural query — closed-set enum classifier OR live-registry
/// HashMap classifier, the family primitive is uniform under both.
///
/// Soft face, like the rest of the `as_*` family: it answers "is this
/// a call whose head decodes through `F`, and what are its arguments?"
/// and yields `None` for everything that isn't (skip / fall through),
/// with no diagnostic. The strict gate sibling stays
/// `TataraDomain::compile_from_sexp` — that distinguishes the
/// not-a-list / empty-list / non-symbol-head / wrong-keyword sub-modes
/// to reject loudly for a single-keyword consumer. The two are the
/// closed-set-decoded dispatch (`as_call_to_any`) and the
/// single-keyword gate (`compile_from_sexp`) faces of the typed-domain
/// recognition problem; keeping both lets a site choose "skip
/// silently if the head isn't ours" or "reject loudly if the head
/// isn't the exact keyword" without re-deriving the head.
///
/// Structural identity binding it to its siblings:
/// * `as_call_to_any(decode) == as_call().and_then(|(h, args)| decode(h).map(|d| (d, args)))`
/// * `as_call_to(k) == as_call_to_any(|h| (h == k).then_some(())).map(|(_, a)| a)` (modulo the discarded `()`)
/// * `as_call_to_any(decode).is_some() == as_call().map_or(false, |(h, _)| decode(h).is_some())`
///
/// The returned `&[Sexp]` borrows from the list's tail verbatim — no
/// copy, no allocation, same lifetime as [`Sexp::as_call`]'s tail.
/// `T` is owned because `decode` is `FnOnce(&str) -> Option<T>` and a
/// `&'_ str` borrow into the head symbol would not outlive the helper
/// boundary; consumers projecting to a typed `Copy` enum (e.g.
/// `MacroDefHead`) get the value directly, consumers projecting to a
/// borrowed `&'static str` (a closed-set head) project to
/// `&'static str` and inherit the static lifetime through the
/// classifier.
///
/// Slice-side sibling: [`iter_calls_to_any`] lifts this per-form
/// projection onto a `&[Sexp]`, yielding the `(decoded, &[Sexp])`
/// pair of every matching form in source order — the substrate's
/// typed-decoded filter over a batch of forms, structurally bound
/// to this per-form projection via the closed-form composition
/// `iter_calls_to_any(forms, decode) == forms.iter().filter_map(|f|
/// f.as_call_to_any(&mut decode))`. The slice-side primitive
/// promotes the closure constraint from [`FnOnce`] (per-form, one
/// call per invocation) to [`FnMut`] (slice-side, one call per
/// element) so a decoder that captures mutable state (a counter, a
/// registry cache) maintains state across the batch walk.
pub fn as_call_to_any<F, T>(&self, decode: F) -> Option<(T, &[Sexp])>
where
F: FnOnce(&str) -> Option<T>,
{
let (head, args) = self.as_call()?;
decode(head).map(|d| (d, args))
}
/// Decompose a named call form (a `(<keyword> NAME :k v …)` shape) whose
/// head decodes through a caller-supplied classifier — `Some(Ok((decoded,
/// name, spec_args)))` iff this is a non-empty list whose first element
/// is a symbol AND `decode(head)` returns `Some((decoded, kw))` AND the
/// remaining elements split cleanly into a NAME slot (symbol or string
/// at position 1) and a spec args tail (position 2..), `Some(Err(…))` iff
/// the head decodes but the NAME slot is missing
/// ([`LispError::NamedFormMissingName`]) or non-symbol-or-string
/// ([`LispError::NamedFormNonSymbolName`]), `None` for every shape
/// [`Sexp::as_call_to_any`] rejects AND for every call whose head is
/// present but `decode` returns `None` for.
///
/// This is the *per-form named-classifier projection* — the per-form
/// peer of [`iter_named_calls_to_any`] on the slice algebra and of
/// [`crate::macro_expand::Expander::expand_and_collect_named_calls_to_any`]
/// on the expander surface. Closes the (per-form × classifier × named)
/// corner of the soft-dispatch cube the substrate's per-form algebra
/// (`as_call_to{,_any}`) and slice algebra (`iter_calls_to{,_any}`,
/// `iter_named_calls_to{,_any}`) collectively shape — pre-lift the cube
/// at the per-form × named corner was "(composed inline at each named
/// consumer)" (the documented gap the cube table inside
/// [`iter_named_calls_to_any`] called out), post-lift the per-form ×
/// named row binds to ONE primitive every per-form named consumer
/// composes through:
///
/// | | bare-kwargs | named NAME-then-kwargs |
/// |----------------|------------------------------|--------------------------------------|
/// | per-form | [`Sexp::as_call_to_any`] | `as_named_call_to_any` (this) |
/// | slice | [`iter_calls_to_any`] | [`iter_named_calls_to_any`] |
/// | expander | `expand_and_collect_calls_to_any` | `expand_and_collect_named_calls_to_any` |
///
/// The slice-side [`iter_named_calls_to_any`] now routes through THIS
/// per-form primitive via the SAME `forms.iter().filter_map(_)`
/// skeleton [`iter_calls_to_any`] uses to route through
/// [`Sexp::as_call_to_any`], so a regression that drifts ONE row's
/// instrumentation, span-aware borrow walker, or fused-iterator
/// invariant from the bare row to the named row (or vice versa) is
/// structurally impossible.
///
/// Composes [`Sexp::as_call_to_any`] with
/// [`crate::compile::split_name_slot`]: the classifier filter precedes
/// the named gate, mirroring how `split_name_slot` is composed AFTER
/// the classifier-decoded args tail is already in hand inside
/// [`iter_named_calls_to_any`]. Decoder signature `FnOnce(&str) ->
/// Option<(T, &'static str)>` pairs the typed witness `T` with the
/// canonical static keyword threaded through the
/// `NamedFormMissingName.keyword` / `NamedFormNonSymbolName.keyword`
/// slots of the named-form gate — the `&'static` constraint pins the
/// same compile-time discipline [`crate::compile::split_name_slot`]'s
/// `keyword: &'static str` parameter pins at the slice-side boundary,
/// AND that the slice-side decoder signature pins on the slice
/// algebra.
///
/// Three-arm result shape — `Option<Result<…>>` — preserves both the
/// classifier filter face (`None` for "not our head, skip silently",
/// matching the per-form soft-projection posture of every other `as_*`
/// method on `Sexp`) AND the named gate face (`Err` for "matched head
/// but malformed NAME", surfacing the typed structural-rejection
/// variants `LispError::NamedFormMissingName` /
/// `LispError::NamedFormNonSymbolName` the slice-side and expander-
/// surface consumers already short-circuit on). A consumer that wants
/// "fold over every per-form result, short-circuiting on the first
/// malformed NAME" composes `.transpose()` (yielding
/// `Result<Option<…>>`) and `?`-routes the outer `Result`; a consumer
/// that wants "skip every non-matching form AND every malformed
/// matched form" composes `.and_then(|res| res.ok())` (yielding
/// `Option<(T, &str, &[Sexp])>`); a consumer that wants the raw
/// three-arm shape pattern-matches directly.
///
/// Two plausible future consumer shapes the per-form named-classifier
/// projection admits with no boilerplate:
/// * **LSP hover tooltip** — an authoring tool that surfaces a
/// tooltip on the symbol under the cursor wants to ask "is THIS
/// form (the one I just resolved to under the cursor) a named
/// call to any registered domain, decoded to a typed kind, with
/// the borrowed NAME slot extracted for the tooltip body?". Pre-
/// lift the tool would re-derive `form.as_call_to_any(decode)
/// .and_then(|((kind, kw), args)| split_name_slot(args,
/// kw).ok().map(|(name, rest)| (kind, name, rest)))` inline;
/// post-lift the tool binds to ONE primitive.
/// * **REPL single-form dispatcher** — a `:dispatch <classifier>
/// <form>` command that walks a single form through the
/// registry classifier, reporting the typed kind AND the NAME
/// slot (for "you said `(defmonitor my-monitor …)`, I see
/// `Monitor` named `my-monitor` with 3 spec args"). Pre-lift
/// the REPL would re-derive the same inline composition; post-
/// lift the REPL binds to ONE primitive, sibling shape to how
/// [`Sexp::as_call_to_any`] backs the slice-side dispatcher
/// [`iter_calls_to_any`].
///
/// Structural identity binding it to its siblings:
/// * `as_named_call_to_any(decode) == as_call_to_any(decode).map(|((d, kw), args)| split_name_slot(args, kw).map(|(name, rest)| (d, name, rest)))`
/// * `as_named_call_to(k) == as_named_call_to_any(|h| (h == k).then_some(((), k))).map(|res| res.map(|(_, name, rest)| (name, rest)))`
/// * `as_named_call_to_any(decode).is_none() == as_call_to_any(decode).is_none()` (the classifier filter face is identical to the bare-kwargs sibling's)
///
/// The returned `&str` NAME slot and `&[Sexp]` spec args tail borrow
/// from `&self` verbatim — no copy, no allocation, same lifetime as
/// [`Sexp::as_call_to_any`]'s tail AND [`crate::compile::split_name_slot`]'s
/// pair. `T` is owned because the underlying [`Sexp::as_call_to_any`]
/// classifier is `FnOnce(&str) -> Option<(T, &'static str)>` and `T`
/// must outlive the helper boundary; consumers projecting to a typed
/// `Copy` enum (e.g. a closed-set `Kind`) get the value directly,
/// consumers projecting to a borrowed `&'static str` (a closed-set
/// head sourced from `ClosedSet::ALL.label()`) project to `&'static
/// str` and inherit the static lifetime through the classifier.
///
/// Soft face on the classifier filter, strict face on the named gate:
/// "is this a named call whose head decodes through `F`, and what
/// are its NAME and spec args?" yielding `None` for "not our head"
/// (skip / fall through, no diagnostic) AND `Some(Err(…))` for "our
/// head but malformed NAME" (reject loudly, structural variant). The
/// soft-classifier-then-strict-named composition matches the
/// slice-side `iter_named_calls_to_any` yielded `Result` shape (with
/// non-matching forms skipped by the iterator filter) and the
/// expander-surface `expand_and_collect_named_calls_to_any` collect
/// shape (with `Result::collect` short-circuiting on the first
/// malformed NAME) — every layer of the cube preserves both faces.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// per-form × classifier × named cell of the soft-dispatch cube is a
/// CONSEQUENCE of [`Sexp::as_call_to_any`] + [`crate::compile::split_name_slot`],
/// named on the substrate's `Sexp` algebra rather than re-derived
/// inline at every per-form named consumer site. THEORY.md §V.1 —
/// knowable platform; the per-form named-classifier projection
/// becomes a NAMED primitive on the `Sexp` algebra, discoverable by
/// any future authoring tool (LSP, REPL, `tatara-check`) that holds
/// a single form in isolation. THEORY.md §II.1 invariant 2 — free
/// middle; the slice-side sibling [`iter_named_calls_to_any`] now
/// routes through this per-form primitive via the same
/// `forms.iter().filter_map(_)` skeleton the bare-kwargs row uses
/// to route through [`Sexp::as_call_to_any`], so the bare and named
/// rows share ONE filter-and-fuse implementation skeleton on the
/// `Sexp`/`&[Sexp]` algebras.
///
/// Frontier inspiration: MLIR's `mlir::dyn_cast<NamedOpInterface>(op)`
/// — the typed downcast from a polymorphic IR node onto a NAMED-op
/// interface that exposes both the typed witness AND the
/// symbol-name accessor is the MLIR idiom; `as_named_call_to_any` is
/// the unstructured-Rust peer on the substrate's `Sexp` algebra,
/// with `Option<Result<(T, &str, &[Sexp])>>` standing in for MLIR's
/// typed-downcast-then-name-accessor pair, and the `Result` face
/// carrying the typed structural rejection MLIR encodes via verifier
/// diagnostics. Racket's `syntax-parse` `~or* ((~datum defX) name:id
/// arg ...) ((~datum defY) name:id arg ...)` on a single syntax
/// object — typed named-form decomposition with `name:id` capture
/// binding is the Racket idiom; this method is the per-form
/// Rust-typed peer with the typed structural rejection
/// (`NamedFormMissingName` / `NamedFormNonSymbolName`) preserved
/// across the boundary.
pub fn as_named_call_to_any<F, T>(
&self,
decode: F,
) -> Option<crate::error::Result<(T, &str, &[Sexp])>>
where
F: FnOnce(&str) -> Option<(T, &'static str)>,
{
self.as_call_to_any(decode).map(|((decoded, kw), args)| {
let (name, spec_args) = crate::compile::split_name_slot(args, kw)?;
Ok((decoded, name, spec_args))
})
}
/// Decompose a named call form whose head matches a constant
/// `keyword` — `Some(Ok((name, spec_args)))` iff this is a non-empty
/// list whose first element is the symbol `keyword` AND the remaining
/// elements split cleanly into a NAME slot and a spec args tail,
/// `Some(Err(…))` iff the head matches but the NAME slot is missing
/// or non-symbol-or-string, `None` for every shape
/// [`Sexp::as_call_to`] rejects.
///
/// Constant-keyword sibling of [`Sexp::as_named_call_to_any`] and
/// per-form sibling of [`iter_named_calls_to`] on the slice algebra.
/// Routes through the typed-decoded sibling with a constant-classifier
/// decoder (`|h| (h == keyword).then_some(((), keyword))`) — the same
/// constant-classifier composition [`Sexp::as_call_to`] uses to route
/// through [`Sexp::as_call_to_any`] on the bare-kwargs axis, and that
/// [`iter_named_calls_to`] uses to route through
/// [`iter_named_calls_to_any`] on the slice algebra. The discarded
/// `()` typed witness (`then_some(((), keyword))`) is consumed by the
/// wrapper projection so the consumer's per-form mapper sees only the
/// `(name, spec_args)` borrowed pair, matching the bare projection
/// signature on the named axis.
///
/// `keyword: &'static str` threads verbatim through the
/// `NamedFormMissingName.keyword` / `NamedFormNonSymbolName.keyword`
/// slots of the named-form gate — same `&'static` discipline
/// [`crate::compile::split_name_slot`] pins at its boundary, AND that
/// [`iter_named_calls_to`] pins on the slice algebra. Consumers that
/// want a runtime keyword whose lifetime is shorter use
/// [`Sexp::as_named_call_to_any`] directly with a constant-classifier
/// decoder that converts post-resolution.
///
/// Structural identity binding it to its siblings:
/// * `as_named_call_to(k) == as_named_call_to_any(|h| (h == k).then_some(((), k))).map(|res| res.map(|(_, name, rest)| (name, rest)))`
/// * `as_named_call_to(k).is_none() == as_call_to(k).is_none()`
/// * `iter_named_calls_to(forms, k) == forms.iter().filter_map(|f| f.as_named_call_to(k))`
///
/// Theory anchor: see [`Sexp::as_named_call_to_any`] — the constant-
/// keyword sibling shares the same lift posture, threading the
/// `&'static str` keyword constraint through the named-form gate's
/// canonical-keyword slot rather than admitting an arbitrary runtime
/// keyword.
pub fn as_named_call_to(
&self,
keyword: &'static str,
) -> Option<crate::error::Result<(&str, &[Sexp])>> {
self.as_named_call_to_any(move |h| (h == keyword).then_some(((), keyword)))
.map(|res| res.map(|(_, name, rest)| (name, rest)))
}
/// Decompose an unquote-family form into its typed marker and inner
/// expression — `Some((UnquoteForm::Unquote, inner))` iff this is `,x`
/// (a [`Sexp::Unquote`] wrapper), `Some((UnquoteForm::Splice, inner))`
/// iff this is `,@x` (a [`Sexp::UnquoteSplice`] wrapper), `None` for
/// every other shape (Quote, Quasiquote, Nil, Atom, List).
///
/// This is the *unquote-family projection* — the typed-marker peer of
/// [`Sexp::as_call`] for the macro-template substitution surface. Where
/// [`Sexp::as_call`] decomposes `(op args …)` into a `(head, args)`
/// pair, `as_unquote` decomposes `,x` / `,@x` into a `(form, inner)`
/// pair where `form: UnquoteForm` is the closed-set typed marker
/// (`Unquote` for `,`, `Splice` for `,@`) and `inner: &Sexp` is the
/// borrowed body. The pairing of `Sexp::Unquote ↔ UnquoteForm::Unquote`
/// and `Sexp::UnquoteSplice ↔ UnquoteForm::Splice` is the structural
/// invariant the macro-expander's substitution path keys every
/// rejection on — naming the projection lifts the pair from
/// per-callsite discipline (two `Sexp::Unquote(inner)` arms paired
/// with two `UnquoteForm::Unquote` literals at distinct sites, two
/// `Sexp::UnquoteSplice(inner)` arms paired with two
/// `UnquoteForm::Splice` literals at distinct sites) into ONE typed
/// projection both expansion strategies route through.
///
/// Three consumers in [`macro_expand`](crate::macro_expand) route
/// through this primitive:
/// * `compile_node` (bytecode-template compile path) — `,x` becomes
/// `TemplateOp::Subst(idx)`, `,@x` becomes `TemplateOp::Splice(idx)`;
/// both arms share the gate-1+gate-2 composition
/// `resolve_unquote_in_params(inner, params, form)?` keyed on the
/// typed `form` projection.
/// * `substitute` top-level (substitute fallback path) — `,x` resolves
/// to its bound value, `,@x` rejects with
/// `LispError::SpliceOutsideList` (a splice form with no containing
/// list to flatten into).
/// * `substitute` list-inner (substitute fallback path's per-item
/// walk) — `,@x` items splice their bound list/nil/scalar value
/// into the assembled list builder via
/// [`crate::macro_expand::splice_value_into`]; non-splice items
/// recurse into `substitute`.
///
/// Pre-lift each site opened the same per-variant match arms —
/// `Sexp::Unquote(inner) => … UnquoteForm::Unquote …` and
/// `Sexp::UnquoteSplice(inner) => … UnquoteForm::Splice …` —
/// independently. The (Sexp variant, UnquoteForm variant) pairing was
/// load-bearing across distinct sites yet only enforced by callsite
/// discipline. Post-lift the pair binds at ONE projection function the
/// type system threads through `(UnquoteForm, &Sexp)`: a regression
/// that drifts ONE site's pairing (e.g. a future emitter that matches
/// `Sexp::Unquote(_)` but threads `UnquoteForm::Splice` into
/// `unquote_target_symbol` — type-checks but renders a misleading
/// diagnostic) becomes structurally impossible.
///
/// Soft face, like the rest of the `as_*` family on `Sexp`: it answers
/// "is this form an unquote-family marker, and what does it wrap?" and
/// yields `None` for everything that isn't (skip / fall through), with
/// no diagnostic. The strict siblings —
/// [`crate::macro_expand::splice_value_into`] for the bound-list
/// coercion, `non_symbol_unquote_target` /
/// `splice_outside_list` for the per-failure-mode rejections — keep
/// their loud-reject posture; this projection is the dispatch face the
/// soft pre-rejection walk binds to.
///
/// Structural identity binding it to the unquote-family variants:
/// * `as_unquote() == Some((UnquoteForm::Unquote, inner))` iff `self == Sexp::Unquote(inner)`
/// * `as_unquote() == Some((UnquoteForm::Splice, inner))` iff `self == Sexp::UnquoteSplice(inner)`
/// * `as_unquote().is_some() == matches!(self, Sexp::Unquote(_) | Sexp::UnquoteSplice(_))`
///
/// The returned `&Sexp` borrows the inner box's body verbatim — no
/// clone, no allocation — same lifetime as `&self`. The closed-set
/// guarantee on [`UnquoteForm`] (exactly `Unquote ⊎ Splice`) is
/// threaded through this projection's return tuple, so consumers that
/// pattern-match on `form: UnquoteForm` get rustc-enforced
/// exhaustiveness — a future `Sexp` variant must extend `UnquoteForm`
/// AND this match arm together (or stay outside the unquote family
/// and project to `None`), eliminating the silent two-site
/// extension-drift this lift was already designed to forbid.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// `(Sexp::Unquote, UnquoteForm::Unquote)` and
/// `(Sexp::UnquoteSplice, UnquoteForm::Splice)` pairings appear ≥3
/// times across `compile_node` (2 arms) + `substitute` (top-level +
/// list-inner) — past the PRIME-DIRECTIVE trigger once the structural
/// shape is named. THEORY.md §V.1 — knowable platform; the
/// unquote-family projection becomes a NAMED primitive on the
/// substrate's `Sexp` algebra rather than per-site `Sexp::Unquote(_)
/// | Sexp::UnquoteSplice(_)` inline matches paired with per-site
/// `UnquoteForm::Unquote` / `UnquoteForm::Splice` literals.
/// THEORY.md §II.1 invariant 1 — typed entry; the macro-template
/// substitution surface's typed-marker projection IS the rust-level
/// typed-entry gate's structural component, lifted from per-site
/// duplication onto ONE rust method the substrate's diagnostic
/// promotions hang off of. THEORY.md §II.1 invariant 2 — free middle;
/// both expansion strategies (bytecode `compile_node` and substitute
/// fallback `substitute`) route through the SAME projection, so a
/// regression that drifts ONE strategy's (Sexp variant, UnquoteForm
/// variant) pairing from the other cannot reach the substrate's
/// runtime — the type system binds both strategies to the
/// projection's single emission shape.
///
/// Frontier inspiration: Racket's `syntax-parse` `~or* (~unquote stx)
/// (~unquote-splice stx)` pattern — every macro-template pattern over
/// `,id` / `,@id` binds to ONE typed decomposition that surfaces the
/// marker identity alongside the inner expression; the substrate's
/// `as_unquote` is the Rust-typed peer of that pattern, lifted onto
/// the `Sexp` algebra with [`UnquoteForm`] standing in for Racket's
/// pattern-class identity. MLIR's typed-IR projection
/// `mlir::dyn_cast<UnquoteFamilyOp>(op)` — the typed downcast from a
/// polymorphic IR node onto a closed-set op family is the MLIR idiom;
/// `as_unquote` is the unstructured-projection peer on the substrate's
/// `Sexp` algebra, with `Option<(UnquoteForm, &Sexp)>` standing in for
/// MLIR's typed downcast result.
pub fn as_unquote(&self) -> Option<(UnquoteForm, &Sexp)> {
let (qf, inner) = self.as_quote_form()?;
qf.as_unquote_form().map(|uf| (uf, inner))
}
/// Soft projection onto the closed-set [`UnquoteForm`] template-
/// substitution carving marker — the 2-of-12 carving of the
/// [`SexpShape`](crate::error::SexpShape) algebra covering the two
/// homoiconic template-substitution wrappers ([`Self::Unquote`] and
/// [`Self::UnquoteSplice`]), which is itself a 2-of-4 subset of the
/// quote-family carving ([`QuoteForm`]). Returns
/// `Some(UnquoteForm::Unquote)` iff this is `,x` (a [`Self::Unquote`]
/// wrapper), `Some(UnquoteForm::Splice)` iff this is `,@x` (a
/// [`Self::UnquoteSplice`] wrapper), `None` for every other outer
/// shape ([`Self::Nil`], every [`Self::Atom`] variant, [`Self::List`],
/// and the two non-substitution quote-family wrappers [`Self::Quote`]
/// and [`Self::Quasiquote`]).
///
/// Direct value-level peer of the shape-level projection
/// [`SexpShape::as_unquote_form`](crate::error::SexpShape::as_unquote_form)
/// — the pair `(Sexp::as_unquote_form, SexpShape::as_unquote_form)`
/// binds the (Sexp value, UnquoteForm carving marker) pairing at ONE
/// typed method on each algebra, closing the unquote-subset cell of
/// the (Sexp value → carving marker) matrix. Marker-only sibling of
/// [`Self::as_unquote`] (which returns
/// `Option<(UnquoteForm, &Sexp)>` — marker + wrapped inner) and
/// direct 2-of-4 subset peer of [`Self::as_quote_form`] (which
/// covers the 4-of-12 quote-family carving with `Option<(QuoteForm,
/// &Sexp)>`). Post-lift the substrate's value-level marker-only
/// carving-marker matrix closes ONE more cell: the atomic axis via
/// [`Self::as_atom_kind`] (6-of-12), the residual axis via
/// [`Self::as_structural_kind`] (2-of-12), the quote-family axis via
/// `Self::as_quote_form().map(|(qf, _)| qf)` (4-of-12, marker + inner
/// available via the pre-existing method), and now the unquote-
/// subset axis via `Self::as_unquote_form` (2-of-12, marker only) —
/// symmetric with the shape-level marker-only projection family on
/// [`SexpShape`](crate::error::SexpShape).
///
/// Composition laws (three-way agreement — bindings): for every
/// `s: &Sexp`,
/// `s.as_unquote_form() == s.as_unquote().map(|(uf, _)| uf) ==
/// s.shape().as_unquote_form() ==
/// s.as_quote_form().and_then(|(qf, _)| qf.as_unquote_form())`.
/// Pre-lift the unquote-subset carving marker at the value level
/// was reachable only via one of these three-step compositions —
/// either through the parent [`Self::as_unquote`] projection
/// (discarding the inner), through the shape algebra
/// (`shape().as_unquote_form()`), or through the parent quote-family
/// projection composed with the 2-of-4 subset gate
/// [`QuoteForm::as_unquote_form`]. Post-lift the projection lands at
/// ONE typed method on the value algebra, and all three compositions
/// are pinned as agreement laws (see
/// `sexp_as_unquote_form_agrees_with_as_unquote_map_marker_for_every_variant`,
/// `sexp_as_unquote_form_agrees_with_shape_as_unquote_form_for_every_variant`,
/// and
/// `sexp_as_unquote_form_agrees_with_as_quote_form_and_quote_form_as_unquote_form_for_every_variant`
/// in this module). A regression that drifts any of the four
/// projections from the others surfaces immediately.
///
/// Symmetric with [`Self::as_atom_kind`] and [`Self::as_structural_kind`]
/// on the marker-only shape (returns just the closed-set marker, no
/// inner-payload borrow) — where [`Self::as_quote_form`] and
/// [`Self::as_unquote`] surface both the marker AND the wrapped
/// inner `&Sexp` (because the four quote-family arms and the two
/// substitution arms structurally carry a boxed inner value),
/// `as_unquote_form` returns a marker-only projection: consumers that
/// need the wrapped inner reach the marker-plus-inner sibling
/// [`Self::as_unquote`], while consumers that only need the closed-
/// set carving-marker identity (typed-pattern matchers, diagnostic
/// filters, coverage sweeps, LSP/REPL structural-navigation gates)
/// reach this projection and never allocate the tuple.
///
/// Composes cleanly with [`UnquoteForm::marker`] to project the value-
/// level substitution carving membership onto its canonical marker
/// string (`,` / `,@`):
/// `s.as_unquote_form().map(UnquoteForm::marker)` — the marker-string
/// witness for the substitution subset, sibling to
/// `s.as_atom_kind().map(AtomKind::label)` on the atomic axis, both
/// routing through the closed-set marker enum's canonical-vocabulary
/// projection at ONE canonical site (`UnquoteForm::marker` —
/// itself composed through `QuoteForm::prefix`).
///
/// Structural identity (pinned as a truth-table by
/// `sexp_as_unquote_form_projects_each_variant_to_canonical_unquote_form`
/// and `sexp_as_unquote_form_rejects_non_unquote_subset_outer_shapes`):
/// * `as_unquote_form() == Some(UnquoteForm::Unquote)` iff `matches!(self, Sexp::Unquote(_))`
/// * `as_unquote_form() == Some(UnquoteForm::Splice)` iff `matches!(self, Sexp::UnquoteSplice(_))`
/// * `as_unquote_form() == None` iff `!matches!(self, Sexp::Unquote(_) | Sexp::UnquoteSplice(_))`
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the substitution-
/// subset carving marker at the value level becomes a NAMED
/// primitive on the substrate's `Sexp` algebra rather than a per-
/// site composition through either [`Self::as_unquote`] (discarding
/// its `&Sexp` inner) or [`Self::shape`] (walking through the full
/// 12-variant `SexpShape` closed set to arrive at the 2-of-12
/// carving marker) or the parent [`Self::as_quote_form`] combined
/// with [`QuoteForm::as_unquote_form`] (the 2-of-4 subset gate).
/// THEORY.md §II.1 invariant 2 — free middle; every consumer that
/// wants the substitution-subset carving identity without needing
/// the wrapped inner (a future `tatara-check` predicate
/// `(check-value-projects-to-unquote-subset …)` that filters
/// diagnostics keyed on the substitution-subset cohort; a future LSP
/// structural-navigation filter that keys on the substitution-subset
/// carving membership at the value level; a future
/// `TypedRewriter<TemplateOp>` sweep that walks `Sexp` values whose
/// substitution-arm identity is `Some(UnquoteForm::_)` regardless of
/// inner payload identity; a future REPL pretty-printer that chooses
/// rendering paths keyed on the value-level substitution carving
/// marker without needing the inner payload) binds to ONE typed
/// method on the value algebra. THEORY.md §VI.1 — generation over
/// composition; the (Sexp variant, UnquoteForm variant) pairing
/// binds at ONE inherent method on the algebra rather than at three
/// parallel compositions (`as_unquote().map(…)`, `shape()
/// .as_unquote_form()`, `as_quote_form().and_then(|(qf, _)|
/// qf.as_unquote_form())`), so a regression that drifts ONE
/// composition's pairing from the others cannot reach the substrate's
/// runtime — the type system binds all three compositions to the
/// projection's single emission shape.
///
/// Frontier inspiration: MLIR's `mlir::dyn_cast<UnquoteFamilyOp>(op)
/// .map(|op| op.marker())` — every typed rewriter that only needs
/// the op-family identity (without the op's operands) binds to the
/// typed-downcast projection composed with an operand-discarding
/// marker extract; `Sexp::as_unquote_form` is the marker-only peer
/// on the substrate's `Sexp` algebra, with `Option<UnquoteForm>`
/// standing in for MLIR's `Optional<OperationName>` marker-only
/// downcast result. Racket's `syntax-parse` `~or* (~unquote _)
/// (~unquote-splice _)` — every syntax-class pattern that keys on
/// the substitution-subset marker identity without binding the
/// inner form; `Sexp::as_unquote_form` is the Rust-typed peer that
/// surfaces the marker identity through a single primitive on the
/// syntax algebra.
#[must_use]
pub fn as_unquote_form(&self) -> Option<UnquoteForm> {
self.as_unquote().map(|(uf, _)| uf)
}
/// Decompose a quote-family form into its typed marker and inner
/// expression — `Some((QuoteForm::Quote, inner))` iff this is `'x`
/// (a [`Sexp::Quote`] wrapper), `Some((QuoteForm::Quasiquote, inner))`
/// iff this is `` `x `` (a [`Sexp::Quasiquote`] wrapper),
/// `Some((QuoteForm::Unquote, inner))` iff this is `,x` (a
/// [`Sexp::Unquote`] wrapper), `Some((QuoteForm::UnquoteSplice, inner))`
/// iff this is `,@x` (a [`Sexp::UnquoteSplice`] wrapper), `None` for
/// every other shape (Nil, Atom, List).
///
/// This is the *quote-family projection* — the typed-marker peer of
/// [`Sexp::as_unquote`] generalized across all four homoiconic
/// prefix-wrappers. Where [`Sexp::as_unquote`] keys the macro-template
/// SUBSTITUTION surface on the closed pair `{Unquote, Splice}` (the
/// two prefixes whose template-time semantic is substitution),
/// `as_quote_form` keys the WIRE-SHAPE surfaces (Display rendering,
/// Hash discrimination, canonical-form interop) on the closed superset
/// `{Quote, Quasiquote, Unquote, UnquoteSplice}` — all four prefixes
/// the reader can tokenize and the writer must round-trip. The
/// `Sexp::as_unquote` projection now derives structurally from
/// `as_quote_form`'s output via [`QuoteForm::as_unquote_form`] — the
/// 2-of-4 subset gate — so the two projections share a SINGLE
/// implementation site on the `Sexp` algebra and the
/// (Sexp variant, QuoteForm variant) pairing binds at ONE rust
/// function regardless of whether the consumer wants the substitution
/// subset or the wire-shape superset.
///
/// Three consumers in this file route through this primitive:
/// * `Hash for Sexp` — the four `Quote`/`Quasiquote`/`Unquote`/
/// `UnquoteSplice` arms (pre-lift each carrying its own
/// `<discr>.hash(h); inner.hash(h)` body) collapse to ONE arm
/// that routes through `as_quote_form` and reads the
/// discriminator via [`QuoteForm::hash_discriminator`].
/// * `Display for Sexp` — the four `write!(f, "<prefix>{inner}")`
/// arms (pre-lift each carrying its own literal prefix string)
/// collapse to ONE arm that routes through `as_quote_form` and
/// reads the prefix via [`QuoteForm::prefix`].
/// * [`Sexp::as_unquote`] — derives `Option<(UnquoteForm, &Sexp)>`
/// by composing `as_quote_form` with [`QuoteForm::as_unquote_form`]
/// (the 2-of-4 subset projection), so the macro-template
/// substitution surface inherits the (Sexp variant, marker)
/// pairing through this projection's typed dispatch rather than
/// re-deriving its own arm-based match.
///
/// The closed-set guarantee on [`QuoteForm`] (exactly
/// `Quote ⊎ Quasiquote ⊎ Unquote ⊎ UnquoteSplice`) is threaded through
/// this projection's return tuple, so consumers that pattern-match on
/// `form: QuoteForm` get rustc-enforced exhaustiveness — a future
/// `Sexp` wrapper variant must extend `QuoteForm` AND this match arm
/// together (or stay outside the quote family and project to `None`),
/// eliminating the silent multi-site extension-drift this lift was
/// designed to forbid.
///
/// Soft face, like the rest of the `as_*` family on `Sexp`: it
/// answers "is this form a quote-family marker, and what does it
/// wrap?" and yields `None` for everything that isn't (skip / fall
/// through), with no diagnostic.
///
/// Structural identity binding it to the quote-family variants and
/// its `as_unquote` subset sibling:
/// * `as_quote_form() == Some((QuoteForm::Quote, inner))` iff `self == Sexp::Quote(inner)`
/// * `as_quote_form() == Some((QuoteForm::Quasiquote, inner))` iff `self == Sexp::Quasiquote(inner)`
/// * `as_quote_form() == Some((QuoteForm::Unquote, inner))` iff `self == Sexp::Unquote(inner)`
/// * `as_quote_form() == Some((QuoteForm::UnquoteSplice, inner))` iff `self == Sexp::UnquoteSplice(inner)`
/// * `as_quote_form().is_some() == matches!(self, Sexp::Quote(_) | Sexp::Quasiquote(_) | Sexp::Unquote(_) | Sexp::UnquoteSplice(_))`
/// * `as_unquote() == as_quote_form().and_then(|(qf, inner)| qf.as_unquote_form().map(|uf| (uf, inner)))`
///
/// The returned `&Sexp` borrows the inner box's body verbatim — no
/// clone, no allocation — same lifetime as `&self` and same posture
/// as [`Sexp::as_unquote`]'s tail.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// quote-family (Sexp variant, prefix string, hash discriminator)
/// triple appeared inline at three sites (`Hash for Sexp`,
/// `Display for Sexp`, `as_unquote`) — well past the ≥2 PRIME-DIRECTIVE
/// trigger once the structural shape is named. THEORY.md §V.1 —
/// knowable platform; the quote-family typed-marker projection becomes
/// a NAMED primitive on the substrate's `Sexp` algebra rather than
/// per-site inline matches paired with per-site discriminator literals
/// and prefix literals. THEORY.md §II.1 invariant 1 — typed entry; the
/// reader's prefix-to-variant dispatch ([`crate::reader::read_quoted`])
/// AND the Display impl's variant-to-prefix dispatch are dual
/// typed-entry / typed-exit gates over the same closed set; the
/// `QuoteForm` algebra threads BOTH gates through ONE typed enum so a
/// regression that drifts one side's prefix from the other (e.g. the
/// reader gains a fifth prefix but the Display impl doesn't) is no
/// longer a silent two-site divergence — rustc binds both sides to
/// the same closed-set enum. THEORY.md §II.1 invariant 2 — free
/// middle; the three consumers (Hash, Display, `as_unquote`) route
/// through the SAME projection, so a regression that drifts ONE
/// consumer's (Sexp variant, marker) pairing from the others cannot
/// reach the substrate's runtime.
///
/// Frontier inspiration: Racket's `syntax-parse` `~or* (~quote stx)
/// (~quasiquote stx) (~unquote stx) (~unquote-splice stx)` pattern —
/// every macro-template pattern over `'`/`` ` ``/`,`/`,@` binds to
/// ONE typed decomposition that surfaces the marker identity
/// alongside the inner expression; the substrate's `as_quote_form` is
/// the Rust-typed peer of that pattern, lifted onto the `Sexp`
/// algebra with `QuoteForm` standing in for Racket's pattern-class
/// identity at the homoiconic prefix surface. MLIR's typed-IR
/// projection `mlir::dyn_cast<QuoteFamilyOp>(op)` — the typed downcast
/// from a polymorphic IR node onto a closed-set op family is the MLIR
/// idiom; `as_quote_form` is the unstructured-projection peer on the
/// substrate's `Sexp` algebra, with `Option<(QuoteForm, &Sexp)>`
/// standing in for MLIR's typed downcast result.
pub fn as_quote_form(&self) -> Option<(QuoteForm, &Sexp)> {
match self {
Self::Quote(inner) => Some((QuoteForm::Quote, inner)),
Self::Quasiquote(inner) => Some((QuoteForm::Quasiquote, inner)),
Self::Unquote(inner) => Some((QuoteForm::Unquote, inner)),
Self::UnquoteSplice(inner) => Some((QuoteForm::UnquoteSplice, inner)),
_ => None,
}
}
/// Soft projection onto the closed-set [`QuoteForm`] quote-family
/// carving marker — the 4-of-12 carving of the [`SexpShape`] algebra
/// covering the four homoiconic prefix-wrappers ([`Self::Quote`],
/// [`Self::Quasiquote`], [`Self::Unquote`], [`Self::UnquoteSplice`]).
/// Returns `Some(QuoteForm::Quote)` iff this is `'x` (a
/// [`Self::Quote`] wrapper), `Some(QuoteForm::Quasiquote)` iff this
/// is `` `x `` (a [`Self::Quasiquote`] wrapper),
/// `Some(QuoteForm::Unquote)` iff this is `,x` (a [`Self::Unquote`]
/// wrapper), `Some(QuoteForm::UnquoteSplice)` iff this is `,@x` (a
/// [`Self::UnquoteSplice`] wrapper), `None` for every other outer
/// shape ([`Self::Nil`], every [`Self::Atom`] variant, [`Self::List`]).
///
/// Direct value-level peer of the shape-level projection
/// [`SexpShape::as_quote_form`](crate::error::SexpShape::as_quote_form)
/// — the pair `(Sexp::as_quote_form_marker, SexpShape::as_quote_form)`
/// binds the (Sexp value, QuoteForm carving marker) pairing at ONE
/// typed method on each algebra, closing the quote-family cell of
/// the (Sexp value → carving marker) matrix at the marker-only
/// value-level projection surface. Marker-only sibling of
/// [`Self::as_quote_form`] (which returns `Option<(QuoteForm, &Sexp)>`
/// — marker + wrapped inner). Post-lift the substrate's value-level
/// marker-only carving-marker matrix closes its FINAL cell: the
/// atomic axis via [`Self::as_atom_kind`] (6-of-12), the residual
/// axis via [`Self::as_structural_kind`] (2-of-12), the unquote-
/// subset axis via [`Self::as_unquote_form`] (2-of-12), and NOW the
/// quote-family axis via `Self::as_quote_form_marker` (4-of-12) —
/// symmetric with the shape-level marker-only projection family on
/// [`SexpShape`](crate::error::SexpShape).
///
/// Composition laws (two-way agreement — bindings): for every
/// `s: &Sexp`,
/// `s.as_quote_form_marker() == s.as_quote_form().map(|(qf, _)| qf)
/// == s.shape().as_quote_form()`. Pre-lift the quote-family carving
/// marker at the value level was reachable only via one of these
/// two-step compositions — either through the parent
/// [`Self::as_quote_form`] projection (discarding the wrapped inner
/// via `.map(|(qf, _)| qf)`) or through the shape algebra
/// (`s.shape().as_quote_form()`, walking the full 12-variant
/// [`SexpShape`](crate::error::SexpShape) closed set to arrive at
/// the 4-of-12 carving marker). Post-lift the projection lands at
/// ONE typed method on the value algebra, and both compositions
/// are pinned as agreement laws (see
/// `sexp_as_quote_form_marker_agrees_with_as_quote_form_map_marker_for_every_variant`
/// and
/// `sexp_as_quote_form_marker_agrees_with_shape_as_quote_form_for_every_variant`
/// in this module).
///
/// Superset-gate contract with [`Self::as_unquote_form`]: for every
/// `s: &Sexp`, `s.as_unquote_form().is_some()` implies
/// `s.as_quote_form_marker().is_some()` (the 2-of-12 substitution
/// subset is a proper subset of the 4-of-12 quote family). The two
/// non-substitution quote-family wrappers ([`Self::Quote`] and
/// [`Self::Quasiquote`]) satisfy `as_quote_form_marker().is_some()`
/// AND `as_unquote_form().is_none()` — the value-level image of the
/// 2-of-4 subset gate [`QuoteForm::as_unquote_form`]. Pinned by
/// `sexp_as_quote_form_marker_extends_as_unquote_form_to_full_quote_family`.
///
/// Structural identity binding it to the quote-family variants:
/// * `as_quote_form_marker() == Some(QuoteForm::Quote)` iff `matches!(self, Sexp::Quote(_))`
/// * `as_quote_form_marker() == Some(QuoteForm::Quasiquote)` iff `matches!(self, Sexp::Quasiquote(_))`
/// * `as_quote_form_marker() == Some(QuoteForm::Unquote)` iff `matches!(self, Sexp::Unquote(_))`
/// * `as_quote_form_marker() == Some(QuoteForm::UnquoteSplice)` iff `matches!(self, Sexp::UnquoteSplice(_))`
/// * `as_quote_form_marker() == None` iff `!matches!(self, Sexp::Quote(_) | Sexp::Quasiquote(_) | Sexp::Unquote(_) | Sexp::UnquoteSplice(_))`
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the quote-
/// family carving marker at the value level becomes a NAMED
/// primitive on the substrate's `Sexp` algebra rather than a per-
/// site two-step composition through either [`Self::as_quote_form`]
/// (discarding its `&Sexp` inner) or [`Self::shape`] (walking through
/// the full 12-variant [`SexpShape`](crate::error::SexpShape) closed
/// set to arrive at the 4-of-12 carving marker). THEORY.md §II.1
/// invariant 2 — free middle; every consumer that wants the quote-
/// family carving identity without needing the wrapped inner (a
/// future `tatara-check` predicate `(check-value-projects-to-quote-
/// family …)` that filters diagnostics keyed on the quote-family
/// cohort; a future LSP structural-navigation filter that keys on
/// the quote-family carving membership at the value level; a
/// future `TypedRewriter<QuoteFamilyOp>` sweep that walks `Sexp`
/// values whose quote-family arm identity is `Some(QuoteForm::_)`
/// regardless of inner payload identity; a future REPL pretty-
/// printer that chooses rendering paths keyed on the value-level
/// quote-family carving marker without needing the inner payload)
/// routes through ONE typed method rather than reaching into one of
/// the two composition sites, and both compositions are pinned as
/// agreement laws so a regression that drifts ONE composition's
/// pairing from the other cannot reach the substrate's runtime.
/// THEORY.md §VI.1 — generation over composition; the (Sexp variant,
/// QuoteForm variant) pairing binds at ONE inherent method on the
/// algebra rather than at two parallel compositions, so a future
/// extension (e.g. a fifth `Sexp` quote-family wrapper) lands at
/// ONE match arm in the parent `as_quote_form` projection and
/// inherits through this method's structural composition.
///
/// Frontier inspiration: MLIR's `mlir::dyn_cast<QuoteFamilyOp>(op)
/// .map(|op| op.marker())` — every typed rewriter that only needs
/// the op-family identity (without the op's operands) binds to the
/// typed-downcast projection composed with an operand-discarding
/// marker extract; `Sexp::as_quote_form_marker` is the marker-only
/// peer on the substrate's `Sexp` algebra, with
/// `Option<QuoteForm>` standing in for MLIR's
/// `Optional<OperationName>` marker-only downcast result. Racket's
/// `syntax-parse` `~or* (~quote _) (~quasiquote _) (~unquote _)
/// (~unquote-splice _)` — every syntax-class pattern that keys on
/// the quote-family marker identity without binding the inner form;
/// `Sexp::as_quote_form_marker` is the Rust-typed peer that
/// surfaces the marker identity through a single primitive on the
/// syntax algebra.
#[must_use]
pub fn as_quote_form_marker(&self) -> Option<QuoteForm> {
self.as_quote_form().map(|(qf, _)| qf)
}
/// Quote-family projection, asserted-total face of [`Sexp::as_quote_form`].
/// Returns `(QuoteForm, &Sexp)` verbatim — same borrowed-inner posture,
/// same closed-set marker — but panics with [`QUOTE_FAMILY_PROJECTION_INVARIANT`]
/// instead of yielding `None` for non-quote-family variants. Use AFTER
/// an outer pattern match has narrowed the discriminant union to the
/// quote family (`Sexp::Quote(_) | Sexp::Quasiquote(_) | Sexp::Unquote(_) |
/// Sexp::UnquoteSplice(_)`); the panic message states the invariant the
/// caller's outer pattern already proves.
///
/// Pre-lift the five production-site quote-family-arm consumers —
/// `Hash for Sexp::hash_discriminator`, `Display for Sexp::prefix`,
/// `domain::sexp_shape`, `domain::sexp_to_json`, `interop::iac_forge_tag` —
/// each carried a verbatim copy of the 4-arm wildcard pattern AND a
/// verbatim copy of the inline
/// `.as_quote_form().expect("matched quote-family variant must project
/// to Some via as_quote_form")` re-projection. The `(pattern, expect
/// message)` pair appeared bit-for-bit at FIVE sites. Post-lift the
/// expect message lives at ONE named const and the projection-with-
/// assertion lives at ONE primitive on the `Sexp` algebra; the five
/// callsites collapse to ONE typed query each. A future quote-family
/// extension that drifts ONE site's panic text from the others becomes
/// structurally impossible (one const, one method); a future site that
/// needs the same "outer-narrowed, total projection" shape lands on
/// this primitive directly without re-deriving the expect literal.
///
/// `#[track_caller]` ensures a panic surfaces the consumer's source
/// position, not this projection's — so the diagnostic stays
/// load-bearing under the lift.
///
/// Sibling posture to the `expect_*` family of typed-projection
/// asserted-total faces across the substrate's closed-set algebras
/// (`Option::expect`, `Result::expect`) — the assertion is the same
/// shape, the message is named on the algebra it asserts about.
///
/// # Panics
///
/// Panics with [`QUOTE_FAMILY_PROJECTION_INVARIANT`] if `self` is not
/// a quote-family variant. The outer pattern match at every caller
/// site is the proof of the invariant; the panic is the static
/// fall-through for a regression that drifts that proof.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// (4-arm wildcard pattern, expect re-projection) pair appeared bit-
/// for-bit at five production sites — well past the ≥2 PRIME-DIRECTIVE
/// trigger. THEORY.md §V.1 — knowable platform; the panic message and
/// the projection-with-assertion are now ONE named primitive on the
/// substrate's `Sexp` algebra, structurally binding the invariant
/// across every consumer that asserts an outer narrowing.
#[must_use]
#[track_caller]
pub fn expect_quote_form(&self) -> (QuoteForm, &Sexp) {
self.as_quote_form()
.expect(QUOTE_FAMILY_PROJECTION_INVARIANT)
}
/// Stable, per-outer-variant byte discriminator for the substrate's
/// [`Hash for Sexp`] cache-key projection — `0` for [`Self::Nil`],
/// `1` for [`Self::Atom`], `2` for [`Self::List`], `3` for
/// [`Self::Quote`], `4` for [`Self::Quasiquote`], `5` for
/// [`Self::Unquote`], `6` for [`Self::UnquoteSplice`]. Composes
/// through [`Self::shape`] into
/// [`crate::error::SexpShape::hash_discriminator`], which in turn
/// composes through the three closed-set sub-carvings' discriminator
/// methods: [`crate::error::StructuralKind::hash_discriminator`] for
/// the two structural-residual arms `{0, 2}`,
/// [`crate::error::QuoteForm::hash_discriminator`] for the four
/// quote-family arms `{3..=6}`, and the outer atomic marker byte
/// `1u8` for the six atomic-payload arms (whose inner
/// [`crate::ast::AtomKind::hash_discriminator`] `{0..=5}` partition
/// nests inside [`Hash for Atom`] rather than surfacing here). The
/// outer-`Sexp` cache-key algebra now closes at FIVE typed layers
/// (outer `Sexp` → [`crate::error::SexpShape`] → three sub-carvings)
/// with rustc-enforced consistency across each.
///
/// The byte values are load-bearing because the macro-expansion cache
/// ([`crate::macro_expand::Expander`]'s cache) keys on the hash of
/// `(macro_name, args)` — changing a discriminator silently
/// invalidates every cached expansion across the substrate.
///
/// The seven outer-variant arms partition `{0, 1, 2, 3, 4, 5, 6}`
/// injectively — closed-set-typed intra-Sexp injectivity that
/// composes through the intermediate
/// [`crate::error::SexpShape::hash_discriminator`] shape-level
/// projection (12 arms → 7 bytes; the six atomic-shape arms
/// collapse to the outer Atom marker byte `1u8`; the two
/// structural-residual arms surface `{0, 2}`; the four quote-family
/// arms surface `{3..=6}`). Together the four sub-algebras (this
/// outer method + shape + three sub-carvings) jointly cover the
/// entire outer-Sexp discriminator space through ONE typed method
/// per algebra layer. A future eighth `Sexp` variant (e.g. a
/// hypothetical `Vector` for `#(...)` reader syntax, `Map` for
/// `{...}`, or `Char` for `#\x`) picks a fresh cache-key byte
/// outside `{0..=6}` (e.g. `7u8`), extends the closed-set
/// [`crate::error::SexpShape`] enum + its
/// `hash_discriminator` (plus either [`crate::error::StructuralKind`]
/// or a fresh sub-algebra) in lockstep — rustc binds the
/// consistency through exhaustiveness over each closed enum.
///
/// Pre-lift this outer method dispatched over the seven `Sexp`
/// variants directly and routed the three structural + four
/// quote-family arms into the two sub-carvings' discriminator
/// methods with the Atom arm inline at `1u8` — the intermediate
/// [`crate::error::SexpShape`] shape-level projection did not
/// exist, so a consumer with a typed [`crate::error::SexpShape`]
/// identity in hand had to re-embed into a `Sexp` value to reach
/// the outer cache-key byte. Post-lift the outer method routes
/// through [`Self::shape`] into
/// [`crate::error::SexpShape::hash_discriminator`]; the shape-level
/// projection is the missing algebra layer between the outer `Sexp`
/// and the three sub-carvings, and consumers with a typed shape
/// identity now reach the outer cache-key byte at ONE typed method
/// per algebra layer without a re-embed.
///
/// `pub(crate)` because the byte-discriminator surface is an
/// implementation detail of the substrate's `Hash for Sexp` cache-
/// key contract; exposing it publicly would leak the cache-key shape
/// through the API without enabling any external consumer the public
/// projections ([`Self::as_atom`], [`Self::as_list`],
/// [`Self::as_quote_form`]) don't already serve. Same posture as
/// [`crate::error::SexpShape::hash_discriminator`],
/// [`crate::ast::AtomKind::hash_discriminator`],
/// [`crate::error::QuoteForm::hash_discriminator`], and
/// [`crate::error::StructuralKind::hash_discriminator`].
#[must_use]
pub(crate) fn hash_discriminator(&self) -> u8 {
self.shape().hash_discriminator()
}
/// Cross-crate canonical iac-forge tag for the outer [`Sexp`] value —
/// the OUTER-VALUE peer of the shape-level [`crate::error::SexpShape
/// ::iac_forge_tag`] one algebra layer down. `Some(&'static str)` for
/// the four homoiconic prefix-wrapper arms — `Self::Quote →
/// Some("quote")`, `Self::Quasiquote → Some("quasiquote")`,
/// `Self::Unquote → Some("unquote")`, `Self::UnquoteSplice →
/// Some("unquote-splicing")` — and `None` for the outer atomic-payload
/// arm ([`Self::Atom`]) AND the two structural-residual arms
/// ([`Self::Nil`], [`Self::List`]). The 4-of-7 partial projection on
/// the outer-`Sexp` algebra surfaces
/// [`crate::ast::QuoteForm::iac_forge_tag`]'s cross-crate canonical-
/// form tag surface at the outermost value-carrier algebra level,
/// composed through the pre-existing [`Self::shape`] projection and
/// [`crate::error::SexpShape::iac_forge_tag`]'s shape-level partial
/// projection.
///
/// Composition law: `sexp.iac_forge_tag() ==
/// sexp.shape().iac_forge_tag()` for every `sexp: &Sexp` — the outer-
/// `Sexp` cross-crate canonical-form tag surface routes through
/// [`Self::shape`] into the shape-level partial projection, which in
/// turn composes through [`crate::error::SexpShape::as_quote_form`]
/// with [`crate::ast::QuoteForm::iac_forge_tag`]'s canonical 4-of-4
/// closed-set tag projection. Post-lift the outer-`Sexp` cross-crate
/// canonical-form tag surface closes at FOUR typed layers: outer
/// [`Self::iac_forge_tag`] (7-arm outer dispatch on the outer
/// [`Sexp`] algebra, this method) → shape-level
/// [`crate::error::SexpShape::iac_forge_tag`] (12-arm shape-level
/// dispatch on the [`crate::error::SexpShape`] algebra) →
/// quote-family carving [`crate::error::SexpShape::as_quote_form`]
/// (4-of-12 quote-family sub-carving) → sub-carving tag
/// [`crate::ast::QuoteForm::iac_forge_tag`] (4-arm quote-family
/// sub-carving's canonical-form tag projection).
///
/// Pre-lift a consumer with a typed [`Sexp`] value in hand (a
/// generation-side canonical-form emitter, a downstream iac-forge
/// attestation site, an LSP / REPL / audit-trail metric keyed on the
/// observed outer value) wanting the cross-crate iac-forge canonical
/// tag string had to spell the two-step composition
/// `sexp.shape().iac_forge_tag()` at every callsite, or route through
/// [`Self::as_quote_form_marker`] composed with
/// [`crate::ast::QuoteForm::iac_forge_tag`] via `map` as the
/// `crate::interop` (removed) `From<&Sexp> for iac_forge::SExpr` impl does
/// for its four quote-family arms via [`Self::expect_quote_form`]
/// composed with [`crate::ast::QuoteForm::iac_forge_tag`]. Post-lift
/// the outer-`Sexp` canonical-form tag projection binds at ONE
/// typed-algebra method on the outer value-carrier — the SEVENTH
/// consumer of the outer-`Sexp` projection surface (sibling of
/// [`Self::shape`], [`Self::type_name`],
/// [`Self::hash_discriminator`], [`Self::as_atom`], [`Self::as_list`],
/// [`Self::as_quote_form`], [`Self::as_quote_form_marker`],
/// [`Self::as_unquote`], [`Self::as_unquote_form`]), matching the
/// same shape-composition posture [`Self::hash_discriminator`] takes
/// through the outer → shape one-step delegation.
///
/// The `Option<&'static str>` return shape mirrors
/// [`crate::error::SexpShape::iac_forge_tag`]'s partial-projection
/// shape one algebra level down — the outer-`Sexp` seven-arm closed
/// set's projection PARTIALIZES on the three non-quote-family shapes
/// (`Nil`, `Atom`, `List`) exactly as the shape-level twelve-arm
/// closed set's projection PARTIALIZES on the eight non-quote-family
/// shapes. The kernel's outer cardinality (three: `Nil` / `Atom` /
/// `List`) matches the shape-level kernel's cardinality (eight)
/// through [`Self::shape`]'s six-atomic-arms → outer `Atom` collapse
/// — the outer three-arm kernel `{Nil, Atom, List}` corresponds to
/// the shape-level eight-arm kernel `{Nil, Symbol, Keyword, String,
/// Int, Float, Bool, List}` under the outer → shape projection.
///
/// The `&'static str` lifetime is load-bearing: every iac-forge
/// consumer projects through this method into the canonical
/// 2-element-list head without an allocation, parallel to how
/// [`crate::ast::QuoteForm::iac_forge_tag`] on the sub-carving,
/// [`crate::error::SexpShape::iac_forge_tag`] on the shape-level
/// projection, and [`crate::error::UnquoteForm::iac_forge_tag`] on
/// the template-substitution subset project their respective closed
/// sets. A future eighth [`Sexp`] variant (e.g. a hypothetical
/// `Vector` for `#(...)` reader syntax, `Map` for `{...}`, `Char` for
/// `#\x`) extends [`crate::error::SexpShape`] (adding a `None`-arm
/// non-quote-family shape) — this method picks up the new arm's
/// `None` mechanically through the shape composition, with rustc's
/// exhaustiveness binding the extension end-to-end at
/// [`crate::error::SexpShape::as_quote_form`]'s closed match.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (outer
/// `Sexp` variant, canonical iac-forge tag) pairing becomes a TYPE
/// projection on the outermost value-carrier algebra rather than an
/// inline `.shape().iac_forge_tag()` two-step at every consumer. A
/// typo or swap at the projection site is no longer a runtime tag
/// drift but a compile error against the typed composition — the
/// `Sexp` ↔ `SexpShape` ↔ `QuoteForm` ↔ tag string chain is rustc-
/// enforced end-to-end. THEORY.md §II.1 invariant 2 — free middle;
/// the (outer value, canonical iac-forge tag) pairing now binds at
/// ONE site on the outer-`Sexp` algebra, composing through the pre-
/// existing shape-level partial projection rather than duplicating
/// the four-arm match here. THEORY.md §VI.1 — generation over
/// composition; the outer-`Sexp` cross-crate canonical-form tag
/// surface closes at FOUR typed layers (outer → shape → carving →
/// sub-carving-tag), each keyed on the SAME canonical-form tag
/// projection carried at the closed-set sub-carving level.
///
/// Frontier inspiration: MLIR's `mlir::Operation::getName()` typed
/// projection composed with `mlir::OperationName::getStringRef()` —
/// narrowing an operation-carrier value through its typed op-name
/// identity yields the canonical cross-boundary string identity in
/// ONE typed composition. [`Self::iac_forge_tag`] is the Rust-typed
/// peer where the "project to shape" step ([`Self::shape`]) composes
/// with the "read the shape's canonical tag" step
/// ([`crate::error::SexpShape::iac_forge_tag`]) into ONE outer-value
/// projection.
#[must_use]
pub fn iac_forge_tag(&self) -> Option<&'static str> {
self.shape().iac_forge_tag()
}
/// Canonical reader-punctuation prefix for the outer [`Sexp`] value —
/// the OUTER-VALUE peer of the shape-level
/// [`crate::error::SexpShape::prefix`] one algebra layer down.
/// `Some(&'static str)` for the four homoiconic prefix-wrapper arms —
/// `Self::Quote → Some("'")`, `Self::Quasiquote → Some("`")`,
/// `Self::Unquote → Some(",")`, `Self::UnquoteSplice → Some(",@")` —
/// and `None` for the outer atomic-payload arm ([`Self::Atom`]) AND
/// the two structural-residual arms ([`Self::Nil`], [`Self::List`]).
/// The 4-of-7 partial projection on the outer-`Sexp` algebra surfaces
/// [`crate::ast::QuoteForm::prefix`]'s reader-punctuation surface at
/// the outermost value-carrier algebra level, composed through the
/// pre-existing [`Self::shape`] projection and
/// [`crate::error::SexpShape::prefix`]'s shape-level partial
/// projection.
///
/// Composition law: `sexp.prefix() == sexp.shape().prefix()` for
/// every `sexp: &Sexp` — the outer-`Sexp` reader-punctuation surface
/// routes through [`Self::shape`] into the shape-level partial
/// projection, which in turn composes through
/// [`crate::error::SexpShape::as_quote_form`] with
/// [`crate::ast::QuoteForm::prefix`]'s canonical 4-of-4 closed-set
/// prefix projection. Post-lift the outer-`Sexp` reader-punctuation
/// surface closes at FOUR typed layers: outer [`Self::prefix`]
/// (7-arm outer dispatch on the outer [`Sexp`] algebra, this method)
/// → shape-level [`crate::error::SexpShape::prefix`] (12-arm shape-
/// level dispatch on the [`crate::error::SexpShape`] algebra) →
/// quote-family carving [`crate::error::SexpShape::as_quote_form`]
/// (4-of-12 quote-family sub-carving) → sub-carving prefix
/// [`crate::ast::QuoteForm::prefix`] (4-arm quote-family sub-
/// carving's canonical reader-punctuation projection).
///
/// Pre-lift a consumer with a typed [`Sexp`] value in hand (an
/// [`fmt::Display for Sexp`] impl that renders the four quote-family
/// arms as `<prefix><inner>`, an LSP hover / REPL completion that
/// echoes the source-punctuation prefix of a wrapper value, an
/// audit-trail metric keyed on the observed outer value) wanting
/// the canonical reader-punctuation prefix string had to spell the
/// two-step composition `sexp.shape().prefix()` at every callsite,
/// or route through [`Self::as_quote_form_marker`] composed with
/// [`crate::ast::QuoteForm::prefix`] via `map` as the
/// [`fmt::Display for Sexp`] impl does for its four quote-family
/// arms via [`Self::expect_quote_form`] composed with
/// [`crate::ast::QuoteForm::prefix`]. Post-lift the outer-`Sexp`
/// reader-punctuation projection binds at ONE typed-algebra method
/// on the outer value-carrier — the natural next rung on the
/// trajectory mirroring the [`Self::iac_forge_tag`] →
/// [`crate::error::SexpShape::iac_forge_tag`] ladder one vocabulary
/// axis over, matching the same shape-composition posture
/// [`Self::hash_discriminator`] and [`Self::iac_forge_tag`] take
/// through the outer → shape one-step delegation.
///
/// The `Option<&'static str>` return shape mirrors
/// [`crate::error::SexpShape::prefix`]'s partial-projection shape one
/// algebra level down — the outer-`Sexp` seven-arm closed set's
/// projection PARTIALIZES on the three non-quote-family shapes
/// (`Nil`, `Atom`, `List`) exactly as the shape-level twelve-arm
/// closed set's projection PARTIALIZES on the eight non-quote-family
/// shapes. The kernel's outer cardinality (three: `Nil` / `Atom` /
/// `List`) matches the shape-level kernel's cardinality (eight)
/// through [`Self::shape`]'s six-atomic-arms → outer `Atom` collapse
/// — the outer three-arm kernel `{Nil, Atom, List}` corresponds to
/// the shape-level eight-arm kernel `{Nil, Symbol, Keyword, String,
/// Int, Float, Bool, List}` under the outer → shape projection.
///
/// The reader-punctuation vocabulary this method projects (`"'"` /
/// `` "`" `` / `","` / `",@"`) is INTENTIONALLY DISJOINT from the
/// two sibling `&'static str` outer-value projection axes:
///
/// * [`Self::iac_forge_tag`] — cross-crate canonical form
/// (`"quote"` / `"quasiquote"` / `"unquote"` /
/// `"unquote-splicing"`), BLAKE3 attestation keys, render-cache
/// shape (load-bearing for byte-identical inter-crate compatibility
/// with the iac-forge ecosystem);
/// * [`Self::type_name`] — operator-facing diagnostic label
/// (`"nil"` / `"atom"` / `"list"` / `"quote"` / `"quasiquote"` /
/// `"unquote"` / `"unquote-splice"`) on the outer 7-arm surface,
/// [`crate::error::LispError::TypeMismatch`]'s `got` rendering,
/// REPL / LSP shape-of-witness surface.
///
/// This method projects the reader's SOURCE-TEXT vocabulary — the
/// four punctuation characters that appear literally in Lisp source
/// at each variant's homoiconic prefix. The three outer-value
/// closed-set projections key the SAME seven-arm outer algebra on
/// THREE distinct `&'static str` vocabularies (source-punctuation,
/// diagnostic-label, cross-crate canonical-form); consolidating any
/// two would silently break either the reader round-trip, the
/// operator-facing diagnostic surface, OR the iac-forge attestation
/// pipeline. The three vocabularies' distinctness is pinned bit-for-
/// bit through the composition law across the closed-set typed
/// algebra.
///
/// The `&'static str` lifetime is load-bearing: every reader / LSP
/// / REPL / [`fmt::Display for Sexp`] consumer projects through this
/// method into the canonical prefix character without an allocation,
/// parallel to how [`crate::ast::QuoteForm::prefix`] on the sub-
/// carving, [`crate::error::SexpShape::prefix`] on the shape-level
/// projection, [`Self::iac_forge_tag`] on the cross-crate canonical-
/// form axis, and [`crate::error::UnquoteForm::marker`] on the
/// template-marker axis project their respective closed sets. A
/// future eighth [`Sexp`] variant (e.g. a hypothetical `Vector` for
/// `#(...)` reader syntax, `Map` for `{...}`, `Char` for `#\x`)
/// extends [`crate::error::SexpShape`] (adding a `None`-arm non-
/// quote-family shape) — this method picks up the new arm's `None`
/// mechanically through the shape composition, with rustc's
/// exhaustiveness binding the extension end-to-end at
/// [`crate::error::SexpShape::as_quote_form`]'s closed match.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (outer
/// `Sexp` variant, reader-punctuation prefix) pairing becomes a
/// TYPE projection on the outermost value-carrier algebra rather
/// than an inline `.shape().prefix()` two-step at every consumer.
/// A typo or swap at the projection site is no longer a runtime
/// prefix drift but a compile error against the typed composition
/// — the `Sexp` ↔ `SexpShape` ↔ `QuoteForm` ↔ prefix character
/// chain is rustc-enforced end-to-end. THEORY.md §II.1 invariant 2
/// — free middle; the (outer value, reader-punctuation prefix)
/// pairing now binds at ONE site on the outer-`Sexp` algebra,
/// composing through the pre-existing shape-level partial
/// projection rather than duplicating the four-arm match here.
/// THEORY.md §VI.1 — generation over composition; the outer-`Sexp`
/// reader-punctuation surface closes at FOUR typed layers (outer
/// → shape → carving → sub-carving-prefix), each keyed on the SAME
/// reader-punctuation projection carried at the closed-set sub-
/// carving level.
///
/// Frontier inspiration: MLIR's `mlir::Operation::getName()` typed
/// projection composed with `mlir::OperationName::getStringRef()`
/// — narrowing an operation-carrier value through its typed op-name
/// identity yields the canonical cross-boundary string identity in
/// ONE typed composition. [`Self::prefix`] is the Rust-typed peer
/// where the "project to shape" step ([`Self::shape`]) composes
/// with the "read the shape's canonical reader-punctuation" step
/// ([`crate::error::SexpShape::prefix`]) into ONE outer-value
/// projection — sibling of [`Self::iac_forge_tag`] one vocabulary
/// axis over on the cross-crate canonical-form surface.
#[must_use]
pub fn prefix(&self) -> Option<&'static str> {
self.shape().prefix()
}
/// Total structural node count of the outer [`Sexp`] value — one
/// node per outer-algebra arm plus the recursive node count of
/// each child. [`Self::Nil`] and [`Self::Atom`] contribute one
/// node apiece (the outer arm itself); [`Self::List`] contributes
/// one node for the outer arm plus the summed node count of each
/// child element; the four homoiconic wrapper arms
/// ([`Self::Quote`], [`Self::Quasiquote`], [`Self::Unquote`],
/// [`Self::UnquoteSplice`]) each contribute one node for the
/// outer arm plus the node count of the wrapped inner form. The
/// projection is a structural size on the AST — every closed-set
/// arm counts as one, so the count is well-defined on ANY
/// [`Sexp`] value regardless of how it was constructed.
///
/// Load-bearing arithmetic identities:
/// * `Sexp::Nil.node_count() == 1`
/// * `Sexp::Atom(_).node_count() == 1`
/// * `Sexp::list(items).node_count() == 1 + sum(item.node_count())`
/// * `Sexp::quote(inner).node_count() == 1 + inner.node_count()`
/// * (peer identity for each other quote-family arm)
///
/// The identities compose: `node_count` is monotone in tree
/// growth (a strictly-larger tree — one containing more arms —
/// has a strictly-larger count), so a resource ceiling keyed on
/// `node_count` bounds the total AST arm-count reachable at that
/// ceiling. A future [`Self::UnquoteSplice`] wrapper appearing
/// inside a list contributes one node for the wrapper AND one
/// node for the outer list arm plus the node count of the
/// wrapper's inner form — the identity holds compositionally
/// through the wrapper's `Box<Sexp>` payload.
///
/// Consumers so far: [`crate::macro_expand::Expander`]'s
/// `max_expansion_size` ceiling — the RESOURCE-axis peer of the
/// `max_expansion_depth` (recursion length) and
/// `max_cache_entries` (memoization width) ceilings — projects
/// the freshly-applied macro expansion through `node_count` to
/// decide whether the result crosses the "expansion bomb"
/// threshold on the OUTPUT-SIZE axis. A `#[derive(TataraDomain)]`
/// consumer that wants to reject "this macro produced a giant
/// blob" at the expander boundary now inherits the projection
/// mechanically through the ceiling; no per-consumer walker
/// discipline required.
///
/// The `usize` return shape is the natural resource-count
/// carrier — sibling to `HashMap::len` (the cache-width ceiling
/// consumes) and to the `usize` depth counter (the recursion
/// ceiling consumes) — so all three ceilings compose against a
/// single arithmetic type without cross-cast overhead.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the
/// structural size of a value on the outer [`Sexp`] algebra
/// becomes a first-class TYPED projection rather than a
/// per-consumer hand-rolled walker. THEORY.md §VI.1 — generation
/// over composition; a future ceiling on a subtree count (e.g.
/// "reject any expansion whose LIST arms exceed N") emerges
/// naturally as a peer projection on the same closed-set
/// algebra, not as a separate walker.
#[must_use]
pub fn node_count(&self) -> usize {
match self {
Self::Nil | Self::Atom(_) => 1,
Self::List(items) => 1 + items.iter().map(Self::node_count).sum::<usize>(),
Self::Quote(inner)
| Self::Quasiquote(inner)
| Self::Unquote(inner)
| Self::UnquoteSplice(inner) => 1 + inner.node_count(),
}
}
}
/// Static panic message for [`Sexp::expect_quote_form`]'s asserted-total
/// face of the quote-family projection. Pre-lift this literal appeared
/// inline at five `.expect(...)` callsites (`Hash for Sexp`,
/// `Display for Sexp`, `domain::sexp_shape`, `domain::sexp_to_json`,
/// `interop::iac_forge_tag`); post-lift it lives at ONE named const so a
/// regression that drifts the diagnostic at one site silently from the
/// others becomes structurally impossible. Sibling to the per-projection
/// asserted-total faces across the substrate's typed algebras — the
/// message names the invariant the outer pattern proves, not the
/// substring grep'able by tests.
pub const QUOTE_FAMILY_PROJECTION_INVARIANT: &str =
"matched quote-family variant must project to Some via as_quote_form";
/// Closed-set typed identifier for the four homoiconic prefix-wrappers in
/// the substrate's `Sexp` algebra — `'x` ([`Sexp::Quote`]), `` `x ``
/// ([`Sexp::Quasiquote`]), `,x` ([`Sexp::Unquote`]), `,@x`
/// ([`Sexp::UnquoteSplice`]) — paired with the projections each consumer
/// surface needs ([`Self::prefix`] for [`crate::ast::Sexp`]'s `Display`
/// impl AND the reader's prefix dispatch dual, [`Self::hash_discriminator`]
/// for [`crate::ast::Sexp`]'s `Hash` impl, [`Self::as_unquote_form`] for
/// the 2-of-4 subset gate the template-substitution surface keys on).
///
/// Mirror at the homoiconic-prefix-wrapper boundary of the prior-run
/// `UnquoteForm` (template-marker subset, 2 variants),
/// `CompilerSpecIoStage` (disk-persistence surface),
/// `TemplateInvariantKind` (bytecode-runtime surface), `MacroDefHead`
/// (macro-definition-head closed set), and `KwargPath` (kwargs-path-shape
/// surface) closed-set lifts: those enums key their respective rejection
/// or projection variants on a typed identity carried inside the variant's
/// data shape; this enum keys the FOUR distinct quote-family rendering /
/// hashing / template-substitution sites on a typed marker identity.
/// Adding a fifth homoiconic prefix-wrapper (e.g., a hypothetical `,~`
/// reverse-unquote) requires extending this enum, which rustc-enforces
/// matching at every projection site (`prefix`, `hash_discriminator`,
/// `as_unquote_form`, plus `Sexp::as_quote_form`'s match arm) — the closed
/// set becomes a TYPE rather than four `&'static str` / `u8` literals that
/// could drift independently across `Sexp::Display`'s prefix arm and
/// `Sexp::Hash`'s discriminator arm and the reader's prefix dispatch.
///
/// Subset-gate relationship to [`UnquoteForm`]: the template-substitution
/// surface's [`Sexp::as_unquote`] is now `as_quote_form().and_then(|(qf,
/// inner)| qf.as_unquote_form().map(|uf| (uf, inner)))` — the 2-of-4
/// projection lives at ONE site on this algebra ([`Self::as_unquote_form`])
/// rather than being re-derived at every consumer that wants only the
/// `{Unquote, UnquoteSplice}` subset. A future enum variant that joins
/// the template-substitution subset (e.g. a typed `defalias`-projected
/// fifth marker) extends [`UnquoteForm`] AND
/// [`Self::as_unquote_form`]'s arm together, with rustc binding the
/// extension through the projection's `Option` return type.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// homoiconic-prefix-wrapper dispatch (the reader's prefix-to-variant
/// gate AND the Display impl's variant-to-prefix dual) IS the rust-level
/// typed-entry / typed-exit gate, and naming its closed-set identity
/// lifts the gate from per-site literal-pair discipline to ONE typed
/// enum the substrate's diagnostic promotions hang off of.
/// THEORY.md §V.1 — knowable platform; the closed set of homoiconic
/// prefix-wrappers becomes a TYPE rather than four `&'static str` / `u8`
/// literals scattered across Hash / Display / interop / sexp_shape — a
/// typo in any one site is no longer a runtime drift but a compile error
/// against the typed projection. THEORY.md §VI.1 — generation over
/// composition; the typed enum lands the structural-completeness floor
/// for the quote-family surface, parallel to how `UnquoteForm` lands it
/// for the template-marker subset and `MacroDefHead` for the
/// macro-definition-head surface.
#[derive(Debug, Clone, Copy, PartialEq, Eq, tatara_closed_set::DeriveClosedSet)]
#[closed_set(via = "prefix", display, generate_unknown = "quote form")]
pub enum QuoteForm {
/// `'x` — literal-quote prefix. The `'` marker; the inner expression
/// is NOT subject to macro substitution. Projects to NO
/// `UnquoteForm` (the template-substitution surface ignores quote).
Quote,
/// `` `x `` — quasi-quote prefix. The `` ` `` marker; the inner
/// expression is the template body inside which `,` and `,@` mark
/// substitution points. Projects to NO `UnquoteForm` (a quasi-quote
/// is the substitution SCOPE, not a substitution itself).
Quasiquote,
/// `,x` — single-value substitution. The `,` marker; the inner
/// symbol is substituted with its bound value at template
/// expansion. Projects to `UnquoteForm::Unquote` for the
/// template-substitution surface.
Unquote,
/// `,@x` — list-splice substitution. The `,@` marker; the inner
/// symbol must be bound to a list, whose elements are flattened
/// into the containing list at template expansion. Projects to
/// `UnquoteForm::Splice` for the template-substitution surface.
UnquoteSplice,
}
impl QuoteForm {
/// The closed set of four homoiconic prefix-wrappers — single
/// source of truth that drives every per-variant projection
/// ([`Self::prefix`] / [`fmt::Display`], [`Self::hash_discriminator`],
/// [`Self::as_unquote_form`], [`Self::iac_forge_tag`],
/// [`Self::sexp_shape`], [`Self::wrap`], and the [`Self::FromStr`]
/// decode sweep keyed on [`Self::prefix`]).
///
/// Adding a hypothetical fifth homoiconic prefix-wrapper (e.g.
/// a `,~` reverse-unquote, a `,?` conditional-unquote, or a
/// `#'` Common-Lisp function-quote literal) lands at one
/// [`Self::ALL`] entry plus one arm per projection — exhaustively
/// checked by the compiler (the `[Self; 4]` array literal forces
/// the arity) AND by the per-variant truth-table tests below.
///
/// Sibling closed-set lift to every other typed-shape enum the
/// substrate carries: this crate's own
/// [`crate::error::SexpShape::ALL`] (the twelve reachable outer
/// shapes — superset of this enum's four via [`Self::sexp_shape`]),
/// [`AtomKind::ALL`] (the six atomic-payload kinds — peer axis
/// on the same algebra, also a 6-of-12 carving of `SexpShape`),
/// [`crate::error::UnquoteForm::ALL`] (the two template-substitution
/// markers — proper 2-of-4 subset of THIS enum via
/// [`Self::as_unquote_form`]), and the cross-crate `tatara-process`
/// family (`ConditionKind::ALL`, `ProcessPhase::ALL`,
/// `ProcessSignal::ALL`, `ChannelKind::ALL`, `IntentKind::ALL`,
/// `LifetimeKind::ALL`, `RequestorKind::ALL`, `ReceiptKind::ALL`,
/// …) every one of which paired its typed projection with `ALL`
/// before this lift.
///
/// Future consumers that compose against `ALL`: LSP / REPL
/// completion for the operator-facing rendered homoiconic prefix
/// (every `'`/`` ` ``/`,`/`,@` substring an authoring tool would
/// surface in a completion list keys on this set's projection
/// through [`Self::prefix`]); `tatara-check` coverage assertions
/// over which quote-family wrappers reach a `Sexp::Display` /
/// `Hash for Sexp` / `as_unquote_form` consumer arm at all — the
/// typed sweep replaces a per-callsite vocabulary of four
/// `&'static str` / `u8` literals; any future audit-trail metric
/// jointly labeled by [`Self::prefix`] (e.g.
/// `tatara_lisp_quote_family_total{prefix="'"}`) — the metric
/// label set IS [`Self::ALL`] mapped through [`Self::prefix`];
/// any future structural rewriter (typed analogue of MLIR's
/// `op.walk<QuoteFormOp>()`) that wants to sweep over every
/// quote-family wrapper in a typed sequence.
pub const ALL: [Self; 4] = [
Self::Quote,
Self::Quasiquote,
Self::Unquote,
Self::UnquoteSplice,
];
/// Canonical `&'static str` reader-prefix of [`Self::Quote`] —
/// `"'"`. The ONE canonical bytes-payload on the closed-set
/// [`QuoteForm`] algebra shared by [`Self::prefix`]'s [`Self::Quote`]
/// arm AND the [`crate::ast::Sexp`] `Display` arm the arm feeds.
///
/// Sibling posture to the closed set of per-role `pub const`
/// bytes on the substrate's other closed-set outer algebras:
/// [`crate::error::MacroDefHead::DEFMACRO_KEYWORD`] /
/// [`crate::error::MacroDefHead::DEFPOINT_TEMPLATE_KEYWORD`] /
/// [`crate::error::MacroDefHead::DEFCHECK_KEYWORD`] (per-role
/// head-keyword algebra on the CL macro-definition surface),
/// [`crate::ast::Atom::TRUE_LITERAL`] /
/// [`crate::ast::Atom::FALSE_LITERAL`] (per-role Scheme-bool
/// spelling algebra on the atomic-payload surface),
/// [`crate::macro_expand::MacroParams::REST_MARKER`] /
/// [`crate::macro_expand::MacroParams::OPTIONAL_MARKER`] (per-role
/// CL lambda-list-keyword algebra on the macro-param surface).
///
/// The `char`-level peer of THIS `&'static str` constant is
/// [`Self::QUOTE_LEAD`] — the first (and only) char of this
/// prefix. The structural round-trip law between the two is
/// `Self::QUOTE_PREFIX.chars().next() == Some(Self::QUOTE_LEAD)`
/// AND `Self::QUOTE_PREFIX.len() ==
/// Self::QUOTE_LEAD.len_utf8()` — the ONE `char` byte
/// composes the ONE `&'static str` prefix. Pinned by
/// `quote_form_per_role_prefixes_route_through_matching_lead_char_for_single_char_prefixes`.
///
/// A regression that inlines the `"'"` literal at
/// [`Self::prefix`]'s [`Self::Quote`] arm and drifts the constant
/// silently (e.g. an ELisp-compat port of the quote prefix to
/// `#'`, a hypothetical Racket-compat swap to a distinct byte)
/// fails at the algebra's `prefix()` path-uniformity pin
/// (`quote_form_prefix_routes_through_typed_per_role_constants`)
/// rather than at silent reader-family drift where the
/// [`Sexp::Display`] round-trip breaks.
pub const QUOTE_PREFIX: &'static str = "'";
/// Canonical `&'static str` reader-prefix of [`Self::Quasiquote`]
/// — `` "`" ``. Sibling of [`Self::QUOTE_PREFIX`] on the closed-set
/// per-role quote-family prefix-bytes axis; see
/// [`Self::QUOTE_PREFIX`] for the algebra-level round-trip +
/// disjointness contracts every sibling shares. The `char`-level
/// peer is [`Self::QUASIQUOTE_LEAD`].
pub const QUASIQUOTE_PREFIX: &'static str = "`";
/// Canonical `&'static str` reader-prefix of [`Self::Unquote`] —
/// `","`. Sibling of [`Self::QUOTE_PREFIX`] on the closed-set
/// per-role quote-family prefix-bytes axis; see
/// [`Self::QUOTE_PREFIX`] for the algebra-level round-trip +
/// disjointness contracts every sibling shares. The `char`-level
/// peer is [`Self::UNQUOTE_LEAD`] (shared with
/// [`Self::UNQUOTE_SPLICE_PREFIX`]'s lead byte — see the
/// [`Self::UNQUOTE_LEAD`] docstring for the shared-lead-char
/// discipline the two prefixes disambiguate on).
pub const UNQUOTE_PREFIX: &'static str = ",";
/// Canonical `&'static str` reader-prefix of [`Self::UnquoteSplice`]
/// — `",@"`. The ONLY two-char prefix on the closed set; every
/// other [`Self::PREFIXES`] entry is a single `char` rendered as
/// `&'static str`. Sibling of [`Self::QUOTE_PREFIX`] on the closed-
/// set per-role quote-family prefix-bytes axis.
///
/// Structural composition law: `Self::UNQUOTE_SPLICE_PREFIX ==
/// format!("{}{}", Self::UNQUOTE_LEAD, Self::SPLICE_DISCRIMINATOR)`
/// — the two-char prefix decomposes cleanly into the ONE shared
/// lead byte [`Self::UNQUOTE_LEAD`] + the ONE splice-promotion
/// discriminator [`Self::SPLICE_DISCRIMINATOR`], both `char`-level
/// constants on this algebra. Pinned by
/// `quote_form_unquote_splice_prefix_constant_composes_from_unquote_lead_and_splice_discriminator`
/// (byte-level composition through the per-role `pub const`) as a
/// section-for-retraction peer of the pre-existing
/// `quote_form_unquote_splice_prefix_composes_from_unquote_lead_and_splice_discriminator`
/// pin (byte-level composition through the [`Self::prefix`]
/// method).
pub const UNQUOTE_SPLICE_PREFIX: &'static str = ",@";
/// The closed-set forced-arity ALL array over the quote-family
/// reader-prefix `&'static str` bytes in canonical declaration
/// order matching [`Self::ALL`] element-wise. Sibling posture to
/// [`crate::error::MacroDefHead::KEYWORDS`] (`[&'static str; 3]`
/// on the CL macro-definition head algebra),
/// [`crate::ast::Atom::BOOL_LITERALS`] (`[&'static str; 2]` on the
/// Scheme-bool spelling algebra), and
/// [`crate::macro_expand::MacroParams::LAMBDA_LIST_KEYWORDS`]
/// (`[&'static str; 2]` on the CL lambda-list-keyword algebra) —
/// every closed-set outer projection on the substrate now pins
/// its canonical bytes at ONE `pub const` per role plus an ALL
/// array for family-wide consumers.
///
/// Adding a hypothetical fifth homoiconic prefix (a `,~`
/// reverse-unquote, a `,?` conditional-unquote, a `#'` Common-
/// Lisp function-quote) extends [`Self::ALL`] AND
/// [`Self::PREFIXES`] AND [`Self::prefix`]'s arm AND one new
/// per-role `pub const` in lockstep — rustc's forced-arity check
/// on `[&'static str; N]` fails compilation if either ALL array
/// grows without the other.
///
/// Future consumers that compose against [`Self::PREFIXES`]:
/// - LSP / REPL completion for the operator-facing rendered
/// homoiconic prefix bar — the completion set IS
/// [`Self::PREFIXES`] rather than four hand-enumerated
/// `&'static str` literals per completion provider.
/// - `tatara-check` coverage assertions that sweep workspace
/// `.lisp` files for every canonical quote-family prefix — the
/// typed sweep replaces per-consumer inline enumeration of the
/// four literals.
/// - Any future audit-trail metric jointly labeled by
/// [`Self::prefix`] (e.g.
/// `tatara_lisp_quote_family_total{prefix="'"}`) — the metric
/// label set IS [`Self::PREFIXES`] mapped through
/// [`Self::prefix`].
pub const PREFIXES: [&'static str; 4] = [
Self::QUOTE_PREFIX,
Self::QUASIQUOTE_PREFIX,
Self::UNQUOTE_PREFIX,
Self::UNQUOTE_SPLICE_PREFIX,
];
/// Canonical `&'static str` prefix that paired with the variant
/// renders the homoiconic form — [`Self::QUOTE_PREFIX`] for
/// [`Self::Quote`], [`Self::QUASIQUOTE_PREFIX`] for
/// [`Self::Quasiquote`], [`Self::UNQUOTE_PREFIX`] for
/// [`Self::Unquote`], [`Self::UNQUOTE_SPLICE_PREFIX`] for
/// [`Self::UnquoteSplice`]. Threaded through
/// [`crate::ast::Sexp`]'s `Display` impl so the per-variant prefix
/// rendering lives at ONE site on this algebra rather than four
/// inline literal strings across the Display arms.
///
/// Post-lift the four arms route through the per-role `pub const`
/// bytes on the closed-set [`QuoteForm`] algebra rather than
/// inline `&'static str` literals — so a rename of ONE canonical
/// prefix bytes (an ELisp-compat port of `Quote` to `"#'"`, a
/// hypothetical Racket-compat swap of `Quasiquote`, a Common-Lisp-
/// standard rename of `UnquoteSplice` to `",."`) lands as ONE
/// edit to the matching `pub const` — every downstream consumer
/// that binds to the algebra ([`crate::ast::Sexp`]'s `Display`
/// impl, the reader's tokenizer round-trip law, the future
/// canonical-form taggers) inherits the rename mechanically.
///
/// Structural dual of the reader's [`crate::reader::read_quoted`]
/// dispatch: the reader maps prefix-tokens to `Sexp::{Quote,
/// Quasiquote, Unquote, UnquoteSplice}` constructors; this method
/// maps the typed `QuoteForm` marker back to its canonical prefix
/// string. Adding a fifth prefix extends both sides — the reader's
/// tokenizer + dispatch AND this method — with rustc enforcing
/// the pair through the closed-set enum. Round-trip:
/// `read(format!("{}{inner}", qf.prefix()))` produces the
/// `Sexp::*` variant matching `qf`, by construction.
///
/// The `&'static str` lifetime is load-bearing: it lets every
/// consumer (Display arm, future format strings, future interop
/// canonical-form taggers) project through this method without
/// an allocation, parallel to how [`UnquoteForm::marker`]
/// projects its 2-of-4 subset surface.
#[must_use]
pub fn prefix(self) -> &'static str {
match self {
Self::Quote => Self::QUOTE_PREFIX,
Self::Quasiquote => Self::QUASIQUOTE_PREFIX,
Self::Unquote => Self::UNQUOTE_PREFIX,
Self::UnquoteSplice => Self::UNQUOTE_SPLICE_PREFIX,
}
}
/// Canonical `'` LEAD `char` of [`Self::Quote`]'s [`Self::prefix`]
/// (`"'"`) — the ONE canonical `char` on the [`QuoteForm`] algebra the
/// substrate's Quote-family single-quote lead-byte disjointness
/// contract binds to.
///
/// Sibling posture to the closed set of `pub const` reader-punctuation
/// canonical `char` bytes on the substrate:
/// [`Self::SPLICE_DISCRIMINATOR`] (`'@'`),
/// [`crate::ast::Atom::STR_DELIMITER`] (`'"'`),
/// [`crate::ast::Atom::STR_ESCAPE_LEAD`] (`'\\'`),
/// [`crate::ast::Atom::KEYWORD_MARKER_LEAD`] (`':'`),
/// [`crate::ast::Atom::BOOL_LITERAL_LEAD`] (`'#'`),
/// [`crate::ast::Sexp::LIST_OPEN`] (`'('`),
/// [`crate::ast::Sexp::LIST_CLOSE`] (`')'`),
/// [`crate::ast::Sexp::COMMENT_LEAD`] (`';'`),
/// [`crate::ast::Sexp::COMMENT_TERM`] (`'\n'`) — every canonical per-
/// role byte the reader's tokenizer specialises on is a `pub const`
/// on its owning closed-set algebra. This constant closes the Quote-
/// family single-quote lead byte at the SAME algebra as the
/// [`Self::lead_char`] projection (whose [`Self::Quote`] arm returns
/// this byte) AND the [`Self::from_lead_char`] inverse (whose match
/// arm decodes this byte back to [`Self::Quote`]).
///
/// Structural round-trip contract:
/// `Self::from_lead_char(Self::QUOTE_LEAD) == Some(Self::Quote)`
/// AND `Self::Quote.lead_char() == Self::QUOTE_LEAD` — pinned by
/// `quote_form_lead_constants_round_trip_through_lead_char_projections`.
/// A regression that drifts EITHER the constant OR the paired
/// projection surfaces at the pin rather than at a silent tokenizer
/// drift where `'foo` classifies as a bare atom instead of
/// [`crate::ast::Sexp::Quote`].
///
/// Disjointness contract: `QUOTE_LEAD`'s byte MUST differ from
/// [`Self::QUASIQUOTE_LEAD`], [`Self::UNQUOTE_LEAD`],
/// [`Self::SPLICE_DISCRIMINATOR`],
/// [`crate::ast::Atom::STR_DELIMITER`],
/// [`crate::ast::Atom::STR_ESCAPE_LEAD`],
/// [`crate::ast::Atom::KEYWORD_MARKER_LEAD`],
/// [`crate::ast::Atom::BOOL_LITERAL_LEAD`],
/// [`crate::ast::Sexp::LIST_OPEN`], [`crate::ast::Sexp::LIST_CLOSE`],
/// [`crate::ast::Sexp::COMMENT_LEAD`], and
/// [`crate::ast::Sexp::COMMENT_TERM`] — every other closed-set outer-
/// marker byte the reader's tokenizer specialises on. A collision
/// would silently break the reader's outer dispatch. Pinned by
/// `quote_form_lead_constants_distinct_from_every_other_algebra_marker_char`.
///
/// Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the
/// (Quote-family single-quote lead byte, canonical `'\''`) pairing
/// binds at ONE constant on the closed-set [`QuoteForm`] algebra
/// regardless of which paired projection reaches in. THEORY.md §V.1
/// — knowable platform; the canonical Quote-family lead byte becomes
/// a TYPE-level constant on the substrate algebra rather than an
/// inline `'\''` char literal at [`Self::lead_char`]'s [`Self::Quote`]
/// arm AND at [`Self::from_lead_char`]'s decode arm.
pub const QUOTE_LEAD: char = '\'';
/// Canonical `` ` `` LEAD `char` of [`Self::Quasiquote`]'s
/// [`Self::prefix`] (`` "`" ``) — sibling of [`Self::QUOTE_LEAD`] on
/// the closed-set quote-family lead-byte axis. See
/// [`Self::QUOTE_LEAD`] for the algebra-level round-trip +
/// disjointness contracts every sibling shares. Bound by
/// [`Self::lead_char`]'s [`Self::Quasiquote`] arm AND
/// [`Self::from_lead_char`]'s decode arm.
pub const QUASIQUOTE_LEAD: char = '`';
/// Canonical `,` LEAD `char` SHARED by [`Self::Unquote`]'s
/// [`Self::prefix`] (`","`) AND [`Self::UnquoteSplice`]'s
/// [`Self::prefix`] (`",@"`) — the splice's two-char prefix opens
/// with this byte and disambiguates on the peek-then-consume
/// [`Self::SPLICE_DISCRIMINATOR`] second char inside
/// [`crate::reader::tokenize`]. Sibling of [`Self::QUOTE_LEAD`] on
/// the closed-set quote-family lead-byte axis; see
/// [`Self::QUOTE_LEAD`] for the algebra-level round-trip +
/// disjointness contracts every sibling shares. Bound by
/// [`Self::lead_char`]'s `Self::Unquote | Self::UnquoteSplice` merged
/// arm AND [`Self::from_lead_char`]'s decode arm.
///
/// Composition identity with [`Self::SPLICE_DISCRIMINATOR`]:
/// `format!("{}{}", Self::UNQUOTE_LEAD, Self::SPLICE_DISCRIMINATOR)
/// == Self::UnquoteSplice.prefix()` — the two byte-level constants
/// on the closed-set [`QuoteForm`] algebra compose the ONLY two-char
/// [`Self::prefix`] in the closed set. Pinned by
/// `quote_form_unquote_splice_prefix_composes_from_unquote_lead_and_splice_discriminator`.
/// A regression that renames EITHER constant without touching the
/// paired [`Self::UnquoteSplice`]'s [`Self::prefix`] arm surfaces
/// here rather than as a silent `,@` reader drift.
pub const UNQUOTE_LEAD: char = ',';
/// The closed-set forced-arity ALL array over the quote-family
/// DISTINCT reader-lead-byte `char`s in canonical declaration
/// order matching [`Self::ALL`]'s three-of-four distinct-lead-
/// byte projection through [`Self::lead_char`] — [`Self::QUOTE_LEAD`]
/// (`'\''` — the [`Self::Quote`] lead byte), [`Self::QUASIQUOTE_LEAD`]
/// (`` '`' `` — the [`Self::Quasiquote`] lead byte),
/// [`Self::UNQUOTE_LEAD`] (`','` — the SHARED lead byte of BOTH
/// [`Self::Unquote`] AND [`Self::UnquoteSplice`], with the splice
/// promotion living at the reader's peek-then-consume
/// [`Self::SPLICE_DISCRIMINATOR`] second-char arm rather than at a
/// distinct lead byte).
///
/// The `[char; 3]` cardinality (vs the peer [`Self::PREFIXES`]
/// `[&'static str; 4]`) IS the structural axis distinguishing the
/// DISTINCT-lead-byte sub-vocabulary from the PER-VARIANT-prefix
/// sub-vocabulary — three-of-four distinct-lead-byte collapse is
/// definitional (only [`Self::UnquoteSplice`]'s two-char `,@`
/// prefix shares its lead byte with a sibling variant; every other
/// variant owns its lead byte outright). The shape asymmetry
/// between the two ALL arrays encodes the shared-lead-byte
/// collapse identity on the closed-set [`QuoteForm`] algebra at
/// the type-system level: a consumer that reaches for
/// [`Self::LEADS`] reads the distinct-lead-byte cardinality
/// directly off the array's forced arity rather than through a
/// per-consumer `HashSet`-then-count over [`Self::PREFIXES`]'s
/// first chars.
///
/// Sibling posture to [`Self::PREFIXES`] (`[&'static str; 4]` on
/// the per-variant reader-prefix axis) AND [`Self::IAC_FORGE_TAGS`]
/// (`[&'static str; 4]` on the per-variant canonical-form tag
/// axis) — those two ALL arrays close the per-variant axes of the
/// outer-tokenizer `QuoteForm` closed set; this ALL array closes
/// the peer DISTINCT-lead-byte axis at the SHAPE-ASYMMETRIC
/// `[char; N]` cardinality. Also sibling-shape to
/// [`crate::ast::Sexp::LIST_DELIMITERS`] (`[char; 2]` on the outer-
/// structural paired-delimiter axis), [`Atom::SELF_ESCAPE_TABLE`]
/// (`[char; 2]` on the inner-Str-payload self-escape axis), and
/// [`Atom::BOOL_LITERALS`] (`[&'static str; 2]` on the Scheme-bool
/// spelling axis) — every closed-set outer projection on the
/// substrate now pins its canonical bytes at ONE `pub const` per
/// role plus an ALL array for family-wide consumers.
///
/// Adding a hypothetical fifth homoiconic prefix with a DISTINCT
/// lead byte (a `~` reverse-unquote, a `?` conditional-unquote, a
/// `#` reader-macro-lead) extends [`Self::ALL`] AND
/// [`Self::PREFIXES`] AND [`Self::LEADS`] AND [`Self::lead_char`]'s
/// arm AND [`Self::from_lead_char`]'s arm AND one new per-role
/// `pub const` in lockstep — rustc's forced-arity check on
/// `[char; N]` fails compilation if the LEADS array grows without
/// the paired algebra constant, and the paired PREFIXES /
/// IAC_FORGE_TAGS arrays extend by ONE row each in lockstep. A
/// fifth prefix that SHARES its lead byte with an existing variant
/// (like the splice's `,@` sharing with unquote's `,`) leaves
/// [`Self::LEADS`]'s cardinality unchanged — the DISTINCT-lead-
/// byte set is invariant under such an extension, closing the
/// splice-family promotion pattern at the ALL-array level.
///
/// Future consumers that compose against [`Self::LEADS`]:
/// - LSP / REPL completion for the operator-facing reader-entry
/// lead-byte set — the completion set IS [`Self::LEADS`] rather
/// than three hand-enumerated `char` literals per completion
/// provider.
/// - The reader's outer tokenizer pre-match check that gates the
/// quote-family dispatch — the check IS
/// `Self::LEADS.contains(&ch)` rather than three inline
/// `ch == Self::QUOTE_LEAD || ch == Self::QUASIQUOTE_LEAD ||
/// ch == Self::UNQUOTE_LEAD` disjuncts, and the sweep binds
/// through the ALL array's forced arity.
/// - A hypothetical `tatara_lisp_quote_family_lead_total{lead="'"}`
/// metric surface — the label-set generator sweeps
/// [`Self::LEADS`] verbatim rather than re-typing the three
/// distinct-lead bytes inline at each recorder.
/// - Any future syntax-highlighter / structural editor that needs
/// the reader-entry lead-byte set for classification — the
/// editor's per-char classifier binds through [`Self::LEADS`]
/// rather than three parallel `char`-literal patterns.
///
/// Theory anchor: THEORY.md §III — the typescape; the three
/// distinct quote-family reader-lead bytes now bind at ONE typed
/// `[char; 3]` array on the closed-set [`QuoteForm`] algebra
/// rather than as three inline algebra-constant enumerations at
/// every consumer that iterates the distinct-lead-byte sub-
/// vocabulary. THEORY.md §V.1 — knowable platform; the distinct-
/// lead-byte sub-vocabulary becomes load-bearing typed data on
/// the closed-set outer [`QuoteForm`] algebra. THEORY.md §VI.1 —
/// generation over composition; the shared-lead-byte collapse
/// identity (four variants → three distinct lead bytes)
/// composes at ONE typed ALL array whose shape-asymmetric
/// cardinality (3 vs [`Self::PREFIXES`]'s 4) IS the collapse
/// invariant carried at the type-system level.
pub const LEADS: [char; 3] = [Self::QUOTE_LEAD, Self::QUASIQUOTE_LEAD, Self::UNQUOTE_LEAD];
/// Canonical FIRST-char of [`Self::prefix`] — [`Self::QUOTE_LEAD`]
/// for [`Self::Quote`], [`Self::QUASIQUOTE_LEAD`] for
/// [`Self::Quasiquote`], [`Self::UNQUOTE_LEAD`] for BOTH
/// [`Self::Unquote`] AND [`Self::UnquoteSplice`] (the splice's two-
/// char `,@` prefix shares its lead byte with bare unquote and
/// disambiguates on the peek-then-consume `@` second char inside
/// [`crate::reader::tokenize`]).
/// The three-of-four collapse onto three distinct lead chars is
/// structurally fixed — the reader's outer tokenizer dispatch
/// selects between quote-family entry and every non-quote-family
/// arm on lead char alone, with the `,`-vs-`,@` disambiguation
/// falling out of the reader's second-char peek.
///
/// Structural dual of [`Self::from_lead_char`]: this method projects
/// the closed-set marker to its canonical reader-punctuation lead
/// char; the sibling projects the lead char back to the DEFAULT
/// marker on that char (`,` → [`Self::Unquote`], with the splice
/// promotion living at the reader's peek arm rather than at
/// [`Self::from_lead_char`]'s decode). Every variant round-trips
/// through the composition `Self::from_lead_char(qf.lead_char())`,
/// with the `{Unquote, UnquoteSplice}` two-of-four collapsing onto
/// `Some(Unquote)` per the shared-lead-char structural identity.
///
/// The `const` qualifier is load-bearing: [`crate::reader::tokenize`]
/// binds its outer-match quote-family dispatch to this projection
/// via a pre-match `Self::from_lead_char` check, and future consumer
/// sites (e.g. `const` array literals of every reader-recognized
/// lead byte the tokenizer could dispatch on, LSP completion
/// generators that pre-materialize the lead-char set) route through
/// this projection at compile time. Sibling posture to
/// [`crate::ast::Atom::STR_DELIMITER`] one axis over on the same
/// closed-set-lead-char algebra — that constant is the ONE `char`
/// the `Token::Str` open/close/self-escape/bare-atom-terminator
/// FOUR sites in the reader pair with; this method is the ONE
/// projection the `Token::Quoted(QuoteForm)` outer-dispatch AND
/// the same bare-atom-terminator disjunct pair with across FOUR
/// per-variant lead chars.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// reader's per-char quote-family dispatch IS the typed-entry gate,
/// and lifting its (char, `QuoteForm`) pairing to ONE projection
/// method plus one inverse (see [`Self::from_lead_char`]) closes
/// the tokenizer's outer-arm entry surface onto the closed-set
/// algebra rather than four inline `char` literals scattered across
/// three tokenizer arms (`'\''` / `` '`' `` / `','` outer-match arms)
/// AND three bare-atom-terminator disjuncts (`ch == '\''` / `ch ==
/// '`'` / `ch == ','`). THEORY.md §V.1 — knowable platform; the
/// closed set of quote-family lead chars becomes a TYPE (the
/// enum's arms projected through this method) rather than four
/// literal `char` values scattered across the reader's outer
/// dispatch AND its bare-atom terminator. THEORY.md §VI.1 —
/// generation over composition; a fifth homoiconic prefix
/// (hypothetical `,~` reverse-unquote, `#'` function-quote,
/// `#[…]` vector-quote) extends [`Self`] AND this method AND
/// [`Self::from_lead_char`] AND the tokenizer's pre-match check
/// in lockstep, with rustc binding the extension through
/// exhaustiveness over the closed enum.
#[must_use]
pub const fn lead_char(self) -> char {
match self {
Self::Quote => Self::QUOTE_LEAD,
Self::Quasiquote => Self::QUASIQUOTE_LEAD,
Self::Unquote | Self::UnquoteSplice => Self::UNQUOTE_LEAD,
}
}
/// Inverse of [`Self::lead_char`] on the three-of-four distinct
/// lead chars — `'\''` decodes to `Some(Self::Quote)`, `` '`' ``
/// decodes to `Some(Self::Quasiquote)`, `','` decodes to
/// `Some(Self::Unquote)` (the DEFAULT variant on the shared `,`
/// lead char; the two-char `,@` splice promotion lives at
/// [`crate::reader::tokenize`]'s peek-then-consume `@` disambiguator
/// rather than at this decode). Every other `char` yields `None` —
/// the closed-set guarantee on [`Self`] AND on the tokenizer's
/// outer-arm set (whitespace, `(`, `)`, [`crate::ast::Atom::STR_DELIMITER`],
/// `;`, bare atom) ensures the four typed markers partition the
/// three distinct lead chars injectively against every other
/// tokenizer-recognized entry char.
///
/// ONE consumer entrypoint the reader's `tokenize` binds against:
/// the outer-match quote-family dispatch was pre-lift a hand-rolled
/// three-arm cascade (`'\''` / `` '`' `` / `','`) with per-arm
/// `Token::Quoted(QuoteForm::*)` construction and a fourth
/// `Token::Quoted(QuoteForm::UnquoteSplice)` arm buried inside the
/// `','`-arm's peek branch; post-lift the tokenizer pre-checks
/// `Self::from_lead_char(c)` before the outer match, promotes the
/// returned `Self::Unquote` to `Self::UnquoteSplice` on second-char
/// `@`, and emits ONE `Token::Quoted(final_qf)` — the (lead char,
/// [`Self`] marker) pairing binds at ONE site on the closed-set
/// algebra rather than at three inline `char` literals across
/// three outer-match arms. The bare-atom terminator disjunct at
/// the reader's `Token::Atom` accumulator loop routes through
/// `Self::from_lead_char(ch).is_some()` so the three
/// quote-family-lead disjuncts (`ch == '\''` / `ch == '`'` /
/// `ch == ','`) collapse to ONE gate — a regression that drifts
/// one bare-atom-terminator disjunct from the outer-dispatch's
/// quote-family arm becomes structurally impossible because
/// there is exactly ONE decode both sites consume.
///
/// The two-of-four collapse onto `Some(Self::Unquote)` for the
/// `,` lead char is INTENTIONAL: `Self::UnquoteSplice` has NO
/// distinct lead char; the tokenizer must see two consecutive
/// chars (`,` then `@`) to promote the decoded `Self::Unquote`
/// to `Self::UnquoteSplice`. Placing the promotion at the
/// reader's peek arm rather than at this decode keeps the
/// (char → marker) projection at the closed-set algebra's
/// character-boundary surface (one char in, one variant out)
/// and the (two-char sequence → splice) promotion at the
/// tokenizer's streaming surface (peek and consume the second
/// char). This split parallels the reader's split of `Token::Str`
/// into open-delimiter dispatch ([`crate::ast::Atom::STR_DELIMITER`])
/// AND inner-payload accumulation — the closed-set char algebra
/// decodes the entry char; the streaming reader handles multi-
/// char follow-through.
///
/// Sibling to [`crate::ast::Atom::from_lexeme`] one axis over on
/// the same typed-entry family — that method decodes a bare-atom
/// lexeme into a typed [`crate::ast::Atom`] variant; this method
/// decodes a single lead char into a typed [`Self`] variant. Both
/// map the reader's per-char / per-lexeme classification surface
/// onto the substrate's closed-set algebra so the reader's outer
/// dispatch binds through ONE typed decode rather than through
/// scattered per-arm `char` / `&str` literal patterns.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// reader's per-char quote-family classification IS the typed-entry
/// gate. THEORY.md §V.1 — knowable platform; the reader's outer
/// dispatch AND the bare-atom terminator each route through ONE
/// typed decode against the closed-set algebra rather than through
/// three (or four) parallel `char`-literal patterns that could
/// drift independently — a regression that renames one lead char
/// without updating the sibling site fails at rustc / test time
/// rather than as a silent tokenizer drift.
#[must_use]
pub const fn from_lead_char(c: char) -> Option<Self> {
match c {
Self::QUOTE_LEAD => Some(Self::Quote),
Self::QUASIQUOTE_LEAD => Some(Self::Quasiquote),
Self::UNQUOTE_LEAD => Some(Self::Unquote),
_ => None,
}
}
/// Canonical SECOND char of [`Self::UnquoteSplice`]'s two-char `,@`
/// [`Self::prefix`] — the ONE `'@'` byte the reader's peek-then-
/// consume splice-promotion arm inside [`crate::reader::tokenize`]
/// disambiguates on. Sibling posture to [`crate::ast::Atom::STR_DELIMITER`]
/// (one-char Str-payload delimiter shared across four `"`-round-
/// trip sites) AND to [`crate::ast::Sexp::COMMENT_LEAD`] (one-char
/// line-comment lead shared across two `;`-boundary sites) — those
/// two constants project a single byte onto their respective closed-
/// set algebras (`Atom` and outer-`Sexp`); this constant projects
/// the single byte that composes the `,` [`Self::Unquote`]
/// [`Self::lead_char`] into the two-char [`Self::UnquoteSplice`]
/// [`Self::prefix`] onto the same closed-set [`Self`] algebra.
///
/// The `,@` splice is the ONLY multi-char [`Self::prefix`] in the
/// closed set — [`Self::Quote`] / [`Self::Quasiquote`] / [`Self::Unquote`]
/// each render as a single [`Self::lead_char`] byte; only
/// [`Self::UnquoteSplice`] appends this discriminator. The
/// composition [`Self::Unquote::prefix()`] + `SPLICE_DISCRIMINATOR`
/// == [`Self::UnquoteSplice::prefix()`] IS the structural identity
/// the reader's peek arm depends on — pinned by
/// `quote_form_unquote_splice_prefix_composes_from_unquote_prefix_and_splice_discriminator`.
/// A future hypothetical fifth homoiconic prefix with its own two-
/// char extension (e.g. `,~` reverse-unquote via a `~` discriminator,
/// `#'` function-quote via a `'` discriminator) extends [`Self`]
/// AND a per-variant promotion peer (extending
/// [`Self::promote_via_next_char`]) in lockstep — rustc binds the
/// extension through exhaustiveness over the closed enum.
///
/// The `const` qualifier is load-bearing: [`Self::promote_via_next_char`]'s
/// body binds through this constant in a `const fn` context so the
/// reader's peek arm consumes the promotion table at compile time.
/// Sibling posture to [`crate::ast::Atom::STR_DELIMITER`],
/// [`crate::ast::Atom::KEYWORD_MARKER`], [`crate::ast::Sexp::LIST_OPEN`],
/// [`crate::ast::Sexp::LIST_CLOSE`], [`crate::ast::Sexp::COMMENT_LEAD`] —
/// every canonical reader-punctuation constant on the substrate is a
/// `pub const` on its owning closed-set algebra.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// reader's two-char splice-promotion gate IS the typed-entry gate
/// on the `,@` boundary, and lifting the `@` discriminator to ONE
/// canonical byte on the closed-set algebra closes the gate's
/// entry-char identity onto the algebra rather than at an inline
/// `char` literal at the reader's peek arm. THEORY.md §V.1 —
/// knowable platform; the splice-promotion discriminator becomes a
/// TYPED byte on the substrate algebra rather than an inline `'@'`
/// scattered across the reader — a regression that renames the byte
/// without updating the sibling promotion peer fails at rustc /
/// test time rather than as a silent tokenizer drift where `,@xs`
/// forms silently degrade to `,` + `@xs` two-token sequences.
pub const SPLICE_DISCRIMINATOR: char = '@';
/// Closed-set forced-arity ALL array over the canonical promotion
/// triples on the substrate's quote-family algebra —
/// `(head_variant, next_char_discriminator, promoted_variant)` for
/// every `(head, next)` pair whose [`Self::promote_via_next_char`]
/// projection yields `Some(promoted)`. Post-lift the promotion
/// algebra's canonical triples bind at ONE typed
/// `[(Self, char, Self); N]` array on the closed-set [`QuoteForm`]
/// algebra rather than at zero-primitive-plus-inline-arm-literals
/// inside [`Self::promote_via_next_char`]'s match body.
///
/// The substrate's current promotion algebra is the singleton
/// `[(Self::Unquote, Self::SPLICE_DISCRIMINATOR, Self::UnquoteSplice)]`
/// — the ONLY (variant, next-char) → longer-variant mapping the
/// reader's peek-then-consume `@` promotion arm depends on. Its
/// forced-arity `1` is INTENTIONAL and load-bearing: [`Self::UnquoteSplice`]
/// is the ONLY variant with a two-char [`Self::prefix`], so the
/// promotion table has exactly ONE `Some` arm and every other
/// pairing rejects — the closed set of promotions is the singleton
/// `{(Unquote, '@') → UnquoteSplice}` on the `Self × char →
/// Option<Self>` product. Pinned bit-for-bit by
/// `quote_form_promotions_has_expected_cardinality` (forced-arity)
/// AND `quote_form_promotions_pin_legacy_splice_promotion_triple`
/// (identity of the singleton entry). A future fifth homoiconic
/// prefix with its own two-char extension (a hypothetical `,~`
/// reverse-unquote via a `~` discriminator, a `#'` function-quote
/// via a `'` discriminator, a `,?` conditional-unquote via a `?`
/// discriminator) extends [`Self::ALL`] AND appends ONE new
/// promotion triple to [`Self::PROMOTIONS`] AND extends
/// [`Self::promote_via_next_char`]'s match body in lockstep —
/// rustc's forced-arity check on the `[(Self, char, Self); N]`
/// array fails compilation if the array's cardinality grows
/// without a matching arm on the projection method.
///
/// Sibling posture to the closed-set forced-arity ALL arrays across
/// the substrate's [`QuoteForm`] algebra — [`Self::ALL`]
/// (`[Self; 4]` — the closed set of variants),
/// [`Self::PREFIXES`] (`[&'static str; 4]` — the reader-prefix
/// `&'static str` axis), [`Self::LABELS`] (`[&'static str; 4]` —
/// the diagnostic-label `&'static str` axis),
/// [`Self::IAC_FORGE_TAGS`] (`[&'static str; 4]` — the iac-forge
/// canonical-form tag `&'static str` axis),
/// [`Self::LEADS`] (`[char; 3]` — the reader-lead `char` axis with
/// shape-asymmetric cardinality reflecting the shared-lead-byte
/// collapse of the `,` prefix across [`Self::Unquote`] AND
/// [`Self::UnquoteSplice`]), and [`Self::HASH_DISCRIMINATORS`]
/// (`[u8; 4]` — the outer-Sexp cache-key byte axis). This lift adds
/// the SEVENTH per-family axis on the algebra — the (head, disc,
/// promoted) triple axis on the closed-set promotion product.
/// Each of the seven axes now pins its per-role canonical data at
/// ONE `pub const` per role PLUS an ALL array for family-wide
/// consumers, across the same closed set of four variants (or
/// three-of-four for the shape-asymmetric [`Self::LEADS`] axis's
/// shared-lead-char collapse, or one-of-four for the promotion-
/// asymmetric [`Self::PROMOTIONS`] axis's single-arm collapse).
///
/// Composition identity (pinned by
/// `quote_form_promotions_align_with_promote_via_next_char_for_every_entry`):
/// for every `(head, disc, promoted)` in [`Self::PROMOTIONS`],
/// `head.promote_via_next_char(disc) == Some(promoted)`. The
/// projection's Some-arm binds through [`Self::PROMOTIONS`]`[i].2`
/// (the promoted-variant column of the ONE promotion triple) — a
/// regression that drifts the triple's promoted-variant column
/// silently redirects every reader `,@` sequence to a phantom
/// variant AND fails the alignment pin at rustc / test time
/// rather than at silent tokenizer drift where every `,@xs` form
/// tokenizes to the wrong closed-set marker.
///
/// Rejection contract (pinned by
/// `quote_form_promotions_close_promote_via_next_char_against_every_non_promotion_pair`):
/// for every `(head, next)` pair NOT in [`Self::PROMOTIONS`]'s
/// projection to `(Self × char)`, `head.promote_via_next_char(next)
/// == None`. Sweeps the [`Self::ALL`] × (rejection-char sweep)
/// product against the promotion set's complement — a regression
/// that widened the promotion algebra (e.g. phantom-promoted
/// [`Self::Quote`] on `'@'` after a copy-paste drift on the match
/// arm) surfaces at test time rather than at silent tokenizer
/// drift where bare `'@xs` forms silently degrade to a phantom
/// [`Self::UnquoteSplice`]-shaped sequence.
///
/// Composition law (rendered-prefix identity, pinned by
/// `quote_form_promotions_compose_prefix_from_source_prefix_and_discriminator_for_every_entry`):
/// for every `(head, disc, promoted)` in [`Self::PROMOTIONS`],
/// `format!("{}{}", head.prefix(), disc) == promoted.prefix()`.
/// The (head prefix + discriminator) source-text composition
/// agrees byte-for-byte with the promoted variant's rendered
/// prefix — the reader's peek-then-consume arm's rendered
/// prefix identity closes the read↔write duality across the
/// promotion algebra. Sibling to the pre-existing
/// `quote_form_promote_via_next_char_composes_prefix_from_source_prefix_and_next_char`
/// which pins the same law through the projection method rather
/// than through the triple's data directly — this pin closes the
/// law at the constant, that pin closes it at the projection.
///
/// `pub(crate)` because the promotion algebra is an implementation
/// detail of the substrate's reader — exposing it publicly would
/// leak the promotion-table shape through the API without enabling
/// any external consumer the public projections
/// ([`Self::promote_via_next_char`], [`Self::prefix`],
/// [`Self::from_lead_char`]) don't already serve — same visibility
/// rationale as [`Self::HASH_DISCRIMINATORS`] on the sibling
/// cache-key axis.
///
/// The `#[allow(dead_code)]` posture matches
/// [`Self::HASH_DISCRIMINATORS`] / [`AtomKind::HASH_DISCRIMINATORS`]:
/// the substrate's current [`Self::promote_via_next_char`] body
/// dispatches through ONE match arm bound to the ONE promotion
/// triple's promoted-variant column ([`Self::PROMOTIONS`]`[0].2`),
/// with the head-pattern + discriminator-pattern arm literals
/// preserved for the const-fn match's pattern surface (patterns
/// cannot be array-indexing expressions in the current const-fn
/// grammar). The lift lands the substrate primitive so future
/// consumers keyed on the whole promotion algebra (a future
/// `tatara-check` predicate `(check-promotion-algebra-injective …)`
/// that verifies each `(head, disc)` pair projects to a unique
/// promoted variant, a future LSP structural-navigation filter
/// that keys on the promotion algebra's cardinality, a future
/// `TypedRewriter<PromotionOp>` sweep zipping ALL / PREFIXES /
/// LABELS / IAC_FORGE_TAGS / HASH_DISCRIMINATORS / PROMOTIONS in
/// lockstep for a family-wide render) bind to ONE `[(Self, char,
/// Self); N]` primitive rather than re-deriving the promotion
/// triples inline per callsite. Matches the preemptive-primitive
/// posture the prior-run [`Self::HASH_DISCRIMINATORS`] +
/// [`AtomKind::HASH_DISCRIMINATORS`] +
/// [`crate::error::StructuralKind::HASH_DISCRIMINATORS`] lifts
/// carried before their downstream consumers materialized.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// reader's two-char quote-family classification IS the typed-
/// entry gate on the `,@` boundary, and lifting the promotion
/// algebra's canonical triples to ONE typed `[(Self, char, Self);
/// N]` primitive on the closed-set algebra closes the gate's
/// two-char entry surface onto the algebra rather than at inline
/// arm literals scattered across the const-fn match body.
/// THEORY.md §III — the typescape; the singleton promotion triple
/// binds at ONE typed `pub const` on the closed-set [`QuoteForm`]
/// algebra rather than at zero-primitive-plus-inline-arm-literals
/// at [`Self::promote_via_next_char`]'s match arm. THEORY.md §V.1
/// — knowable platform; the family's cardinality becomes a
/// TYPE-level constant on the substrate algebra rather than a
/// per-consumer runtime dispatch through the match table.
/// THEORY.md §VI.1 — generation over composition; the family-wide
/// contract sweeps (alignment with
/// [`Self::promote_via_next_char`], pairwise disjointness across
/// the head-discriminator product, rendered-prefix composition
/// identity) emerge from the composition of ONE substrate
/// primitive (this `pub(crate) const` array) rather than as
/// per-arm inline assertions duplicated at each call site.
///
/// Frontier inspiration: MLIR's typed rewriter registry
/// (`mlir::PatternApplicator`) carries a per-op-family
/// `[(source_pattern, matcher, rewritten_op)]` static rewrite
/// table at the closed-set boundary — the (source, matcher,
/// target) triple axis becomes typed data on the IR algebra
/// rather than dispatch tables scattered across per-pattern
/// callsites. Translated through the substrate's [`QuoteForm`]
/// closed-set marker, the reader's promotion rewrite table
/// becomes ONE typed `[(head_variant, next_char, promoted_variant);
/// N]` array on the algebra. Where MLIR's registry carries the
/// rewrite table dynamically on the pattern applicator's runtime
/// state, this substrate carries it statically as `pub const` on
/// the closed-set marker — the pattern-matching evaluation lands
/// at rustc-time through const-fn match arm binding to
/// [`Self::PROMOTIONS`]`[i].2` rather than at runtime through a
/// dynamic registry lookup.
#[allow(dead_code)]
pub(crate) const PROMOTIONS: [(Self, char, Self); 1] = [(
Self::Unquote,
Self::SPLICE_DISCRIMINATOR,
Self::UnquoteSplice,
)];
/// Promotion table on the closed-set quote-family algebra —
/// `Some(Self::UnquoteSplice)` iff `self == Self::Unquote &&
/// next == Self::SPLICE_DISCRIMINATOR`, else `None`. Encodes the
/// substrate's ONE (variant, next-char) → longer-variant mapping —
/// `,` [`Self::Unquote`] followed by `@` [`Self::SPLICE_DISCRIMINATOR`]
/// promotes to `,@` [`Self::UnquoteSplice`]. Every other pairing
/// (including [`Self::Quote`] / [`Self::Quasiquote`] / [`Self::UnquoteSplice`]
/// on ANY next-char, AND [`Self::Unquote`] on any non-discriminator
/// next-char) yields `None` — the closed set of promotions is the
/// singleton `{(Unquote, '@') → UnquoteSplice}` on the `Self × char
/// → Option<Self>` product.
///
/// Structural sibling of [`Self::from_lead_char`] one axis over on
/// the same typed-entry family: [`Self::from_lead_char`] decodes
/// ONE lead char to its DEFAULT variant on that char; this method
/// decodes ONE (default variant, second char) pair to its PROMOTED
/// variant. Together the two methods close the reader's outer
/// quote-family entry surface onto the algebra: the tokenizer
/// consumes ONE lead char through [`Self::from_lead_char`], then
/// OPTIONALLY consumes one second char through this method — the
/// (lead char, second char) → typed marker projection binds at TWO
/// typed decodes rather than at inline `char`-literal patterns
/// scattered across the outer-match dispatch arm.
///
/// ONE consumer entrypoint the reader's `tokenize` binds against:
/// the peek-then-consume `@` promotion inside the outer-match
/// quote-family dispatch was pre-lift a hand-rolled inline check
/// `matches!(qf_head, QuoteForm::Unquote) &&
/// chars.peek().map(|&(_, c)| c) == Some('@')` paired with a
/// per-branch `QuoteForm::UnquoteSplice` construction. The pairing
/// was load-bearing yet only enforced by callsite discipline at a
/// SEVENTH consumer site (alongside `Hash`, `Display`, `sexp_shape`,
/// `wrap`, `iac_forge_tag`, `as_unquote_form`) the prior closed-set
/// `QuoteForm` lifts did not reach. Post-lift the reader's peek
/// arm routes through this method, so the (Unquote, '@') →
/// UnquoteSplice promotion binds at ONE site on the typed algebra.
/// A regression that drifts the promotion table (e.g. re-inlines
/// `matches!(qf_head, QuoteForm::Quote)` at the peek arm and
/// silently promotes bare `'` to a phantom variant) becomes a
/// typed compile error against the `Option<Self>` return type.
///
/// The single-promotion collapse (only `(Unquote, '@')` triggers)
/// is INTENTIONAL: [`Self::UnquoteSplice`] is the ONLY variant with
/// a two-char [`Self::prefix`], so the promotion table has exactly
/// ONE `Some` arm and every other pairing rejects. Placing the
/// promotion at the closed-set algebra rather than at the reader's
/// peek arm keeps the streaming reader's two-char peek-then-consume
/// shape at ONE site (the reader) while the (variant × second
/// char) → promoted variant projection lives on the substrate
/// algebra — parallel to the split that [`Self::from_lead_char`]
/// closes for the one-char entry surface. This split parallels the
/// reader's split of `Token::Str` into open-delimiter dispatch
/// ([`crate::ast::Atom::STR_DELIMITER`]) AND inner-payload
/// accumulation — the closed-set char algebra decodes the entry
/// chars; the streaming reader handles the peek-and-consume
/// follow-through.
///
/// Composition identity: for every `qf: QuoteForm` and every
/// `c: char`, if `qf.promote_via_next_char(c) == Some(promoted)`
/// then `format!("{}{}", qf.prefix(), c) == promoted.prefix()`.
/// Pinned by
/// `quote_form_promote_via_next_char_composes_prefix_from_source_prefix_and_next_char`
/// across the singleton promotion arm — the pin asserts the
/// (variant, next char) → promoted-variant projection agrees with
/// the reader's rendered [`Self::prefix`] composition, so a
/// regression that drifts one side of the identity (a promotion
/// arm rerouted through the wrong variant, or a prefix renamed
/// without updating the promotion table) surfaces immediately.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// reader's two-char quote-family classification IS the typed-
/// entry gate on the `,@` boundary. THEORY.md §V.1 — knowable
/// platform; the (variant, next char) → promoted variant table
/// becomes a TYPE projection on the substrate algebra rather than
/// at an inline `matches!(qf, Unquote) && c == '@'` pattern
/// scattered at the reader's peek arm. THEORY.md §VI.1 —
/// generation over composition; a fifth homoiconic prefix with its
/// own two-char extension extends [`Self`] AND this method's match
/// arm in lockstep — rustc binds the extension through
/// exhaustiveness over the closed enum, and the `Option<Self>`
/// return shape leaves the promotion table structurally open for
/// future variants to append their own `Some` arms without
/// touching the existing arms' semantics.
///
/// Frontier inspiration: Racket's `read-syntax` two-char
/// discriminator table (`(quote-abbrev-mapping char) → syntax`)
/// that maps `(#\' → 'quote)`, `(#\` → 'quasiquote)`, `(#\, →
/// 'unquote)`, `(#\, #\@) → 'unquote-splicing)` on the reader's
/// typed abbreviation surface. Translated through the substrate's
/// [`QuoteForm`] outer-marker algebra, the `(#\, #\@) → 'unquote-
/// splicing)` two-char arm becomes ONE typed `(Self::Unquote, '@')
/// → Some(Self::UnquoteSplice)` promotion on the closed-set
/// algebra with rustc binding the promotion identity through
/// exhaustiveness. Where Racket carries the promotion table
/// dynamically on the reader's abbreviation-mapping parameter,
/// this substrate carries it statically as `pub const fn` on the
/// closed-set marker.
#[must_use]
pub const fn promote_via_next_char(self, next: char) -> Option<Self> {
// The Some-arm's promoted-variant column routes through
// `Self::PROMOTIONS[0].2` — the ONE promotion triple on the
// closed-set algebra — so a regression that drifts the
// promoted-variant column of the singleton triple silently
// redirects every reader `,@` sequence to a phantom variant AND
// fails the alignment pin
// `quote_form_promotions_align_with_promote_via_next_char_for_every_entry`
// at rustc / test time rather than at silent tokenizer drift.
// The head-pattern (`Self::Unquote`) + discriminator-pattern
// (`Self::SPLICE_DISCRIMINATOR`) arm literals stay inline
// because patterns cannot be array-indexing expressions in the
// current const-fn grammar; the alignment pin catches head /
// discriminator column drift by construction.
match (self, next) {
(Self::Unquote, Self::SPLICE_DISCRIMINATOR) => Some(Self::PROMOTIONS[0].2),
_ => None,
}
}
/// Canonical `u8` cache-key byte for [`Self::Quote`]'s
/// [`Self::hash_discriminator`] arm — `3`. ONE canonical byte on
/// the closed-set [`QuoteForm`] algebra shared by
/// [`Self::hash_discriminator`]'s [`Self::Quote`] arm AND every
/// downstream consumer (the [`Hash for Sexp`](crate::ast::Sexp)
/// cache-key body, the expansion cache
/// (`crate::macro_expand::Expander::cache`) that keys on that hash).
///
/// Sibling posture to the closed set of per-role `pub(crate) const`
/// / `pub const` bytes on the substrate's other closed-set outer
/// algebras: [`Self::QUOTE_PREFIX`] / [`Self::QUASIQUOTE_PREFIX`]
/// / [`Self::UNQUOTE_PREFIX`] / [`Self::UNQUOTE_SPLICE_PREFIX`]
/// (per-role reader-prefix `&'static str` algebra on the SAME
/// [`QuoteForm`] closed set — commit a08e61f),
/// [`Self::QUOTE_LABEL`] / [`Self::QUASIQUOTE_LABEL`] /
/// [`Self::UNQUOTE_LABEL`] / [`Self::UNQUOTE_SPLICE_LABEL`] (per-
/// role diagnostic-label `&'static str` algebra on the SAME closed
/// set — commit 70be157), [`Self::QUOTE_IAC_FORGE_TAG`] /
/// [`Self::QUASIQUOTE_IAC_FORGE_TAG`] / [`Self::UNQUOTE_IAC_FORGE_TAG`]
/// / [`Self::UNQUOTE_SPLICE_IAC_FORGE_TAG`] (per-role iac-forge
/// canonical-form tag `&'static str` algebra on the SAME closed set
/// — commit bdd624b). This constant closes the FOURTH per-role
/// axis on [`QuoteForm`] — the `u8` cache-key axis paired with the
/// three pre-existing `&'static str` axes.
///
/// The FOUR canonical bytes `{3, 4, 5, 6}` partition the outer-
/// [`crate::ast::Sexp`] `Hash` body's quote-family arm-set against
/// the reserved bytes the non-quote-family arms use (`0u8` for
/// [`crate::error::StructuralKind::Nil`] via
/// [`crate::error::StructuralKind::hash_discriminator`], `1u8` for
/// [`crate::ast::Sexp::Atom`]'s outer-carve marker via the
/// pre-existing inline `1u8` at [`Hash for Sexp`](crate::ast::Sexp)'s
/// atom arm, `2u8` for [`crate::error::StructuralKind::List`] via
/// [`crate::error::StructuralKind::hash_discriminator`]) — the
/// three carvings of the outer-[`crate::ast::Sexp`] cache-key
/// space jointly cover the `{0, 1, 2, 3, 4, 5, 6}` byte-set with
/// no gaps AND no overlaps.
///
/// A regression that inlines the `3` literal at
/// [`Self::hash_discriminator`]'s [`Self::Quote`] arm and drifts
/// the constant silently (e.g. a re-numbering that collides with
/// the reserved `2u8` for [`crate::error::StructuralKind::List`],
/// silently mis-hashing every cached expansion across the substrate)
/// fails at the algebra's `hash_discriminator()` path-uniformity
/// pin
/// (`quote_form_hash_discriminator_routes_through_typed_per_role_constants`)
/// rather than at silent cache-key drift where
/// `crate::macro_expand::Expander::cache` mis-collides live
/// expansions.
///
/// `pub(crate)` because the byte-discriminator surface is an
/// implementation detail of the substrate's [`Hash for Sexp`](crate::ast::Sexp)
/// cache-key contract; exposing it publicly would leak the cache-
/// key shape through the API without enabling any external
/// consumer the public projections ([`Self::as_quote_form`],
/// [`Self::prefix`], [`Self::as_unquote_form`]) don't already
/// serve — same visibility rationale as [`Self::hash_discriminator`]
/// itself.
///
/// Theory anchor: THEORY.md §II.1 invariant 5 — composition
/// preserves proofs; the alias-chain composition law
/// `QuoteForm::HASH_DISCRIMINATORS[i] ==
/// QuoteForm::ALL[i].hash_discriminator()` binds the family-wide
/// array to the projection method at rustc time, pinned by byte
/// equality. THEORY.md §III — the typescape; the four canonical
/// cache-key bytes bind at ONE `pub(crate) const` per role on the
/// typed algebra rather than as inline `u8` literals in the
/// `hash_discriminator` match arms.
pub(crate) const QUOTE_HASH_DISCRIMINATOR: u8 = 3;
/// Canonical `u8` cache-key byte for [`Self::Quasiquote`]'s
/// [`Self::hash_discriminator`] arm — `4`. Sibling of
/// [`Self::QUOTE_HASH_DISCRIMINATOR`] on the closed-set per-role
/// quote-family cache-key-byte axis; see
/// [`Self::QUOTE_HASH_DISCRIMINATOR`] for the algebra-level round-
/// trip + disjointness contracts every sibling shares.
pub(crate) const QUASIQUOTE_HASH_DISCRIMINATOR: u8 = 4;
/// Canonical `u8` cache-key byte for [`Self::Unquote`]'s
/// [`Self::hash_discriminator`] arm — `5`. Sibling of
/// [`Self::QUOTE_HASH_DISCRIMINATOR`] on the closed-set per-role
/// quote-family cache-key-byte axis. Byte-for-byte distinct from
/// [`Self::UNQUOTE_SPLICE_HASH_DISCRIMINATOR`] — the two template-
/// substitution arms partition `{5, 6}` on the outer-Sexp cache-
/// key space.
pub(crate) const UNQUOTE_HASH_DISCRIMINATOR: u8 = 5;
/// Canonical `u8` cache-key byte for [`Self::UnquoteSplice`]'s
/// [`Self::hash_discriminator`] arm — `6`. Sibling of
/// [`Self::QUOTE_HASH_DISCRIMINATOR`] on the closed-set per-role
/// quote-family cache-key-byte axis. The HIGHEST byte on the
/// closed set — a future fifth quote-family variant would extend
/// the partition to `{3, 4, 5, 6, 7}` and land the new
/// discriminator at `7u8`.
pub(crate) const UNQUOTE_SPLICE_HASH_DISCRIMINATOR: u8 = 6;
/// Closed-set forced-arity ALL array over the canonical cache-key
/// `u8` bytes, in declaration order matching [`Self::ALL`] element-
/// wise (pinned by `quote_form_hash_discriminators_align_with_all_by_index`).
/// Sibling posture to [`Self::PREFIXES`] (`[&'static str; 4]` —
/// the reader-prefix `&'static str` axis on the SAME closed set),
/// [`Self::LABELS`] (`[&'static str; 4]` — the diagnostic-label
/// `&'static str` axis), [`Self::IAC_FORGE_TAGS`] (`[&'static str;
/// 4]` — the iac-forge canonical-form tag `&'static str` axis) —
/// every closed-set outer projection on the substrate's
/// [`QuoteForm`] algebra now pins its per-role canonical bytes at
/// ONE `pub(crate) const` / `pub const` per role PLUS an ALL array
/// for family-wide consumers, across ALL FOUR production
/// vocabularies the closed set carries (reader prefix, diagnostic
/// label, iac-forge canonical-form tag, outer-Sexp cache-key byte).
///
/// Pre-lift the four cache-key bytes had NO per-role primitive on
/// this closed-set algebra — a consumer with a [`QuoteForm`]
/// variant in hand at compile time reaching for the canonical byte
/// had to spell `QuoteForm::Unquote.hash_discriminator()` (runtime
/// dispatch through the match arm) OR reach across into the inline
/// `5u8` at the pre-lift match arm's [`Self::Unquote`] branch and
/// re-derive the (variant, byte) pairing at the call site.
/// Post-lift the FOUR canonical bytes bind at ONE `pub(crate) const`
/// per role on the typed [`QuoteForm`] algebra AND at
/// [`Self::HASH_DISCRIMINATORS`] as a family-wide forced-arity
/// array — a future substrate-facing cache-key introspection tool
/// (a `tatara-check` predicate that asserts every quote-family
/// arm's discriminator disjoint from the reserved
/// [`crate::ast::Sexp::Atom`] byte, a Sekiban audit-trail metric
/// jointly labeled by the cache-key partition, a future
/// `TypedRewriter<QuoteFormOp>` sweep zipping ALL / PREFIXES /
/// LABELS / IAC_FORGE_TAGS / HASH_DISCRIMINATORS in lockstep for a
/// family-wide (variant, four-vocabulary quadruple) render) reads
/// through the typed constants without re-deriving the four-arm
/// carving inline.
///
/// Each entry is byte-for-byte identical to the pre-lift inline
/// `u8` literal at the corresponding [`Self::hash_discriminator`]
/// arm — pinned by
/// `quote_form_hash_discriminators_pin_legacy_cache_key_bytes` so
/// a regression that drifts ONE `pub(crate) const` from its pre-
/// lift byte silently invalidates every cached expansion AND mis-
/// collides with the reserved bytes the non-quote-family arms use,
/// fails-loudly at the alias test rather than at a silent
/// [`crate::macro_expand::Expander::cache`] mis-hash. Adding a
/// hypothetical fifth homoiconic prefix (a `,~` reverse-unquote, a
/// `,?` conditional-unquote) extends [`Self::ALL`] AND
/// [`Self::HASH_DISCRIMINATORS`] AND adds ONE per-role
/// `pub(crate) const` in lockstep — rustc's forced-arity check on
/// the two `[_; N]` arrays fails compilation if EITHER array grows
/// without the other, closing the extensibility gap that pre-lift
/// silently allowed a discriminator collision on `7u8` (the next
/// free byte).
///
/// Theory anchor: THEORY.md §III — the typescape; the four
/// canonical cache-key bytes bind at ONE typed `[u8; 4]` array on
/// the closed-set [`QuoteForm`] algebra rather than at zero-
/// primitive-plus-four-inline-`u8`-literals scattered across the
/// [`Self::hash_discriminator`] match arms. THEORY.md §V.1 —
/// knowable platform; the family's cardinality becomes a TYPE-
/// level constant on the substrate algebra rather than a per-
/// consumer runtime dispatch through the match table. THEORY.md
/// §V.3 — three-pillar attestation; the cache-key partition is
/// the substrate's outer-Sexp `intent_hash` composition axis for
/// every quote-family arm — binding the four bytes on the typed
/// algebra makes attestation-key drift a compile error rather
/// than a silent BLAKE3 mis-hash. THEORY.md §VI.1 — generation
/// over composition; the family-wide contract sweeps (alignment
/// with `ALL`, pairwise disjointness, membership through
/// [`Self::hash_discriminator`]) emerge from the composition of
/// TWO substrate primitives (this `pub(crate) const` array + the
/// four per-role `pub(crate) const *_HASH_DISCRIMINATOR` aliases)
/// rather than as per-variant inline assertions duplicated at
/// each call site.
///
/// The `#[allow(dead_code)]` posture is deliberate: the substrate's
/// current [`Hash for Sexp`](crate::ast::Sexp) body composes
/// through the per-variant [`Self::hash_discriminator`] projection
/// arm-by-arm rather than sweeping the family-wide array, so no
/// non-test caller currently reaches this ALL array directly. The
/// lift lands the substrate primitive so future consumers keyed
/// on the whole family (a future
/// [`crate::macro_expand::Expander`] cache-warmup pass that hashes
/// the quote-family byte-set upfront, a future `tatara-check`
/// predicate `(check-cache-key-partition-disjoint …)` that
/// verifies the `{3, 4, 5, 6}` partition against the reserved
/// `{0, 1, 2}` bytes structurally, a future
/// `TypedRewriter<QuoteFormOp>` sweep zipping ALL / PREFIXES /
/// LABELS / IAC_FORGE_TAGS / HASH_DISCRIMINATORS in lockstep for a
/// family-wide (variant, four-vocabulary quadruple) render) bind
/// to ONE `[u8; 4]` primitive rather than re-deriving the array
/// inline per callsite. Matches the preemptive-primitive posture
/// the prior-run [`crate::error::UnquoteForm::hash_discriminator`]
/// lift carried before its downstream consumers materialized.
#[allow(dead_code)]
pub(crate) const HASH_DISCRIMINATORS: [u8; 4] = [
Self::QUOTE_HASH_DISCRIMINATOR,
Self::QUASIQUOTE_HASH_DISCRIMINATOR,
Self::UNQUOTE_HASH_DISCRIMINATOR,
Self::UNQUOTE_SPLICE_HASH_DISCRIMINATOR,
];
/// Stable, per-variant byte discriminator that paired with the
/// recursive inner hash builds the substrate's `Hash for Sexp`
/// projection — `3` for [`Self::Quote`], `4` for
/// [`Self::Quasiquote`], `5` for [`Self::Unquote`], `6` for
/// [`Self::UnquoteSplice`]. The byte values are load-bearing
/// because the expansion cache (`Expander::cache`) keys on the
/// hash of `(macro_name, args)` — changing a discriminator silently
/// invalidates every cached expansion AND mis-collides with the
/// reserved bytes the non-quote-family Hash arms use (`0` for
/// `Nil`, `1` for `Atom`, `2` for `List`). The closed set ensures
/// the four arms partition `{3, 4, 5, 6}` injectively against the
/// reserved bytes — a future quote-family extension must extend
/// this method AND the non-quote-family arms in lockstep, with
/// rustc binding the consistency through exhaustiveness over the
/// closed enum.
///
/// Post-lift the four arms route through the per-role
/// `pub(crate) const` bytes on the closed-set [`QuoteForm`]
/// algebra ([`Self::QUOTE_HASH_DISCRIMINATOR`],
/// [`Self::QUASIQUOTE_HASH_DISCRIMINATOR`],
/// [`Self::UNQUOTE_HASH_DISCRIMINATOR`],
/// [`Self::UNQUOTE_SPLICE_HASH_DISCRIMINATOR`]) rather than
/// inline `u8` literals — so a re-numbering that would silently
/// invalidate every cached expansion lands as ONE edit to the
/// matching `pub(crate) const` rather than at four scattered
/// arm-literals. Every downstream consumer that binds to the
/// algebra ([`Hash for Sexp`](crate::ast::Sexp)'s outer sweep,
/// the [`crate::macro_expand::Expander::cache`] cache-key
/// composition, the future coverage-tool sweeps) inherits the
/// rename mechanically.
///
/// `pub(crate)` because the byte-discriminator surface is an
/// implementation detail of the substrate's `Hash for Sexp` cache-
/// key contract; exposing it publicly would leak the cache-key
/// shape through the API without enabling any external consumer
/// the public projections (`Sexp::as_quote_form`, `Self::prefix`,
/// `Self::as_unquote_form`) don't already serve.
#[must_use]
pub(crate) fn hash_discriminator(self) -> u8 {
match self {
Self::Quote => Self::QUOTE_HASH_DISCRIMINATOR,
Self::Quasiquote => Self::QUASIQUOTE_HASH_DISCRIMINATOR,
Self::Unquote => Self::UNQUOTE_HASH_DISCRIMINATOR,
Self::UnquoteSplice => Self::UNQUOTE_SPLICE_HASH_DISCRIMINATOR,
}
}
/// Project the 4-of-4 quote-family marker into the 2-of-4
/// template-substitution subset — `Some(UnquoteForm::Unquote)` for
/// [`Self::Unquote`], `Some(UnquoteForm::Splice)` for
/// [`Self::UnquoteSplice`], `None` for [`Self::Quote`] /
/// [`Self::Quasiquote`] (the literal-quote and quasi-quote
/// prefixes are wrappers, NOT substitution points). ONE projection
/// on this algebra the [`crate::ast::Sexp::as_unquote`] derivation
/// routes through — the (Sexp variant, UnquoteForm marker) pairing
/// now binds at the typed [`crate::ast::Sexp::as_quote_form`]
/// projection's output composed with this method's output, instead
/// of being re-derived per-arm inside `Sexp::as_unquote`.
///
/// The closed-set guarantee on [`UnquoteForm`] (exactly
/// `Unquote ⊎ Splice`) AND on [`Self`] (exactly
/// `Quote ⊎ Quasiquote ⊎ Unquote ⊎ UnquoteSplice`) ensures that the
/// 2-of-4 subset is structurally fixed: a future variant joining
/// the template-substitution surface extends both enums AND this
/// method's match arm together, with rustc binding the extension
/// through the projection's `Option` return type.
#[must_use]
pub fn as_unquote_form(self) -> Option<UnquoteForm> {
match self {
Self::Unquote => Some(UnquoteForm::Unquote),
Self::UnquoteSplice => Some(UnquoteForm::Splice),
Self::Quote | Self::Quasiquote => None,
}
}
/// Canonical `&'static str` iac-forge canonical-form tag of
/// [`Self::Quote`] — `"quote"`. The ONE canonical bytes-payload on
/// the closed-set [`QuoteForm`] algebra shared by [`Self::iac_forge_tag`]'s
/// [`Self::Quote`] arm AND the `crate::interop` (removed) `From<&Sexp> for
/// iac_forge::sexpr::SExpr` arm the projection feeds.
///
/// Sibling posture to the closed set of per-role `pub const` bytes
/// on the substrate's other closed-set outer algebras:
/// [`Self::QUOTE_PREFIX`] / [`Self::QUASIQUOTE_PREFIX`] /
/// [`Self::UNQUOTE_PREFIX`] / [`Self::UNQUOTE_SPLICE_PREFIX`] (per-
/// role reader-prefix algebra on the SAME [`QuoteForm`] closed set),
/// [`crate::error::MacroDefHead::DEFMACRO_KEYWORD`] /
/// [`crate::error::MacroDefHead::DEFPOINT_TEMPLATE_KEYWORD`] /
/// [`crate::error::MacroDefHead::DEFCHECK_KEYWORD`] (per-role
/// head-keyword algebra on the CL macro-definition surface),
/// [`Atom::TRUE_LITERAL`] / [`Atom::FALSE_LITERAL`] (per-role
/// Scheme-bool spelling algebra on the atomic-payload surface).
///
/// The (canonical iac-forge tag) axis lives ORTHOGONAL to the
/// (canonical reader prefix) axis: `Self::QUOTE_PREFIX` (`"'"`) and
/// `Self::QUOTE_IAC_FORGE_TAG` (`"quote"`) both project the same
/// variant but through two distinct byte vocabularies — the reader
/// axis for the Lisp source-code surface, the iac-forge axis for
/// the cross-crate canonical-form surface (BLAKE3 attestation,
/// render cache). A regression that inlines the `"quote"` literal
/// at [`Self::iac_forge_tag`]'s [`Self::Quote`] arm and drifts the
/// constant silently (e.g. a hypothetical rename to `"literal-quote"`
/// on the iac-forge side while leaving the prefix `"'"` intact)
/// fails at the algebra's `iac_forge_tag()` path-uniformity pin
/// (`quote_form_iac_forge_tag_routes_through_typed_per_role_constants`)
/// rather than at silent canonical-form drift where downstream
/// BLAKE3 attestation keys silently mis-hash.
pub const QUOTE_IAC_FORGE_TAG: &'static str = "quote";
/// Canonical `&'static str` iac-forge canonical-form tag of
/// [`Self::Quasiquote`] — `"quasiquote"`. Sibling of
/// [`Self::QUOTE_IAC_FORGE_TAG`] on the closed-set per-role
/// quote-family iac-forge tag-bytes axis; see
/// [`Self::QUOTE_IAC_FORGE_TAG`] for the algebra-level round-trip +
/// disjointness contracts every sibling shares.
pub const QUASIQUOTE_IAC_FORGE_TAG: &'static str = "quasiquote";
/// Canonical `&'static str` iac-forge canonical-form tag of
/// [`Self::Unquote`] — `"unquote"`. Sibling of
/// [`Self::QUOTE_IAC_FORGE_TAG`] on the closed-set per-role
/// quote-family iac-forge tag-bytes axis.
///
/// Byte-identical to the substrate's shorter diagnostic label
/// [`crate::error::SexpShape::Unquote`]'s label projection
/// (`SexpShape::label` returns `"unquote"` for this variant) — the
/// two projections happen to agree on this variant's bytes but
/// live at distinct algebraic layers (iac-forge canonical form vs
/// substrate diagnostic surface); the divergence is load-bearing on
/// the [`Self::UnquoteSplice`] arm (`"unquote-splicing"` vs
/// `"unquote-splice"`) and this byte-level agreement here does not
/// license a consolidation of the two axes. Pinned by
/// `quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice`.
pub const UNQUOTE_IAC_FORGE_TAG: &'static str = "unquote";
/// Canonical `&'static str` iac-forge canonical-form tag of
/// [`Self::UnquoteSplice`] — `"unquote-splicing"`. The Common-Lisp-
/// canonical spelling: a `,@x` form encodes as `(unquote-splicing x)`
/// rather than `(unquote-splice x)`. That tag-string choice is
/// INTENTIONALLY DISTINCT from the substrate's shorter diagnostic
/// label projected by [`crate::error::SexpShape::label`] (which
/// renders `[`Self::UnquoteSplice`]` as `"unquote-splice"` — the
/// shorter idiom appropriate for `expected …, got unquote-splice`
/// error surfaces). The two projections key the SAME closed set on
/// TWO distinct boundaries — pinning the divergence at the typed
/// per-role `pub const` documents the intent structurally: a
/// future "consolidation" PR that homogenizes them would have to
/// touch this constant explicitly, surfacing the boundary-distinct
/// invariant at code-review time rather than silently.
///
/// Sibling of [`Self::QUOTE_IAC_FORGE_TAG`] on the closed-set
/// per-role quote-family iac-forge tag-bytes axis. The ONLY entry
/// on this axis whose bytes disagree with the peer-axis
/// [`crate::error::SexpShape::label`] projection — pinned by
/// `quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice`
/// alongside the three matched-arm agreements.
pub const UNQUOTE_SPLICE_IAC_FORGE_TAG: &'static str = "unquote-splicing";
/// The closed-set forced-arity ALL array over the quote-family
/// iac-forge canonical-form tag `&'static str` bytes in canonical
/// declaration order matching [`Self::ALL`] element-wise. Sibling
/// posture to [`Self::PREFIXES`] (`[&'static str; 4]` on the
/// reader-prefix axis of the SAME [`QuoteForm`] closed set),
/// [`crate::error::MacroDefHead::KEYWORDS`] (`[&'static str; 3]`
/// on the CL macro-definition head algebra),
/// [`Atom::BOOL_LITERALS`] (`[&'static str; 2]` on the Scheme-bool
/// spelling algebra), and
/// [`crate::macro_expand::MacroParams::LAMBDA_LIST_KEYWORDS`]
/// (`[&'static str; 2]` on the CL lambda-list-keyword algebra) —
/// every closed-set outer projection on the substrate now pins its
/// canonical bytes at ONE `pub const` per role plus an ALL array
/// for family-wide consumers.
///
/// The (canonical iac-forge tag) axis + the (canonical reader
/// prefix) axis together span the two production byte-vocabularies
/// the [`QuoteForm`] closed set carries — [`Self::PREFIXES`] holds
/// the Lisp source-code prefixes (`"'"`, `` "`" ``, `","`, `",@"`)
/// the reader tokenizes on, [`Self::IAC_FORGE_TAGS`] holds the
/// cross-crate canonical-form tag strings (`"quote"`,
/// `"quasiquote"`, `"unquote"`, `"unquote-splicing"`) the
/// iac-forge interop layer round-trips through. Adding a
/// hypothetical fifth homoiconic prefix (a `,~` reverse-unquote, a
/// `,?` conditional-unquote, a `#'` Common-Lisp function-quote)
/// extends [`Self::ALL`] AND [`Self::PREFIXES`] AND
/// [`Self::IAC_FORGE_TAGS`] AND [`Self::prefix`]'s arm AND
/// [`Self::iac_forge_tag`]'s arm AND two new per-role `pub const`s
/// (one on each axis) in lockstep — rustc's forced-arity check on
/// `[&'static str; N]` fails compilation if any of the three ALL
/// arrays grows without the others.
///
/// Future consumers that compose against [`Self::IAC_FORGE_TAGS`]:
/// - Cross-crate canonical-form completion (an authoring tool
/// surfacing every legal iac-forge tag in a `(<tag> <inner>)`
/// template — the completion set IS [`Self::IAC_FORGE_TAGS`]
/// rather than four hand-enumerated `&'static str` literals per
/// completion provider).
/// - `tatara-check` coverage assertions that sweep workspace
/// attestation payloads for every canonical iac-forge tag —
/// the typed sweep replaces per-consumer inline enumeration of
/// the four literals.
/// - Any future audit-trail metric jointly labeled by
/// [`Self::iac_forge_tag`] (e.g.
/// `tatara_lisp_iac_forge_tag_total{tag="quote"}`) — the metric
/// label set IS [`Self::IAC_FORGE_TAGS`] mapped through
/// [`Self::iac_forge_tag`].
pub const IAC_FORGE_TAGS: [&'static str; 4] = [
Self::QUOTE_IAC_FORGE_TAG,
Self::QUASIQUOTE_IAC_FORGE_TAG,
Self::UNQUOTE_IAC_FORGE_TAG,
Self::UNQUOTE_SPLICE_IAC_FORGE_TAG,
];
/// Canonical iac-forge interop tag — the symbol head the canonical
/// 2-element-list encoding of a quote-family wrapper uses when
/// projecting `tatara_lisp::Sexp` into `iac_forge::sexpr::SExpr`:
/// `"quote"` for [`Self::Quote`], `"quasiquote"` for
/// [`Self::Quasiquote`], `"unquote"` for [`Self::Unquote`],
/// `"unquote-splicing"` for [`Self::UnquoteSplice`].
///
/// The mapping is Common-Lisp-canonical: a `,@x` form encodes as
/// `(unquote-splicing x)` rather than `(unquote-splice x)`. That
/// tag-string choice is INTENTIONALLY DISTINCT from the substrate's
/// shorter diagnostic label projected by
/// [`crate::error::SexpShape::label`] (which renders
/// `[`Self::UnquoteSplice`]` as `"unquote-splice"` — the shorter
/// idiom appropriate for `expected …, got unquote-splice` error
/// surfaces). The two projections key the SAME closed set on TWO
/// distinct boundaries:
///
/// * `iac_forge_tag` — cross-crate canonical form, BLAKE3 attestation
/// keys, render-cache shape (load-bearing for byte-identical
/// inter-crate compatibility with the iac-forge ecosystem).
/// * `SexpShape::label` — operator-facing diagnostic label,
/// `LispError::TypeMismatch.got` rendering, REPL/LSP
/// shape-of-witness surface.
///
/// Pre-lift the four canonical iac-forge tag strings lived inline
/// across four arms in `crate::interop` (removed)'s
/// `From<&Sexp> for iac_forge::sexpr::SExpr` impl, paired with the
/// matching `Sexp::{Quote, Quasiquote, Unquote, UnquoteSplice}`
/// patterns. The pairing was load-bearing yet only enforced by
/// callsite discipline at a FOURTH consumer site (alongside `Hash`,
/// `Display`, and `Sexp::as_unquote`) the prior closed-set
/// `QuoteForm` lift did not reach (the `iac-forge` feature gate
/// kept that site's drift risk silent in the default build). After
/// this lift the interop arms collapse to ONE arm routing through
/// [`crate::ast::Sexp::as_quote_form`] + this method, so the
/// (Sexp variant, canonical tag string) pairing binds at ONE site
/// on the substrate algebra regardless of which consumer surface
/// (`Hash`, `Display`, `Sexp::as_unquote`, iac-forge interop)
/// needs it.
///
/// The `&'static str` lifetime is load-bearing: every iac-forge
/// consumer projects through this method into the canonical
/// 2-element-list head without an allocation, parallel to how
/// [`Self::prefix`], [`UnquoteForm::marker`], and
/// [`crate::error::SexpShape::label`] project their respective
/// closed-set surfaces. A future homoiconic prefix-wrapper (e.g.
/// hypothetical `,~` reverse-unquote) extends [`Self`] AND this
/// method's match arm together — rustc binds the iac-forge
/// canonical-form surface to the algebra through exhaustiveness.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the
/// quote-family canonical-form tag set becomes a TYPE projection
/// on the substrate algebra rather than four `&'static str`
/// literals scattered across the `interop` arms (parallel to how
/// `Self::prefix` lifts the Display↔reader prefix and
/// `Self::hash_discriminator` lifts the cache-key bytes).
/// THEORY.md §VI.1 — generation over composition; the (Sexp
/// variant, iac-forge tag) pairing appeared at the four
/// `interop.rs` arms — past the ≥2 PRIME-DIRECTIVE trigger once
/// the structural shape is named. THEORY.md §II.1 invariant 1 —
/// typed entry; the cross-crate canonical-form projection IS the
/// typed-exit gate at the iac-forge boundary, and naming its
/// closed-set tag identity lifts the gate from per-site literal
/// discipline to ONE method the iac-forge round-trip discipline
/// binds against.
#[must_use]
pub fn iac_forge_tag(self) -> &'static str {
match self {
Self::Quote => Self::QUOTE_IAC_FORGE_TAG,
Self::Quasiquote => Self::QUASIQUOTE_IAC_FORGE_TAG,
Self::Unquote => Self::UNQUOTE_IAC_FORGE_TAG,
Self::UnquoteSplice => Self::UNQUOTE_SPLICE_IAC_FORGE_TAG,
}
}
/// Inverse of [`Self::iac_forge_tag`] on the four-arm canonical CL
/// tag closed set — `"quote"` decodes to `Some(Self::Quote)`,
/// `"quasiquote"` decodes to `Some(Self::Quasiquote)`, `"unquote"`
/// decodes to `Some(Self::Unquote)`, `"unquote-splicing"` decodes to
/// `Some(Self::UnquoteSplice)`. Every other `tag` (empty string,
/// PascalCase drift, the shorter substrate diagnostic label
/// `"unquote-splice"` — which is INTENTIONALLY distinct from the
/// CL canonical `"unquote-splicing"` per the substrate's
/// two-vocabulary axis pinned by
/// `quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice`,
/// every arbitrary word not in the four-arm image) yields `None`.
///
/// Structural roundtrip law (pinned by
/// `quote_form_iac_forge_tag_round_trips_through_from_iac_forge_tag`):
/// for every `qf: QuoteForm`,
/// `Self::from_iac_forge_tag(qf.iac_forge_tag()) == Some(qf)`.
/// Sibling posture to [`Self::from_lead_char`]'s inverse-of-
/// [`Self::lead_char`] contract on the reader-lead-char axis —
/// both name the typed inverse decoder on a per-role projection
/// axis of the same closed set, with `Option<Self>` shape mirroring
/// the partial decode over an unbounded string codomain into the
/// four-arm typed closed set.
///
/// Load-bearing use case: cross-crate iac-forge canonical-form
/// inbound decoding. Pre-lift a consumer parsing a canonical
/// `(<tag> <inner>)` list from an `iac_forge::sexpr::SExpr` (a
/// downstream deserialization codepath, an LSP quick-fix that
/// completes an iac-forge canonical-form skeleton, a
/// `tatara-check` predicate that reads back an attested
/// canonical form and re-typed-witnesses its shape) would have
/// to hand-roll `match tag { "quote" => QuoteForm::Quote,
/// "quasiquote" => …, "unquote-splicing" => …, _ => return None
/// }` at each callsite; post-lift the (tag, typed variant)
/// decode binds at ONE typed method on the substrate algebra
/// composed as a linear sweep over [`Self::ALL`] keyed on
/// [`Self::iac_forge_tag`]. The (tag literals, decode arms)
/// pairing lives at ONE canonical site (the four
/// [`Self::QUOTE_IAC_FORGE_TAG`] / [`Self::QUASIQUOTE_IAC_FORGE_TAG`]
/// / [`Self::UNQUOTE_IAC_FORGE_TAG`] /
/// [`Self::UNQUOTE_SPLICE_IAC_FORGE_TAG`] per-role constants
/// [`Self::iac_forge_tag`]'s outbound arms bind to) rather than
/// at TWO — the outbound projection (existing) plus a hand-rolled
/// inbound decoder duplicated per callsite.
///
/// Boundary distinction with [`Self::from_str`] (the substrate's
/// [`FromStr`] impl derived via `#[closed_set(via = "prefix")]`):
/// [`Self::from_str`] decodes the reader-punctuation vocabulary
/// (`"'"`, `` "`" ``, `","`, `",@"`); THIS method decodes the
/// cross-crate iac-forge canonical-form vocabulary (`"quote"`,
/// `"quasiquote"`, `"unquote"`, `"unquote-splicing"`). The two
/// closed-set inverse decoders key the SAME four-arm outer set
/// through TWO orthogonal byte vocabularies — pinning them at
/// distinct methods documents the axis-orthogonality
/// [`Self::PREFIXES`] vs [`Self::IAC_FORGE_TAGS`] carries at the
/// per-role forced-arity ALL array level. A consumer with a
/// reader-punctuation byte in hand routes through [`FromStr`];
/// a consumer with an iac-forge canonical tag in hand routes
/// through THIS method — the vocabulary axis binds at the
/// decoder-method boundary rather than at per-consumer inline
/// dispatch.
///
/// Case-sensitive by design — matches the case-sensitive
/// [`FromStr`] posture (which decodes reader punctuation) and
/// every other closed-set FromStr on the substrate. Non-const
/// because `&str` equality is not const-evaluable on stable at
/// substrate MSRV (parallel to how [`Self::FromStr`]'s decode
/// body is non-const while [`Self::from_lead_char`] is
/// `const fn` because `char` equality IS const-evaluable);
/// callers that need a decode-at-compile-time surface stay on
/// the reader-lead-char decoder.
///
/// Post-lift the (iac-forge tag, typed variant) inverse decoder
/// closes the FIFTH inverse-projection axis on the outer-`QuoteForm`
/// algebra alongside [`Self::from_lead_char`] (the reader-lead-char
/// axis inverse), [`Self::FromStr`] (the reader-prefix axis
/// inverse, derived via `#[closed_set(via = "prefix")]`),
/// [`crate::error::SexpShape::as_quote_form`] (the outer-shape
/// carving inverse embedding), and
/// [`crate::error::UnquoteForm::to_quote_form`] (the
/// substitution-subset embedding inverse). The full outer
/// quote-family algebra now closes ALL FIVE inverse-projection
/// axes matched with their forward-projection siblings
/// ([`Self::lead_char`] / [`Self::prefix`] / [`Self::sexp_shape`]
/// / [`Self::as_unquote_form`] on the forward side).
///
/// Theory anchor: THEORY.md §II.1 invariant 3 — typed exit; the
/// inbound iac-forge canonical-form decode surface becomes a
/// TYPE projection on the closed-set [`QuoteForm`] algebra
/// rather than an inline match at every downstream consumer.
/// THEORY.md §V.1 — knowable platform; the closed set of
/// canonical CL tags becomes a decoder codomain rather than
/// four inline `&'static str` literals scattered across future
/// consumers that could drift independently. THEORY.md §VI.1 —
/// generation over composition; the (tag, typed variant)
/// pairing decodes at ONE typed method on the algebra composed
/// from the pre-existing [`Self::ALL`] typed set and the
/// [`Self::iac_forge_tag`] outbound projection — no new
/// per-role primitive, the decode is a typed CONSEQUENCE of
/// the existing family-wide primitives. Sibling posture to
/// [`Self::from_lead_char`] which similarly composes as an
/// inverse over [`Self::lead_char`] without introducing a new
/// per-role primitive.
///
/// Frontier inspiration: MLIR's typed-attribute
/// `parseType(str) -> Optional<Type>` factory on the closed-set
/// typed-attribute registry — the same inverse-decode shape on
/// a Rust closed-set enum, where the (tag, typed variant)
/// decode binds at ONE typed factory rather than at every
/// downstream operation's parseAttribute callback. Racket's
/// `(assq tag tag-alist)` typed lookup over a closed
/// association list — the inverse decode projects through the
/// ALL array without hand-rolling a per-tag match; `Self::ALL
/// .iter().find(qf.iac_forge_tag() == tag)` is the Rust-typed
/// peer on the closed-set outer-[`QuoteForm`] algebra with the
/// ALL array standing in for Racket's typed association-list
/// spine.
#[must_use]
pub fn from_iac_forge_tag(tag: &str) -> Option<Self> {
Self::ALL
.iter()
.copied()
.find(|qf| qf.iac_forge_tag() == tag)
}
/// Project the typed marker into its matching [`crate::error::SexpShape`]
/// variant — `Quote → SexpShape::Quote`, `Quasiquote → SexpShape::Quasiquote`,
/// `Unquote → SexpShape::Unquote`, `UnquoteSplice → SexpShape::UnquoteSplice`.
/// ONE projection on the closed-set quote-family algebra the substrate's
/// outer-shape projection ([`crate::domain::sexp_shape`]) routes through
/// for the four quote-family arms — so the (Sexp variant, SexpShape
/// variant) pairing binds at ONE site on the typed algebra rather than
/// at four byte-identical inline arms in [`crate::domain::sexp_shape`].
///
/// The SIXTH consumer of the closed-set [`QuoteForm`] algebra, sibling
/// of [`Self::prefix`] (Display / reader prefix-string surface),
/// [`Self::hash_discriminator`] (Hash cache-key bytes surface),
/// [`Self::as_unquote_form`] (2-of-4 template-substitution subset gate),
/// [`Self::iac_forge_tag`] (cross-crate canonical-form tag surface), and
/// [`Self::wrap`] (reader's marker → `Sexp::*` constructor surface).
/// Composes with [`SexpShape::label`] to yield the short diagnostic
/// label string the substrate's `LispError::TypeMismatch.got` slot
/// renders — the (QuoteForm variant, SexpShape variant, short label)
/// triple binds end-to-end through the typed algebra so a regression
/// that drifts the short label silently between the typed marker and
/// the diagnostic surface is structurally impossible.
///
/// Bidirectional dual: the inverse projection
/// [`crate::error::SexpShape::as_quote_form`] (12→4, partial)
/// covers the 4-of-12 carving of [`SexpShape`] this embed reaches.
/// The pair `(QuoteForm::sexp_shape,
/// SexpShape::as_quote_form)` forms an `Iso(QuoteForm, QuoteShape ⊂
/// SexpShape)`: every typed marker round-trips through the embed
/// (`QuoteForm::sexp_shape(qf).as_quote_form() == Some(qf)` for
/// every `qf: QuoteForm`), every quote-shape pre-image recovers
/// the typed marker. The non-quote-family shapes (`Nil`, `List`,
/// every atomic-payload variant) form the kernel of the inverse —
/// `as_quote_form` returns `None` for them. See
/// [`crate::error::SexpShape::as_quote_form`]'s docstring for the
/// composition law's other direction + disjointness with the
/// atomic-payload sibling `SexpShape::as_atom_kind`.
///
/// Canonical [`SexpShape`] embed target for the [`Self::Quote`]
/// quote-family arm on the QuoteForm ⊂ SexpShape carving —
/// [`SexpShape::Quote`]. Per-role peer of `Self::Quote` on the
/// closed-set outer-shape embed axis; consumers with a `QuoteForm`
/// variant in hand at compile time bind the canonical embed target
/// through ONE typed `pub const` per role rather than through
/// runtime dispatch via [`Self::sexp_shape`] or by re-deriving the
/// QuoteForm ⊂ SexpShape variant pairing inline.
///
/// Sibling posture to [`Self::QUOTE_LABEL`] (the per-role
/// diagnostic label alias) and [`Self::QUOTE_HASH_DISCRIMINATOR`]
/// (the per-role outer-Sexp cache-key byte) on the closed-set
/// QuoteForm algebra — each closes a distinct per-role
/// sub-vocabulary axis on the QuoteForm carving. This constant
/// closes the FOURTH per-role axis on [`QuoteForm`] (the
/// `SexpShape`-embed axis, paired with the pre-existing
/// `&'static str` reader-prefix + diagnostic-label +
/// cross-crate iac-forge-tag axes AND the `u8` cache-key axis) at
/// ONE typed alias through the peer superset variant on the
/// [`SexpShape`] closed set.
///
/// Sibling posture to the peer 6-of-12 atomic-payload carving's
/// per-role SHAPE aliases ([`AtomKind::SYMBOL_SHAPE`] …
/// [`AtomKind::BOOL_SHAPE`] — every one an alias of its
/// [`SexpShape`] peer on the AtomKind ⊂ SexpShape 6-of-12
/// carving). Post-lift the SexpShape's per-carving embed-target
/// axis is uniformly surfaced through per-role `pub const *_SHAPE`
/// aliases on every sub-carving that carries a bidirectional
/// (embed, project) `Iso(_, _ ⊂ SexpShape)` — first `AtomKind` (6),
/// now `QuoteForm` (4).
pub const QUOTE_SHAPE: SexpShape = SexpShape::Quote;
/// Canonical [`SexpShape`] embed target for the [`Self::Quasiquote`]
/// quote-family arm on the QuoteForm ⊂ SexpShape carving —
/// [`SexpShape::Quasiquote`]. Per-role peer of `Self::Quasiquote`.
/// See [`Self::QUOTE_SHAPE`] for the alias-chain shape every
/// sibling shares.
pub const QUASIQUOTE_SHAPE: SexpShape = SexpShape::Quasiquote;
/// Canonical [`SexpShape`] embed target for the [`Self::Unquote`]
/// quote-family arm on the QuoteForm ⊂ SexpShape carving —
/// [`SexpShape::Unquote`]. Per-role peer of `Self::Unquote`.
pub const UNQUOTE_SHAPE: SexpShape = SexpShape::Unquote;
/// Canonical [`SexpShape`] embed target for the [`Self::UnquoteSplice`]
/// quote-family arm on the QuoteForm ⊂ SexpShape carving —
/// [`SexpShape::UnquoteSplice`]. Per-role peer of
/// `Self::UnquoteSplice`.
pub const UNQUOTE_SPLICE_SHAPE: SexpShape = SexpShape::UnquoteSplice;
/// Closed-set forced-arity ALL array over the canonical
/// [`SexpShape`] embed targets on the QuoteForm ⊂ SexpShape
/// 4-of-12 carving, in declaration order matching [`Self::ALL`]
/// element-wise (pinned by
/// `quote_form_shapes_align_with_all_by_index`). Sibling posture
/// to [`Self::LABELS`] (`[&'static str; 4]` — per-role diagnostic
/// bytes), [`Self::PREFIXES`] (`[&'static str; 4]` — per-role
/// reader-punctuation bytes), [`Self::IAC_FORGE_TAGS`] (`[&'static
/// str; 4]` — cross-crate iac-forge canonical-form tag bytes), and
/// [`Self::HASH_DISCRIMINATORS`] (`[u8; 4]` — per-role outer-Sexp
/// cache-key bytes) on the SAME closed-set QuoteForm algebra;
/// where those four arrays lift per-role `&'static str` and `u8`
/// sub-vocabularies onto the substrate, this array lifts the
/// per-role [`SexpShape`] embed-target sub-vocabulary at the same
/// `[_; 4]` forced arity.
///
/// Sibling posture to [`AtomKind::SHAPES`] (`[SexpShape; 6]`) —
/// the peer atomic-payload carving's family-wide embed-target
/// array on the AtomKind ⊂ SexpShape 6-of-12 carving. Together the
/// two `SHAPES` arrays cover the TWO bidirectional sub-carvings of
/// [`SexpShape`] (`Iso(AtomKind, AtomShape ⊂ SexpShape)` + `Iso(QuoteForm,
/// QuoteShape ⊂ SexpShape)`) — a family-wide sweep zipping every
/// carving's `ALL` + `SHAPES` in lockstep now closes over TWO
/// carvings' 10-of-12 embed targets at ONE typed pair-of-arrays
/// each.
///
/// Pre-lift the four [`SexpShape`] embed targets had NO per-role
/// primitive on this closed-set algebra — a consumer with a
/// `QuoteForm` variant in hand at compile time reaching for the
/// canonical embed target had to spell
/// `QuoteForm::Quote.sexp_shape()` (runtime dispatch through the
/// four-arm match body) OR re-derive the QuoteForm ⊂ SexpShape
/// variant pairing at the call site by importing both enums and
/// spelling `SexpShape::Quote` inline. Post-lift the FOUR canonical
/// embed targets bind at ONE `pub const` per role on the typed
/// [`QuoteForm`] algebra AND at [`Self::SHAPES`] as a family-wide
/// forced-arity array — a future LSP / REPL completion bar keyed
/// on `QuoteForm::SHAPES` for the "which SexpShape does this
/// QuoteForm embed into?" outer-shape column, a `tatara-check`
/// coverage sweep zipping `QuoteForm::ALL` / `LABELS` / `PREFIXES`
/// / `IAC_FORGE_TAGS` / `HASH_DISCRIMINATORS` / `SHAPES` in
/// lockstep for a family-wide (variant, label, prefix, iac-forge
/// tag, byte, embed-target) sextuple render, or a Sekiban
/// audit-trail metric jointly labeled by the embed-target's
/// SexpShape identity reads through the typed constants on this
/// subset algebra without re-deriving the 4-of-12 carving inline.
///
/// Round-trip identity with the inverse projection
/// [`crate::error::SexpShape::as_quote_form`]: for every index `i`,
/// `Self::SHAPES[i].as_quote_form() == Some(Self::ALL[i])`
/// (pinned by
/// `quote_form_shapes_align_with_all_by_index_through_as_quote_form`) —
/// the embed / project section closes as a family-wide array-
/// indexed law rather than as a per-variant assertion sweep.
/// Adding a hypothetical fifth quote-family wrapper (e.g. `,~`
/// reverse-unquote, `,?` conditional-unquote, `#'` Common-Lisp
/// function-quote) extends [`Self::ALL`] AND [`Self::SHAPES`] AND
/// [`SexpShape::ALL`] AND adds ONE per-role `pub const *_SHAPE` in
/// lockstep — rustc's forced-arity check on the two `[_; N]`
/// arrays fails compilation if EITHER ALL array grows without the
/// other, AND the peer [`SexpShape::as_quote_form`] arm must grow
/// in lockstep to preserve the round-trip identity.
///
/// Theory anchor: THEORY.md §III — the typescape; the four
/// canonical [`SexpShape`] embed targets bind at ONE typed
/// `[SexpShape; 4]` array on the closed-set QuoteForm algebra
/// rather than at zero-primitive-on-this-subset-plus-four-inline-
/// lookups scattered across the substrate. Closes the FOURTH
/// per-role `pub const` axis on the QuoteForm carving alongside
/// the pre-existing LABELS + PREFIXES + IAC_FORGE_TAGS +
/// HASH_DISCRIMINATORS axes. THEORY.md §V.1 — knowable platform;
/// the family's cardinality becomes a TYPE-level constant on the
/// substrate algebra rather than a per-consumer runtime dispatch
/// through the composition. THEORY.md §II.1 invariant 2 — free
/// middle; the (embed, project) pair binds at THREE typed sites
/// now — the projection method [`Self::sexp_shape`], this family-
/// wide array, AND the peer inverse
/// [`crate::error::SexpShape::as_quote_form`] — with rustc-enforced
/// consistency across all three. THEORY.md §VI.1 — generation
/// over composition; the family-wide contract sweeps (alignment
/// with `ALL`, round-trip through `as_quote_form`, membership
/// through `sexp_shape`, pairwise injectivity across the four
/// embed targets) emerge from the composition of TWO substrate
/// primitives (this `pub const` array + the four per-role
/// `pub const *_SHAPE` aliases) rather than as per-variant inline
/// assertions duplicated at each call site.
pub const SHAPES: [SexpShape; 4] = [
Self::QUOTE_SHAPE,
Self::QUASIQUOTE_SHAPE,
Self::UNQUOTE_SHAPE,
Self::UNQUOTE_SPLICE_SHAPE,
];
/// Project the typed marker into its matching [`crate::error::SexpShape`]
/// variant — `Quote → SexpShape::Quote`, `Quasiquote → SexpShape::Quasiquote`,
/// `Unquote → SexpShape::Unquote`, `UnquoteSplice → SexpShape::UnquoteSplice`.
/// ONE projection on the closed-set quote-family algebra the substrate's
/// outer-shape projection ([`crate::domain::sexp_shape`]) routes through
/// for the four quote-family arms — so the (Sexp variant, SexpShape
/// variant) pairing binds at ONE site on the typed algebra rather than
/// at four byte-identical inline arms in [`crate::domain::sexp_shape`].
///
/// The SIXTH consumer of the closed-set [`QuoteForm`] algebra, sibling
/// of [`Self::prefix`] (Display / reader prefix-string surface),
/// [`Self::hash_discriminator`] (Hash cache-key bytes surface),
/// [`Self::as_unquote_form`] (2-of-4 template-substitution subset gate),
/// [`Self::iac_forge_tag`] (cross-crate canonical-form tag surface), and
/// [`Self::wrap`] (reader's marker → `Sexp::*` constructor surface).
/// Composes with [`SexpShape::label`] to yield the short diagnostic
/// label string the substrate's `LispError::TypeMismatch.got` slot
/// renders — the (QuoteForm variant, SexpShape variant, short label)
/// triple binds end-to-end through the typed algebra so a regression
/// that drifts the short label silently between the typed marker and
/// the diagnostic surface is structurally impossible.
///
/// Each arm routes through the per-role `pub const` on `impl Self`
/// ([`Self::QUOTE_SHAPE`], [`Self::QUASIQUOTE_SHAPE`],
/// [`Self::UNQUOTE_SHAPE`], [`Self::UNQUOTE_SPLICE_SHAPE`]) so the
/// four canonical embed targets bind at ONE typed source of truth
/// per role rather than as inline `SexpShape::X` literals scattered
/// across the `match` body. Sibling posture to
/// [`AtomKind::sexp_shape`]'s post-lift routing through
/// [`AtomKind::SYMBOL_SHAPE`] … [`AtomKind::BOOL_SHAPE`] on the peer
/// 6-of-12 atomic-payload carving — the per-role `pub const *_SHAPE`
/// routing is now uniform across every sub-carving of [`SexpShape`]
/// that has a bidirectional (embed, project) isomorphism, closing
/// the (embed-target constant, embed-target array, projection
/// method) trio on each sub-carving in lockstep.
///
/// Post-lift routing pin
/// `quote_form_sexp_shape_routes_through_typed_per_role_constants`
/// catches a regression that re-inlines the four `SexpShape::X` arm
/// literals here and silently drifts ONE arm from the per-role
/// `pub const` alias — the routing agreement is a TYPED CONSEQUENCE
/// of the composition rather than literal discipline at two sites.
///
/// Bidirectional dual: the inverse projection
/// [`crate::error::SexpShape::as_quote_form`] (12→4, partial)
/// covers the 4-of-12 carving of [`SexpShape`] this embed reaches.
/// The pair `(QuoteForm::sexp_shape,
/// SexpShape::as_quote_form)` forms an `Iso(QuoteForm, QuoteShape ⊂
/// SexpShape)`: every typed marker round-trips through the embed
/// (`QuoteForm::sexp_shape(qf).as_quote_form() == Some(qf)` for
/// every `qf: QuoteForm`), every quote-shape pre-image recovers
/// the typed marker. The non-quote-family shapes (`Nil`, `List`,
/// every atomic-payload variant) form the kernel of the inverse —
/// `as_quote_form` returns `None` for them. See
/// [`crate::error::SexpShape::as_quote_form`]'s docstring for the
/// composition law's other direction + disjointness with the
/// atomic-payload sibling `SexpShape::as_atom_kind`.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (QuoteForm
/// variant, SexpShape variant) pairing becomes a TYPE projection on
/// the substrate algebra rather than four inline arms in
/// [`crate::domain::sexp_shape`]. A typo or swap at the shape-projection
/// site is no longer a runtime drift but a compile error against the
/// typed projection. THEORY.md §II.1 invariant 2 — free middle; SIX
/// consumers of the [`QuoteForm`] algebra now route through ONE typed
/// closed-set match family, so a regression that drifts ONE consumer's
/// pairing from the others cannot reach the substrate's runtime.
/// THEORY.md §VI.1 — generation over composition; the (Sexp variant,
/// SexpShape variant) pairing appeared at four arms in `sexp_shape` —
/// past the ≥2 PRIME-DIRECTIVE trigger once the structural shape is
/// named.
#[must_use]
pub fn sexp_shape(self) -> SexpShape {
match self {
Self::Quote => Self::QUOTE_SHAPE,
Self::Quasiquote => Self::QUASIQUOTE_SHAPE,
Self::Unquote => Self::UNQUOTE_SHAPE,
Self::UnquoteSplice => Self::UNQUOTE_SPLICE_SHAPE,
}
}
/// Project the typed marker to its canonical short diagnostic label —
/// `"quote"` for [`Self::Quote`], `"quasiquote"` for
/// [`Self::Quasiquote`], `"unquote"` for [`Self::Unquote`],
/// `"unquote-splice"` for [`Self::UnquoteSplice`]. Body composes
/// through `self.sexp_shape().label()` — routing through
/// [`Self::sexp_shape`] (the typed 4-of-12 outer-value → SexpShape
/// projection) then [`SexpShape::label`] (the canonical 12-arm
/// diagnostic-label projection) so the (QuoteForm variant, short
/// diagnostic string) pairing lives at ONE canonical site
/// ([`SexpShape::label`]'s four quote-family arms in `error.rs`)
/// rather than at four inline `&'static str` arms on the closed-set
/// `QuoteForm` algebra.
///
/// The outer-shape peer of [`crate::ast::Sexp::type_name`] one
/// algebra layer up (`self.shape().label()` on outer-`Sexp`) and of
/// [`crate::ast::Atom::label`] one algebra layer down
/// (`self.kind().label()` on outer-`Atom` through [`AtomKind`]).
/// Where `Atom::label` composes through the atomic-payload 6-of-12
/// carving via [`AtomKind`] into [`SexpShape::label`], this method
/// composes through the quote-family 4-of-12 carving directly onto
/// [`SexpShape::label`] — the (label, sexp_shape, hash_discriminator)
/// trio the outer-`Atom` algebra closed one lift back
/// (`Atom::hash_discriminator`, e49f550) is now mirrored on the
/// `QuoteForm` algebra: `prefix` (reader punctuation) and
/// `iac_forge_tag` (CL canonical form) key the SAME closed set on
/// their own boundaries, and `label` keys it on the substrate's
/// operator-facing diagnostic boundary.
///
/// Composition law: `qf.label() == qf.sexp_shape().label()` for every
/// `qf: QuoteForm`. Pinned by
/// `quote_form_label_composes_through_sexp_shape_label_for_every_variant`
/// across all four variants — the pin asserts pointer-equality on the
/// returned `&'static str` so a regression that re-inlines the four
/// literals here (and gains its own drift surface separate from the
/// canonical [`SexpShape::label`] site) surfaces immediately. Sibling
/// of `atom_label_composes_through_kind_label_for_every_variant` one
/// algebra layer down (on the outer-`Atom` value / `AtomKind` marker
/// pair) and
/// `sexp_type_name_method_composes_through_shape_label_for_every_outer_shape`
/// one algebra layer up (on the outer-`Sexp` value / `SexpShape`
/// marker pair).
///
/// Cross-algebra agreement law: for every `qf: QuoteForm` and every
/// `inner: Sexp`, `qf.label() == qf.wrap(inner).type_name()`. The
/// (QuoteForm variant, canonical label) pairing lands at the SAME
/// `&'static str` regardless of whether the consumer holds the typed
/// marker directly or an outer-`Sexp` wrapper produced from
/// [`Self::wrap`] — so a regression that drifts one algebra layer's
/// label from the other (a `QuoteForm::label` re-inlined onto a
/// different literal, a `Sexp::type_name` re-routed through a stale
/// shape projection, a `QuoteForm::sexp_shape` arm that swaps two
/// markers) fails-loudly here rather than as a silent operator-facing
/// diagnostic drift at every consumer that pattern-matches on the
/// outer-`Sexp` label vs the outer-`QuoteForm` label independently.
/// Pinned by `quote_form_label_agrees_with_sexp_type_name_at_every_quote_form_arm`.
///
/// Divergence law (boundary distinction with [`Self::iac_forge_tag`]):
/// at the [`Self::UnquoteSplice`] arm, `qf.label() == "unquote-splice"`
/// while `qf.iac_forge_tag() == "unquote-splicing"`. The two
/// projections key the SAME closed-set on TWO distinct boundaries
/// (substrate diagnostic surface vs cross-crate CL canonical form)
/// and their intentional divergence at the `Splice` arm is pinned by
/// `quote_form_label_diverges_from_iac_forge_tag_for_unquote_splice`
/// — sibling posture to
/// `quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice`
/// which pinned the divergence at the `sexp_shape().label()`
/// composition; this pin lifts the divergence contract onto the new
/// typed peer.
///
/// The `&'static str` lifetime is load-bearing: every future consumer
/// with a `QuoteForm` in hand wanting the substrate's short
/// diagnostic string projects through this method into the
/// `LispError::TypeMismatch.got` slot / REPL / LSP surface without an
/// allocation, parallel to how [`Self::prefix`] projects the reader
/// punctuation and [`Self::iac_forge_tag`] projects the CL canonical
/// tag. A future homoiconic prefix-wrapper (e.g. hypothetical `,~`
/// reverse-unquote) extends [`Self`] AND [`SexpShape::label`]
/// together — rustc binds the diagnostic surface to the algebra
/// through the closed-set composition without touching this method.
///
/// Theory anchor: THEORY.md §V.1 — knowable platform; the (QuoteForm
/// variant, canonical short label) pairing becomes a TYPE projection
/// on the substrate algebra composed through the pre-existing outer-
/// shape projection, rather than at a per-callsite
/// `.sexp_shape().label()` two-hop the load-bearing pin already
/// carries as a composition-law contract. THEORY.md §II.1 invariant 2
/// — free middle; the outer-`QuoteForm` diagnostic-label algebra now
/// closes over THREE typed layers (`QuoteForm` → [`SexpShape`] →
/// `&'static str`) with rustc-enforced consistency across each — a
/// regression that drifts ONE layer's mapping from the others cannot
/// reach the substrate's runtime typed-witness surface,
/// `LispError::TypeMismatch.got` slot, or [`crate::error::SexpWitness::shape`]
/// projection. THEORY.md §VI.1 — generation over composition; the
/// outer-value diagnostic-label projection is the missing algebra
/// layer between the outer `QuoteForm` and the pre-existing marker-
/// level label projection — the two pre-existing typed layers become
/// a full THREE-layer typed composition through ONE new named
/// projection, closing the (prefix, iac_forge_tag, sexp_shape,
/// hash_discriminator, label) quintet on the outer-`QuoteForm`
/// algebra.
///
/// Frontier inspiration: MLIR's `mlir::OperationName::getStringRef()`
/// composed with an op-family typed projection — narrowing a
/// closed-set op-family value through its typed identity yields the
/// canonical diagnostic string identity in ONE typed composition on
/// the op-family algebra. Translated through the substrate's
/// [`QuoteForm`] outer-marker algebra, `qf.sexp_shape().label()`
/// closes the (typed marker, canonical diagnostic label) pairing at
/// ONE typed projection on the marker algebra composed through the
/// outer-shape's per-carving canonical site. Racket's `(quote-kind
/// qf)` composed with `(kind-label kind)` on the quote-family
/// taxonomy — the typed diagnostic label emerges from a two-hop
/// composition on the closed-set marker through the typed outer-shape
/// identity. `QuoteForm::label` is the Rust-typed peer on the
/// closed-set outer-[`QuoteForm`] algebra with [`SexpShape`] standing
/// in for Racket's quote-family taxonomy.
#[must_use]
pub fn label(self) -> &'static str {
self.sexp_shape().label()
}
/// Canonical `&'static str` bytes for the [`Self::Quote`] quote-family
/// marker — aliases [`SexpShape::QUOTE_LABEL`] on the QuoteForm ⊂
/// SexpShape carving so the marker-level per-role bytes bind at ONE
/// `pub const` on the parent superset's quote-family arm rather than
/// at TWO sites (the per-role `pub const` AND a parallel inline
/// literal). Per-role peer of `Self::Quote` on the closed-set quote-
/// family algebra; consumers reach for `QuoteForm::QUOTE_LABEL` when
/// the caller has a variant in hand at compile time and wants the
/// canonical diagnostic bytes without runtime dispatch through
/// [`Self::label`].
///
/// Sibling posture to the peer 6-of-12 atomic-payload carving's per-
/// role LABEL aliases ([`crate::ast::AtomKind::SYMBOL_LABEL`] …
/// [`crate::ast::AtomKind::BOOL_LABEL`] — every one an alias of its
/// [`SexpShape`] peer) and the peer 2-of-12 structural-residual
/// carving's per-role LABEL aliases
/// ([`crate::error::StructuralKind::NIL_LABEL`] +
/// [`crate::error::StructuralKind::LIST_LABEL`]) — this closes the
/// fourth and final closed-set sub-carving of [`SexpShape`] whose
/// per-role diagnostic-label bytes are surfaced through the same
/// alias-chain shape rather than reachable only through the
/// composition [`Self::sexp_shape`] + [`SexpShape::label`]. Every
/// SexpShape sub-carving (atomic payload, quote family, structural
/// residual) now exposes its per-role LABEL bytes at ONE `pub const`
/// per role on its subset algebra AS WELL AS at the parent
/// superset's `SexpShape::*_LABEL`.
///
/// The prefix-family peer of THIS `&'static str` constant is
/// [`Self::QUOTE_PREFIX`] (`"'"` — reader-punctuation byte); the
/// canonical-form peer is [`Self::QUOTE_IAC_FORGE_TAG`] (`"quote"` —
/// cross-crate iac-forge tag). At the `Quote` arm the label and
/// the iac-forge tag agree byte-for-byte (`"quote"`); the divergence
/// axis lives at [`Self::UNQUOTE_SPLICE_LABEL`] (`"unquote-splice"`)
/// vs [`Self::UNQUOTE_SPLICE_IAC_FORGE_TAG`] (`"unquote-splicing"`).
/// The three parallel per-role `pub const` families (prefix, label,
/// iac-forge tag) close the (reader, diagnostic, canonical-form)
/// triple on the outer-`QuoteForm` algebra.
pub const QUOTE_LABEL: &'static str = SexpShape::QUOTE_LABEL;
/// Canonical `&'static str` bytes for the [`Self::Quasiquote`] quote-
/// family marker — aliases [`SexpShape::QUASIQUOTE_LABEL`] on the
/// QuoteForm ⊂ SexpShape carving. Per-role peer of `Self::Quasiquote`.
/// See [`Self::QUOTE_LABEL`] for the alias-chain shape every sibling
/// shares.
pub const QUASIQUOTE_LABEL: &'static str = SexpShape::QUASIQUOTE_LABEL;
/// Canonical `&'static str` bytes for the [`Self::Unquote`] quote-
/// family marker — aliases [`SexpShape::UNQUOTE_LABEL`] on the
/// QuoteForm ⊂ SexpShape carving. Per-role peer of `Self::Unquote`.
/// See [`Self::QUOTE_LABEL`] for the alias-chain shape every sibling
/// shares.
pub const UNQUOTE_LABEL: &'static str = SexpShape::UNQUOTE_LABEL;
/// Canonical `&'static str` bytes for the [`Self::UnquoteSplice`]
/// quote-family marker — aliases [`SexpShape::UNQUOTE_SPLICE_LABEL`]
/// on the QuoteForm ⊂ SexpShape carving. Per-role peer of
/// `Self::UnquoteSplice`; the `"unquote-splice"` short label matches
/// [`SexpShape::UNQUOTE_SPLICE_LABEL`] byte-for-byte and diverges
/// INTENTIONALLY from [`Self::UNQUOTE_SPLICE_IAC_FORGE_TAG`]
/// (`"unquote-splicing"`) — the two projections key the SAME closed
/// set on TWO distinct boundaries (substrate diagnostic surface vs
/// cross-crate Common-Lisp canonical form). The divergence is pinned
/// by `quote_form_label_diverges_from_iac_forge_tag_for_unquote_splice`
/// on the runtime projection and by the byte-equality pins on THIS
/// constant vs its iac-forge peer on the per-role `pub const`
/// surface. See [`Self::QUOTE_LABEL`] for the alias-chain shape
/// every sibling shares.
pub const UNQUOTE_SPLICE_LABEL: &'static str = SexpShape::UNQUOTE_SPLICE_LABEL;
/// Closed-set forced-arity ALL array over the canonical quote-family
/// marker `&'static str` bytes, in declaration order matching
/// [`Self::ALL`] element-wise (pinned by
/// `quote_form_labels_align_with_all_by_index`). Sibling posture to
/// [`crate::error::SexpShape::LABELS`] (`[&'static str; 12]` — the
/// superset carving this QuoteForm subset embeds into),
/// [`crate::ast::AtomKind::LABELS`] (`[&'static str; 6]` — the peer
/// 6-of-12 atomic-payload carving's ALL array),
/// [`crate::error::StructuralKind::LABELS`] (`[&'static str; 2]` —
/// the peer 2-of-12 structural-residual carving's ALL array),
/// [`Self::PREFIXES`] (`[&'static str; 4]` — reader-prefix axis on
/// this same algebra), and [`Self::IAC_FORGE_TAGS`]
/// (`[&'static str; 4]` — canonical-form tag axis on this same
/// algebra) — every closed-set outer projection on the substrate
/// that carries an `&'static str`-per-variant label now pins its
/// per-role canonical bytes at ONE `pub const` per role PLUS an ALL
/// array for family-wide consumers.
///
/// Pre-lift the four quote-family marker labels had NO per-role
/// primitive on this closed-set algebra — a consumer with a
/// [`QuoteForm`] variant in hand at compile time reaching for the
/// canonical diagnostic bytes had to spell `QuoteForm::Quote.label()`
/// (runtime dispatch through the composition [`Self::sexp_shape`] +
/// [`SexpShape::label`]) OR reach across the algebra boundary into
/// [`SexpShape::QUOTE_LABEL`] and re-derive the QuoteForm ⊂
/// SexpShape variant pairing at the call site. Post-lift the FOUR
/// canonical labels bind at ONE `pub const` per role on the typed
/// [`QuoteForm`] algebra AND at [`Self::LABELS`] as a family-wide
/// forced-arity array — a future LSP / REPL completion bar keyed on
/// `QuoteForm::LABELS` for the "quote-family" carving-axis column,
/// a `tatara-check` coverage sweep over the quote-family arms of a
/// `TypeMismatch.got` corpus, or a Sekiban audit-trail metric
/// jointly labeled by the quote-family marker
/// (`tatara_lisp_quote_family_label_total{label="quote"}`) reads
/// through the typed constants on this subset algebra without re-
/// deriving the 4-of-12 carving inline OR reaching across into the
/// superset's twelve-entry `SexpShape::LABELS` array + filtering.
///
/// Each entry is byte-for-byte identical to the corresponding
/// [`SexpShape`] quote-family arm — an intentional cross-axis
/// overlap pinned by
/// `quote_form_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte`
/// so a future label rename on EITHER side (a `SexpShape`
/// `"quote"` → `"cite"` drift, a `QuoteForm` rename that skips the
/// alias, a hypothetical Racket-compat swap of `"quasiquote"`)
/// fails-loudly at the alias test rather than as a silent operator-
/// facing vocabulary fracture. Adding a hypothetical fifth
/// homoiconic prefix-wrapper (a `,~` reverse-unquote, a `,?`
/// conditional-unquote, a `#'` Common-Lisp function-quote) extends
/// [`Self::ALL`] AND [`Self::LABELS`] AND adds ONE per-role
/// `pub const` alias in lockstep — rustc's forced-arity check on
/// the two `[_; N]` arrays fails compilation if EITHER ALL array
/// grows without the other.
///
/// Theory anchor: THEORY.md §III — the typescape; the four
/// canonical quote-family marker labels bind at ONE typed
/// `[&'static str; 4]` array on the closed-set [`QuoteForm`]
/// algebra rather than at zero-primitive-on-this-subset-plus-four-
/// inline-lookups scattered across the substrate. Closes the
/// fourth SexpShape sub-carving's per-role LABEL parity with
/// [`AtomKind`] and [`crate::error::StructuralKind`]. THEORY.md
/// §V.1 — knowable platform; the family's cardinality becomes a
/// TYPE-level constant on the substrate algebra rather than a per-
/// consumer runtime dispatch through the composition. The alias-
/// chain shape is load-bearing: a [`SexpShape`]-side rename
/// propagates through the const-eval alias chain byte-for-byte
/// without silent drift. THEORY.md §VI.1 — generation over
/// composition; the family-wide contract sweeps (alignment with
/// [`Self::ALL`], pairwise disjointness, membership through
/// [`Self::label`]) emerge from the composition of TWO substrate
/// primitives (this `pub const` array + the four per-role
/// `pub const *_LABEL` aliases) rather than as per-variant inline
/// assertions duplicated at each call site. THEORY.md §II.1
/// invariant 5 — composition preserves proofs; the alias-chain
/// composition law `QuoteForm::LABELS[i] ==
/// QuoteForm::ALL[i].sexp_shape().label()` binds the family-wide
/// array to the composition through [`Self::sexp_shape`] +
/// [`SexpShape::label`] at rustc time.
pub const LABELS: [&'static str; 4] = [
Self::QUOTE_LABEL,
Self::QUASIQUOTE_LABEL,
Self::UNQUOTE_LABEL,
Self::UNQUOTE_SPLICE_LABEL,
];
/// Project the typed marker back into its matching `Sexp::*` wrapper
/// variant applied to `inner` — the structural inverse of
/// [`crate::ast::Sexp::as_quote_form`]. [`Self::Quote`] yields
/// [`Sexp::Quote`], [`Self::Quasiquote`] yields [`Sexp::Quasiquote`],
/// [`Self::Unquote`] yields [`Sexp::Unquote`], [`Self::UnquoteSplice`]
/// yields [`Sexp::UnquoteSplice`], each boxing `inner` into the
/// corresponding tuple-variant constructor (`fn(Box<Sexp>) -> Sexp`).
///
/// Round-trip identity with [`crate::ast::Sexp::as_quote_form`] — the
/// structural law every consumer can pin against:
///
/// ```ignore
/// // for every (qf, inner): qf.wrap(inner.clone()).as_quote_form() == Some((qf, &inner))
/// // for every Sexp s matching the quote family:
/// // let (qf, inner) = s.as_quote_form().unwrap();
/// // qf.wrap(inner.clone()) == s
/// ```
///
/// Consumer: [`crate::reader::read_quoted`] — the FIFTH consumer site
/// of the closed-set `QuoteForm` algebra (sibling to `Hash for Sexp`'s
/// `hash_discriminator` arm, `Display for Sexp`'s `prefix` arm,
/// `Sexp::as_unquote`'s `as_unquote_form` subset-gate composition, and
/// the feature-gated `From<&Sexp> for iac_forge::SExpr`'s
/// `iac_forge_tag` arm). Pre-lift the reader's parse dispatch carried
/// its own parallel closed set: a local `Token::{Quote, Quasiquote,
/// Unquote, UnquoteSplice}` enum paired with the matching `Sexp::*`
/// tuple-variant constructors threaded as `fn(Box<Sexp>) -> Sexp`
/// arguments to `read_quoted`. The (Token variant, Sexp::* constructor)
/// pairing was load-bearing yet only enforced by callsite discipline
/// at the FIFTH consumer site the prior `QuoteForm` lifts did not
/// reach — a regression that swapped `Sexp::Quote` and
/// `Sexp::Quasiquote` between the parser arms type-checked but
/// silently corrupted every program's quote-family parse.
///
/// Post-lift the reader's `Token` collapses to ONE typed variant
/// `Token::Quoted(QuoteForm)`, the parser's four prefix arms collapse
/// to ONE arm `Some((Token::Quoted(qf), _)) => read_quoted(it,
/// eof_pos, qf)`, and `read_quoted` routes through this projection to
/// produce the matching `Sexp::*` variant. The (QuoteForm variant,
/// Sexp::* constructor) pairing now binds at ONE site on the typed
/// algebra — rustc enforces exhaustiveness across [`Self`]'s closed
/// set, so a regression that drifts the (marker, constructor) pair
/// becomes a typed compile error rather than a silent program-text
/// corruption.
///
/// The `Sexp` (owned) return type complements [`Sexp::as_quote_form`]'s
/// `&Sexp` (borrowed) — `wrap` consumes the inner body to build the
/// new wrapper, `as_quote_form` borrows the inner body from the
/// existing wrapper. The asymmetry is intentional: at the reader's
/// parse-then-wrap boundary the inner is fresh from `parse(...)?` and
/// has no caller-owned binding; the typed `Box::new(inner)` allocation
/// lives at ONE site rather than four (one per pre-lift parser arm),
/// so a future allocation-policy change (e.g. arena-allocated wrappers
/// for span-aware Sexp) lands as ONE edit.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// reader's prefix-token → Sexp-wrapper gate IS the rust-level
/// typed-entry gate at the source-text boundary, and naming the
/// typed projection from [`QuoteForm`] back to the `Sexp::*` wrapper
/// lifts the gate from per-arm constructor literals to ONE method
/// the closed-set algebra owns — parallel to how [`Self::prefix`]
/// lifts the Display↔reader prefix-string surface. THEORY.md §II.1
/// invariant 2 — free middle; ALL FIVE consumers (Hash, Display,
/// as_unquote, iac-forge interop, reader's parse) now route through
/// the SAME closed-set algebra so a regression that drifts ONE
/// consumer's pairing from the others cannot reach the substrate's
/// runtime. THEORY.md §V.1 — knowable platform; the (QuoteForm
/// variant, Sexp::* constructor) pairing becomes a TYPE projection on
/// the substrate algebra rather than four `fn(Box<Sexp>) -> Sexp`
/// function pointers threaded as call arguments. A typo or
/// swap is no longer a runtime drift but a compile error against the
/// typed projection. THEORY.md §VI.1 — generation over composition;
/// the (QuoteForm variant, Sexp::* constructor) pairing appeared at
/// the four reader arms — past the ≥2 PRIME-DIRECTIVE trigger once
/// the structural shape is named. The typed projection lands the
/// structural-completeness floor for the reader's quote-family
/// surface, completing the FIVE-consumer closure of the
/// `QuoteForm` algebra.
#[must_use]
pub fn wrap(self, inner: Sexp) -> Sexp {
let boxed = Box::new(inner);
match self {
Self::Quote => Sexp::Quote(boxed),
Self::Quasiquote => Sexp::Quasiquote(boxed),
Self::Unquote => Sexp::Unquote(boxed),
Self::UnquoteSplice => Sexp::UnquoteSplice(boxed),
}
}
}
// `impl fmt::Display for QuoteForm` is generated by
// `#[derive(tatara_closed_set::DeriveClosedSet)]` + `#[closed_set(display)]` on
// the enum declaration above — emits the substrate-wide
// `f.write_str(Self::prefix(*self))` block byte-for-byte.
// `impl std::str::FromStr for QuoteForm` + `impl tatara_closed_set::ClosedSet for
// QuoteForm` + `pub struct UnknownQuoteForm(pub String)` are generated by
// `#[derive(tatara_closed_set::DeriveClosedSet)]` on the enum declaration
// above. `label` delegates to the inherent `QuoteForm::prefix` via
// `#[closed_set(via = "prefix")]` so the domain-canonical
// reader-punctuation projection (`"'" / "`" / "," / ",@"`) stays
// load-bearing at the inherent surface while the trait surface unifies
// every closed-set implementor's projection name onto `label`.
// `#[closed_set(generate_unknown = "quote form")]` emits the typed
// parse-rejection carrier with the substrate-wide `Debug + Clone +
// PartialEq + Eq + thiserror::Error` derives and the `#[error("unknown
// quote form: {0}")]` annotation byte-for-byte; the explicit label pins
// the pre-lift wording even though the auto-derived
// `pascal_to_spaced_lowercase("QuoteForm")` projects to the same
// `"quote form"` literal. The FromStr decode is a linear sweep over
// `QuoteForm::ALL` keyed on `prefix`: every successful decode round-trips
// through `prefix()`, cross-axis labels from `SexpShape` (`"quote" /
// "quasiquote" / ...`) and `iac_forge_tag` (`"unquote-splicing"`) reject —
// pinned by `quote_form_prefix_round_trips_through_from_str` +
// `quote_form_from_str_rejects_sexp_shape_labels_on_homoiconic_prefix_axis`.
/// Iterate over the argument tails of every form in `forms` whose call head
/// matches `keyword` — the *slice-side* sibling of [`Sexp::as_call_to`].
/// Where [`Sexp::as_call_to`] answers "is THIS form a call to `K`, and what
/// are its arguments?" on ONE form, `iter_calls_to` answers "which forms
/// in this SLICE are calls to `K`, and what are their arguments?" on a
/// `&[Sexp]`. Yields `&[Sexp]` for each matching form's argument tail
/// (`&form_list[1..]`, the empty slice for a singleton call like `(K)`);
/// non-matching forms — every shape [`Sexp::as_call_to`] rejects — are
/// skipped silently, matching the soft-projection posture the per-form
/// sibling carries.
///
/// Two consumers in [`compile.rs`](crate::compile) route through this
/// primitive:
/// * [`compile_typed::<T>`](crate::compile::compile_typed) — walks every
/// expanded top-level form and compiles every `(T::KEYWORD :k v …)`
/// form into a typed `T`.
/// * [`compile_named_from_forms::<T>`](crate::compile::compile_named_from_forms)
/// — walks every expanded form and compiles every
/// `(T::KEYWORD NAME :k v …)` form into a [`NamedDefinition<T>`](crate::compile::NamedDefinition).
///
/// Before this lift both consumers opened the same `for form in &expanded
/// { if let Some(args) = form.as_call_to(T::KEYWORD) { … } }` walk inline
/// — well past the ≥2 PRIME-DIRECTIVE trigger once the per-form sibling
/// had a name. After this lift the walk lives in ONE function the two
/// dispatchers route through; a regression that drifts ONE consumer's
/// walk from the other (a future emitter that inlines a partial filter,
/// a debug-mode logger that loses track of non-matching forms, a span-
/// aware walk that threads a borrowed `&Sexp` position alongside the
/// tail) becomes structurally impossible because there is exactly ONE
/// implementation both dispatchers consume. A future authoring tool
/// (LSP / REPL / `tatara-check`) that wants to surface "which forms in
/// this program invoke `K`?" binds to ONE function on the slice algebra
/// instead of re-deriving the walk per consumer.
///
/// Closes the soft-dispatch family at the slice level: the per-form
/// projections `{head_symbol, as_call, as_call_to, as_call_to_any}` each
/// answer "what does THIS form's head say?", and the slice-side
/// `iter_calls_to` extends them to "what do THESE forms' heads say,
/// projected through one keyword?". Typed-decoded sibling on the
/// slice algebra: [`iter_calls_to_any`] — the closure-typed extension
/// of THIS function the same way [`Sexp::as_call_to_any`] extends
/// [`Sexp::as_call_to`] on the per-form algebra. The (per-form,
/// slice-side) × (keyword, classifier) 2×2 of soft-dispatch
/// primitives is closed at the slice corner this lift establishes;
/// the closed-form composition binding the slice-side projection to
/// its per-form sibling is the structural identity every consumer
/// can pin against:
///
/// ```ignore
/// iter_calls_to(forms, k) == forms.iter().filter_map(|f| f.as_call_to(k))
/// ```
///
/// Post-lift `iter_calls_to`'s body composes
/// [`iter_calls_to_any`] with a keyword-equality decoder
/// (`|h| (h == keyword).then_some(())`) and drops the decoded unit, so
/// the keyword-typed slice walk IS the typed-decoded slice walk
/// restricted to a constant-keyword classifier. The (slice-side
/// keyword projection, slice-side typed-decoded projection) pair
/// binds at ONE filter-and-fuse implementation on the algebra
/// rather than at two parallel `forms.iter().filter_map(_)` triples
/// that the type system would not catch when one drifts from the
/// other (a future emitter that adds debug logging at one site but
/// not the other, a future span-aware walk that threads borrowed
/// positional metadata through one site but skips the other).
///
/// The yielded `&[Sexp]` slices borrow `&forms[i][1..]` verbatim — no
/// copy, no allocation, same lifetime as [`Sexp::as_call_to`]'s tail.
/// The iterator's lifetime `'a` is the unified outer lifetime of `forms`
/// AND `keyword`: the keyword string must outlive the iterator's borrow
/// of the slice (typical caller passes `T::KEYWORD: &'static str`, which
/// unifies trivially; a caller passing a locally-allocated `&str` ties
/// the iterator to that local). The closure captures `keyword` by move
/// (the `move` keyword on the `filter_map` closure), so each invocation
/// re-derives the head comparison via [`Sexp::as_call_to`]'s `head ==
/// keyword` check at every form — no shared-state, fully Iterator-fused.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// two-site `for + as_call_to` inline walk is past the ≥2 PRIME-DIRECTIVE
/// trigger once the per-form sibling has a name. THEORY.md §V.1 —
/// knowable platform / "make invalid states unrepresentable"; the
/// slice-side projection becomes a NAMED primitive on the substrate's
/// `&[Sexp]` algebra rather than a re-derived for-loop at every consumer
/// site, so authoring tools (REPL, LSP, `tatara-check`) bind to ONE
/// function instead of re-implementing the walk. THEORY.md §II.1
/// invariant 1 — typed entry; the typed-keyword filter on a slice IS the
/// rust-level typed-entry-batch gate (the batch sibling of `as_call_to`'s
/// per-form gate), and naming its single shape lifts the gate from
/// two-site duplication to one rust function the substrate's diagnostic
/// promotions hang off of. THEORY.md §II.1 invariant 2 — free middle;
/// both dispatchers route through the SAME projection, so a regression
/// that drifts one consumer's walk from the other cannot reach the
/// substrate's runtime: the type system binds every consumer to the
/// projection's single emission shape.
///
/// Frontier inspiration: MLIR's `op.getOps<NamedOp>()` — every rewrite
/// pattern over a typed-op block binds to ONE typed-filter iterator
/// regardless of whether it's matching one op kind or batching across a
/// region's contents; the substrate's `iter_calls_to` is the
/// unstructured-projection peer of that iterator, lifted onto the
/// substrate's typed `&[Sexp]` algebra. Racket's `syntax-parse`
/// `~seq (defmacro id args …) …` ellipsis-form — the slice-level
/// matched-keyword filter is the closed-form sibling of `~seq`'s
/// repeated-pattern matcher, translated through pleme-io primitives as
/// ONE `iter_calls_to(forms, keyword)` projection. Tree-sitter's
/// `Query::matches` over a node sequence — the same "iterate the
/// matched forms in a parent" projection, inherited here for the typed
/// `Sexp` algebra without a new IR layer.
pub fn iter_calls_to<'a>(
forms: &'a [Sexp],
keyword: &'a str,
) -> impl Iterator<Item = &'a [Sexp]> + 'a {
iter_calls_to_any(forms, move |h| (h == keyword).then_some(())).map(|(_, args)| args)
}
/// Iterate over the `(decoded, args)` pairs of every form in `forms` whose
/// call head decodes through `decode` — the *slice-side* sibling of
/// [`Sexp::as_call_to_any`]. Where [`Sexp::as_call_to_any`] answers "is
/// THIS form a call whose head decodes through `F`, and what are its
/// arguments?" on ONE form, `iter_calls_to_any` answers "which forms in
/// this SLICE are calls whose heads decode through `F`, and what do they
/// decode to alongside their arguments?" on a `&[Sexp]`. Yields
/// `(decoded, &[Sexp])` for each matching form — the decoded typed
/// witness alongside the matched form's argument tail (`&form_list[1..]`,
/// the empty slice for a singleton call like `(K)`); non-matching forms
/// — every shape [`Sexp::as_call_to_any`] rejects, including calls whose
/// head is present but `decode` returns `None` for — are skipped silently,
/// matching the soft-projection posture the per-form sibling carries.
///
/// Closes the soft-dispatch family at the slice corner this lift
/// establishes — the (per-form, slice-side) × (keyword, classifier) 2×2
/// of soft-dispatch primitives on the `Sexp`/`&[Sexp]` algebras:
///
/// | | per-form | slice-side |
/// |----------------|-----------------------|--------------------------|
/// | keyword | [`Sexp::as_call_to`] | [`iter_calls_to`] |
/// | classifier `F` | [`Sexp::as_call_to_any`] | `iter_calls_to_any` (this) |
///
/// The keyword corner is the constant-classifier projection of the
/// classifier corner: [`iter_calls_to`] now composes through THIS
/// primitive with a `move |h| (h == keyword).then_some(())` decoder
/// and drops the decoded unit, parallel to how
/// `Sexp::as_call_to(k) == Sexp::as_call_to_any(|h| (h ==
/// k).then_some(())).map(|(_, a)| a)` (modulo the discarded `()`) on
/// the per-form algebra. The slice-side filter-and-fuse implementation
/// now lives at ONE site, so a regression that drifts a debug-logging
/// instrumentation, span-aware borrow threading, or fused-iterator
/// invariant from one slice consumer to the other becomes
/// structurally impossible.
///
/// Two plausible future consumer shapes the typed-decoded slice walk
/// admits with no boilerplate:
/// * **Closed-set classifier** — `iter_calls_to_any(forms,
/// MacroDefHead::from_keyword)` walks a slice yielding `(head: MacroDefHead,
/// args: &[Sexp])` for every `(defmacro …)` / `(defpoint-template …)`
/// / `(defcheck …)` form, decoded to the typed `MacroDefHead` enum.
/// Future LSP / `tatara-check` consumers that surface "every
/// defmacro-family form in this buffer with its kind tag" bind to
/// ONE projection rather than a hand-rolled
/// `forms.iter().filter_map(|f| f.as_call_to_any(MacroDefHead::from_keyword))`
/// triple at each consumer site.
/// * **Live-registry classifier** — `iter_calls_to_any(forms, |h|
/// registry.get(h))` walks a slice yielding `(handler: &Handler,
/// args: &[Sexp])` for every form whose head matches a runtime
/// registry. Future REPL / `tatara-check` consumers that route
/// every form through a registry dispatcher bind to ONE
/// projection rather than re-deriving the `filter_map` pattern
/// per consumer surface — sibling shape to
/// [`Expander::expand`](crate::macro_expand::Expander::expand)'s
/// per-form `as_call_to_any(|h| self.macros.get(h))` macro-call
/// dispatch, lifted onto the slice algebra so a batch walk picks
/// up the same dispatch shape without re-derivation.
///
/// The closed-form composition binding the slice-side projection to
/// its per-form sibling is the structural identity every consumer can
/// pin against:
///
/// ```ignore
/// iter_calls_to_any(forms, decode) ==
/// forms.iter().filter_map(|f| f.as_call_to_any(&mut decode))
/// ```
///
/// The yielded `&[Sexp]` slices borrow `&forms[i][1..]` verbatim — no
/// copy, no allocation, same lifetime as [`Sexp::as_call_to_any`]'s
/// tail. `T` is owned because `decode` is `FnMut(&str) -> Option<T>`
/// and a `&'_ str` borrow into the head symbol would not outlive the
/// helper boundary; consumers projecting to a typed `Copy` enum
/// (e.g. `MacroDefHead`) get the value directly per form, consumers
/// projecting to a borrowed `&'static str` (a closed-set head)
/// project to `&'static str` and inherit the static lifetime through
/// the classifier. The closure is `FnMut` (rather than the per-form
/// sibling's `FnOnce`) because the slice walk calls it once per form
/// — a closure that captures mutable state (a counter, a registry
/// cache) maintains that state across the batch walk; a closure with
/// no mutable state is admitted trivially.
///
/// The iterator's lifetime `'a` unifies `forms`'s borrow lifetime
/// with the closure `F`'s captures lifetime: the decoder must outlive
/// the iterator's borrow of the slice, the typical caller passes a
/// `'static` decoder (a `fn` item like `MacroDefHead::from_keyword`,
/// or a closure capturing nothing) which unifies trivially. The
/// closure captures `decode` by move (the `move` keyword on the
/// `filter_map` closure), so each invocation re-borrows it as
/// `&mut decode` and calls [`Sexp::as_call_to_any`] with a fresh
/// `FnOnce`-coerced borrow — no shared-state hazard, fully
/// Iterator-fused.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// per-form classifier sibling [`Sexp::as_call_to_any`] has two
/// production consumers (`macro_def_from` via closed-set classifier
/// `MacroDefHead::from_keyword`, `Expander::expand` via live-registry
/// classifier `|h| self.macros.get(h)`) — past the ≥2 PRIME-DIRECTIVE
/// trigger once the slice-side projection is named. Future
/// authoring-tool surfaces (LSP buffer walks, `tatara-check` batch
/// dispatchers, REPL exhaustive listers) join the family without
/// re-deriving the `filter_map(|f| f.as_call_to_any(_))` triple per
/// consumer. THEORY.md §V.1 — knowable platform; the slice-side
/// typed-decoded projection becomes a NAMED primitive on the
/// substrate's `&[Sexp]` algebra, closing the 2×2 of soft-dispatch
/// primitives the per-form algebra already establishes. THEORY.md
/// §II.1 invariant 2 — free middle; the slice-side keyword filter
/// ([`iter_calls_to`]) now routes through the slice-side classifier
/// filter (THIS function) via the constant-classifier composition, so
/// a regression that drifts the keyword filter's instrumentation
/// from the classifier filter's instrumentation becomes structurally
/// impossible.
///
/// Frontier inspiration: MLIR's
/// `op.walk<OpInterface, OpInterface2, …>([&](auto op) { … })` — the
/// typed-IR walk over a region yielding ops decoded to their typed
/// interface witness IS the slice-side typed-decoded projection on
/// MLIR's op algebra; `iter_calls_to_any` is the unstructured-Rust
/// peer on the substrate's typed `&[Sexp]` algebra, with `decode:
/// FnMut(&str) -> Option<T>` standing in for MLIR's typed-interface
/// dyn-cast bag. Racket's `syntax-parse` `~or* (~datum defmacro)
/// (~datum defpoint-template) (~datum defcheck) (head args …)` over
/// an ellipsis-form — the slice-level matched-set filter decoded to
/// a typed witness is the closed-form sibling of `~or*`'s
/// typed-choice repeater, translated through pleme-io primitives as
/// ONE `iter_calls_to_any(forms, F)` projection.
pub fn iter_calls_to_any<'a, F, T>(
forms: &'a [Sexp],
mut decode: F,
) -> impl Iterator<Item = (T, &'a [Sexp])> + 'a
where
F: FnMut(&str) -> Option<T> + 'a,
T: 'a,
{
forms
.iter()
.filter_map(move |f| f.as_call_to_any(&mut decode))
}
/// Iterate over the `Result<(decoded, NAME, spec_args)>` triples of every
/// form in `forms` whose call head decodes through `decode` AND carries a
/// positional NAME slot — the *slice-side* sibling of
/// [`Sexp::as_call_to_any`] specialized to the named NAME-then-kwargs
/// form shape, with the named-form structural gate
/// [`crate::compile::split_name_slot`] composed in. Where
/// [`iter_calls_to_any`] answers "which forms in this SLICE are calls
/// whose heads decode through `F`, and what do they decode to alongside
/// their args tail?" on a `&[Sexp]`, `iter_named_calls_to_any` answers
/// the same question AND extracts the borrowed NAME slot AND the
/// remaining spec args tail in ONE projection per matched form, lifting
/// the named-form gate from inside the projection at every consumer
/// site to the slice algebra itself.
///
/// The yielded `Result<(T, &'a str, &'a [Sexp])>` shape carries the
/// classifier's typed witness `T` alongside the BORROWED NAME slot AND
/// the BORROWED spec args tail. Non-matching forms (every shape
/// [`Sexp::as_call_to_any`] rejects, AND every call whose head is
/// present but `decode` returns `None` for) are skipped silently — the
/// classifier filter precedes the named gate, mirroring how
/// [`crate::compile::split_name_slot`] is composed into the projection
/// AFTER the classifier-decoded args tail is already in hand. Matched
/// forms whose NAME slot is missing yield `Err(NamedFormMissingName {
/// keyword })` carrying the classifier-supplied keyword; matched forms
/// whose NAME slot is a non-symbol-or-string yield `Err(NamedFormNonSymbolName
/// { keyword, got })` carrying the same keyword and the typed
/// [`SexpShape`](crate::error::SexpShape) projection of the offending
/// slot. Consumers `.collect::<Result<Vec<_>, _>>()` to short-circuit
/// at the first malformed NAME slot, exactly as
/// [`Expander::expand_and_collect_named_calls_to_any`](crate::macro_expand::Expander::expand_and_collect_named_calls_to_any)
/// short-circuits today via the same `split_name_slot` gate composed
/// inside its projection closure.
///
/// Decoder signature `FnMut(&str) -> Option<(T, &'static str)>` pairs
/// the typed witness `T` with the canonical static keyword threaded
/// through the `NamedFormMissingName.keyword` /
/// `NamedFormNonSymbolName.keyword` slots of the named-form gate — the
/// `&'static` constraint pins the same compile-time discipline
/// [`crate::compile::split_name_slot`]'s `keyword: &'static str`
/// parameter pins at its boundary. A classifier consumer that wants
/// "filter forms by a constant keyword" supplies a constant-classifier
/// decoder `|h| (h == keyword).then_some(((), keyword))`; the
/// [`iter_named_calls_to`] sibling below is exactly that specialization.
///
/// Closes the (per-form, slice-side) × (keyword, classifier) × (bare,
/// named) 2×2×2 cube of soft-dispatch primitives on the substrate's
/// `Sexp`/`&[Sexp]` algebras at the slice-side × classifier × named
/// corner — the cube the per-form algebra
/// (`as_call_to{,_any}`), the slice algebra
/// (`iter_calls_to{,_any}`), and the Expander surface
/// (`expand_and_collect_calls_to{,_any}` /
/// `expand_and_collect_named_calls_to{,_any}`) collectively shape:
///
/// | | bare-kwargs | named NAME-then-kwargs |
/// |----------------|--------------------------|--------------------------------------------------|
/// | per-form | [`Sexp::as_call_to_any`] | [`Sexp::as_named_call_to_any`] |
/// | slice | [`iter_calls_to_any`] | `iter_named_calls_to_any` (this) |
/// | expander | `expand_and_collect_calls_to_any` | `expand_and_collect_named_calls_to_any` |
///
/// Pre-lift the bare expander surface (`expand_and_collect_calls_to_any`)
/// routed through the slice primitive ([`iter_calls_to_any`]) via a
/// uniform `expand_program + iter_calls_to_any + map + collect`
/// pipeline; the named expander surface
/// (`expand_and_collect_named_calls_to_any`) routed through the
/// BARE expander surface and welded
/// [`crate::compile::split_name_slot`] INSIDE the projection closure —
/// the named gate composition lived at the expander level rather than
/// at the slice level the bare row sat at. Post-lift the named expander
/// surface routes through THIS slice primitive via the SAME
/// `expand_program + iter_named_calls_to_any + map + collect`
/// pipeline shape, so both rows now share the same composition skeleton
/// on the slice algebra — a regression that drifts a future debug-mode
/// logger, span-aware borrow walker, or fused-iterator invariant from
/// one row to the other becomes structurally impossible at the slice
/// boundary.
///
/// Two plausible future consumer shapes the slice-side named-classifier
/// walk admits with no boilerplate:
/// * **Closed-set classifier** — `iter_named_calls_to_any(forms, |h|
/// match h { "defmonitor" => Some((Kind::Monitor, "defmonitor")),
/// "defalertpolicy" => Some((Kind::Alert, "defalertpolicy")), _ =>
/// None }).collect::<Result<Vec<_>, _>>()?` walks a slice of
/// already-expanded forms, yielding the `(typed Kind, NAME, spec
/// args)` triple for every `(defmonitor NAME …)` / `(defalertpolicy
/// NAME …)` form. Future `tatara-check` consumers that already hold
/// expanded forms (the workspace coherence checker walks
/// `checks.lisp`'s post-expansion top-level) bind to ONE projection
/// on the slice algebra rather than re-deriving the
/// `iter_calls_to_any(forms, decode).map(|(decoded, args)| {
/// split_name_slot(args, kw).map(|(name, rest)| (decoded, name,
/// rest)) })` four-step inline composition.
/// * **Live-registry classifier** — `iter_named_calls_to_any(forms,
/// |h| registry.lookup(h).map(|h| (h, h.canonical_label())))` walks
/// a slice of expanded forms, yielding the `(handler reference, NAME,
/// spec args)` triple for every form whose head matches a runtime
/// registry. Future REPL / authoring-tool surfaces that dispatch
/// named forms through a live registry bind to ONE projection,
/// sibling shape to how the macro expander already routes through
/// a live-registry classifier via
/// [`Sexp::as_call_to_any`].
///
/// The closed-form composition binding this slice primitive to its
/// per-form sibling AND to the bare-kwargs slice primitive is the
/// structural identity every consumer can pin against:
///
/// ```ignore
/// iter_named_calls_to_any(forms, decode) ==
/// iter_calls_to_any(forms, decode).map(|(decoded, args)| {
/// let kw = /* keyword the decoder returned alongside decoded */;
/// split_name_slot(args, kw).map(|(name, rest)| (decoded, name, rest))
/// })
/// ```
///
/// The yielded `&'a str` NAME slot and `&'a [Sexp]` spec args tail
/// borrow from `&forms[i]` verbatim — no copy, no allocation, same
/// lifetime as [`Sexp::as_call_to_any`]'s tail. Consumers that need
/// owned ownership of the NAME (`NamedDefinition.name: String`,
/// JSON-serialized payloads) `.to_string()` themselves — pushing the
/// clone to the consumer boundary keeps the primitive allocation-free.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// named-form gate composition lived at the Expander level pre-lift
/// (inside `expand_and_collect_named_calls_to_any`'s projection
/// closure); the slice algebra had no named sibling to the bare
/// [`iter_calls_to_any`]. Post-lift the slice algebra closes at the
/// named corner, and the Expander surface routes through it via the
/// SAME `expand_program + iter + map + collect` pipeline the bare
/// expander surface uses. THEORY.md §V.1 — knowable platform; the
/// slice-side named-classifier walk becomes a NAMED primitive on the
/// substrate's `&[Sexp]` algebra, discoverable by any future authoring
/// tool (LSP, REPL, `tatara-check`) that already holds expanded forms.
/// THEORY.md §II.1 invariant 2 — free middle; the bare and named slice
/// projections share the same `forms.iter().filter_map(_)` skeleton, so
/// a regression that drifts ONE row's instrumentation from the other
/// becomes structurally impossible.
///
/// Frontier inspiration: MLIR's
/// `region.walk<NamedOp>([&](auto op) { auto name = op.getName(); … })`
/// — the typed-IR walk over a region yielding ops decoded to their
/// typed kind with the NAMED-symbol accessor pre-extracted is the MLIR
/// idiom for a named-op visitor; `iter_named_calls_to_any` is the
/// unstructured-Rust peer on the substrate's `&[Sexp]` algebra, with
/// `decode: FnMut(&str) -> Option<(T, &'static str)>` standing in for
/// MLIR's typed-interface dyn-cast bag AND `split_name_slot` standing
/// in for the named accessor. Racket's `syntax-parse` `~or* ((~datum
/// defX) name:id arg ...) ((~datum defY) name:id arg ...)` over an
/// ellipsis-form — the slice-level matched-set named-form filter
/// decoded to a typed witness is the closed-form sibling of `~or*`'s
/// typed-choice repeater with the `name:id` capture binder, translated
/// through pleme-io primitives as ONE projection on the `&[Sexp]`
/// algebra.
pub fn iter_named_calls_to_any<'a, F, T>(
forms: &'a [Sexp],
mut decode: F,
) -> impl Iterator<Item = crate::error::Result<(T, &'a str, &'a [Sexp])>> + 'a
where
F: FnMut(&str) -> Option<(T, &'static str)> + 'a,
T: 'a,
{
forms
.iter()
.filter_map(move |f| f.as_named_call_to_any(&mut decode))
}
/// Iterate over the `Result<(NAME, spec_args)>` pairs of every form in
/// `forms` whose call head matches `keyword` AND carries a positional
/// NAME slot — the *slice-side* sibling of [`Sexp::as_call_to`]
/// specialized to the named NAME-then-kwargs form shape, with the
/// named-form structural gate [`crate::compile::split_name_slot`]
/// composed in. Where [`iter_calls_to`] answers "which forms in this
/// SLICE are calls to `K`, and what are their args tails?" on a
/// `&[Sexp]`, `iter_named_calls_to` answers the same question AND
/// extracts the borrowed NAME slot AND the remaining spec args tail in
/// ONE projection per matched form.
///
/// Routes through the typed-decoded sibling [`iter_named_calls_to_any`]
/// with a constant-classifier decoder — the same constant-classifier
/// composition [`iter_calls_to`] uses to route through
/// [`iter_calls_to_any`] on the bare-kwargs axis, and that
/// [`crate::macro_expand::Expander::expand_and_collect_named_calls_to`]
/// uses to route through
/// [`crate::macro_expand::Expander::expand_and_collect_named_calls_to_any`]
/// on the Expander surface. The discarded `()` typed witness
/// (`then_some(((), keyword))`) is consumed by the wrapper projection so
/// the consumer's per-form mapper sees only the `(name, spec_args)`
/// borrowed pair, matching the bare projection signature on the named
/// axis.
///
/// `keyword: &'static str` threads verbatim through the
/// `NamedFormMissingName.keyword` / `NamedFormNonSymbolName.keyword`
/// slots of the named-form gate — same `&'static` discipline
/// [`crate::compile::split_name_slot`] pins at its boundary. Consumers
/// that want a runtime keyword whose lifetime is `&'static` (typical:
/// `T::KEYWORD` of a typed-domain witness, a hardcoded literal like
/// `"defcheck"`) bind to this primitive; consumers that want a runtime
/// keyword whose lifetime is shorter use [`iter_named_calls_to_any`]
/// directly with a constant-classifier decoder that converts
/// post-resolution.
///
/// Closes the (slice-side × constant-keyword × named) corner of the
/// soft-dispatch cube — see [`iter_named_calls_to_any`]'s docstring for
/// the cube shape. The closed-form composition binding this primitive
/// to the typed-decoded sibling is the structural identity every
/// consumer can pin against:
///
/// ```ignore
/// iter_named_calls_to(forms, k) ==
/// iter_named_calls_to_any(forms, |h| (h == k).then_some(((), k)))
/// .map(|maybe_triple| maybe_triple.map(|(_, name, args)| (name, args)))
/// ```
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// constant-keyword named slice projection is a CONSEQUENCE of the
/// typed-decoded named slice projection + a constant-classifier
/// decoder, parallel to how [`iter_calls_to`] is a consequence of
/// [`iter_calls_to_any`] on the bare-kwargs axis. THEORY.md §II.1
/// invariant 2 — free middle; both rows of the slice algebra
/// (bare-kwargs, named) route through their classifier sibling via
/// constant-classifier composition, so a regression that drifts ONE
/// row's pipeline from the other becomes structurally impossible.
pub fn iter_named_calls_to<'a>(
forms: &'a [Sexp],
keyword: &'static str,
) -> impl Iterator<Item = crate::error::Result<(&'a str, &'a [Sexp])>> + 'a {
iter_named_calls_to_any(forms, move |h| (h == keyword).then_some(((), keyword)))
.map(|maybe_triple| maybe_triple.map(|(_, name, args)| (name, args)))
}
/// Render an `Atom::Float`'s `f64` value to a form that re-reads as
/// `Atom::Float` — preserves the float-vs-int typed identity across the
/// `Sexp::Display` → [`crate::reader::read`] round-trip.
///
/// Rust's stdlib `Display` impl for `f64` elides the trailing `.0` for
/// finite integral values: `format!("{}", 1.0_f64) == "1"`,
/// `format!("{}", 100.0_f64) == "100"`. The substrate's reader
/// (via the typed-entry classifier [`Atom::from_lexeme`]) tries
/// `i64::parse` BEFORE `f64::parse`, so a bare `1` re-reads as
/// `Atom::Int(1)` — NOT as `Atom::Float(1.0)`. The default Display rendering therefore drifts the
/// typed identity at the Display→read boundary: `Float(1.0)` round-trips
/// to `Int(1)` and a regression silently coerces an authoring-surface
/// `1.0` slot into the typed `Int` track.
///
/// This helper emits `1.0` for `1.0_f64` and `1.5` for `1.5_f64` — the
/// `.0` suffix is appended IFF the value is finite AND already integral
/// (`n == n.trunc()`). Non-integral values render through the default
/// `f64` Display impl, which already preserves the fractional component
/// (`1.5`, `0.99`, etc.) round-trippably. Non-finite values (`NaN`,
/// `inf`, `-inf`) also fall through to the default impl — they cannot be
/// reliably round-tripped through the reader regardless (the Hash impl
/// already warns about NaN's PartialEq irregularity at the cache-key
/// boundary), so the helper does not paper over that prior limitation.
///
/// Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the
/// substrate's typed-entry gate distinguishes `Atom::Int` from
/// `Atom::Float`, and the Display→read round-trip is the typed-exit-side
/// mirror that must preserve the distinction. Pre-lift the
/// `Float(integral) → Int(integral)` collapse silently violated the
/// invariant at the round-trip boundary; post-lift the typed identity is
/// preserved. THEORY.md §V.1 — knowable platform; diagnostics that
/// project a `Float(1.0)` slot through `SexpWitness::display` (sourced
/// from `Sexp::to_string()`) used to surface as `got 1` — confusingly
/// identical to the typed `Int(1)` projection. Post-lift the diagnostic
/// shape names the offender's typed identity (`got 1.0`) so operators
/// distinguish "you wrote 1.0 in an int slot" from "you wrote 1 in a
/// kwarg slot the kwarg gate rejected" without re-reading source.
fn fmt_float(n: f64, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if n.is_finite() && n == n.trunc() {
write!(f, "{n}.0")
} else {
write!(f, "{n}")
}
}
/// Canonical reader-round-trippable rendering of a single atomic payload —
/// `Symbol(s) → "{s}"`, `Keyword(s) → ":{s}"`, `Str(s) → "{s:?}"` (the
/// debug-quoted form: `\"…\"` with embedded `"` and `\` escaped), `Int(n)
/// → "{n}"`, `Float(n)` through [`fmt_float`] so integral values render
/// with the `.0` suffix that preserves the typed-`Float`-vs-typed-`Int`
/// distinction at the Display→read boundary, `Bool(true) → "#t"`,
/// `Bool(false) → "#f"` (the Scheme bool spellings the reader's
/// typed-entry classifier [`Atom::from_lexeme`] dispatches on — `true`
/// / `false` re-read as symbols, NOT as bools — see the CLAUDE.md
/// "Lisp bools" warning).
///
/// This is the *atomic-payload Display surface* — the typed-exit-side
/// peer of [`Atom::from_lexeme`]'s atomic-payload typed-entry surface
/// (the FOURTH and LAST of the per-`Atom`-variant projection sites
/// lifted onto the closed-set algebra, after the typed-exit Display
/// [this impl], JSON [`Atom::to_json`], and iac-forge canonical
/// attestation `Atom::to_iac_forge_sexpr` (removed) projections — completing
/// the bidirectional typed-entry/typed-exit sweep). Before this lift
/// the per-variant rendering arms
/// lived inline at the `Sexp::Atom(a) => match a { … }` arm of
/// [`fmt::Display for Sexp`]; routing the outer arm through this impl
/// lifts the seven inline sub-arms (the Bool variant splits into
/// `true`/`false` to short-circuit the `if-else` branch) into ONE
/// typed-algebra method the `Sexp` Display arm calls into via
/// `fmt::Display::fmt(a, f)`. Sibling closed-set lift to
/// [`QuoteForm::prefix`] (the four homoiconic prefix wrappers) and
/// [`AtomKind::label`] (the six diagnostic labels) — those name the
/// quote-family and atomic-discriminator pairings at the `Sexp` and
/// `Atom` algebras respectively; this names the atomic-payload
/// rendering at the `Atom` algebra so future consumers of "render a
/// bare atom" land on this impl directly without unwrapping through
/// `Sexp::Atom(_).to_string()` and stripping the outer wrap.
///
/// Three production-site sibling shapes the substrate carries that
/// route through a per-`Atom`-variant projection, all 6/7-arm inline
/// matches pre-lift:
/// * [`fmt::Display for Sexp`]'s atom arm — 7 sub-arms (Bool splits),
/// produces a `fmt::Formatter` body. Post-lift collapses to
/// ONE `fmt::Display::fmt(a, f)` delegation.
/// * [`crate::domain::sexp_to_json`]'s atom arms — 6 inline arms
/// producing `serde_json::Value`. Now lifted onto [`Atom::to_json`]
/// in the sibling pattern this impl's docstring named; the
/// `sexp_to_json` site collapses to ONE `Sexp::Atom(a) =>
/// a.to_json()` arm.
/// * `crate::interop`'s `From<&Sexp> for SExpr` (removed)'s
/// atom arm (feature-gated `iac-forge`) — 6 inline arms producing
/// `iac_forge::sexpr::SExpr`. Now lifted onto
/// `Atom::to_iac_forge_sexpr` (removed) in the sibling pattern this impl's
/// docstring named; the interop site collapses to ONE
/// `Sexp::Atom(a) => a.to_iac_forge_sexpr()` arm. THIRD and LAST
/// of the three production-site atom-arm shapes lifted onto the
/// typed `Atom` algebra; the sweep across the Lisp / JSON /
/// iac-forge canonical-form surfaces is complete.
///
/// The (Atom variant, rendered prefix/suffix/body) quadruple now lives
/// at ONE typed-algebra Display impl rather than at seven inline
/// sub-arms inside `Display for Sexp`'s outer Atom arm. A regression
/// that drifts the Bool spelling (`#t`/`#f` vs `true`/`false`) — the
/// CLAUDE.md-pinned reader-round-trip invariant — now lands at ONE
/// site, and the test surface pins each variant's canonical rendering
/// AND the round-trip identity through the reader at the Atom level
/// directly (no Sexp wrap required to exercise the round-trip).
///
/// Bidirectional contract anchored by tests in this module:
/// * `atom_display_renders_each_variant_to_canonical_form` —
/// sweeps `AtomKind::ALL` and pins each variant's canonical
/// rendering byte-for-byte against the pre-lift inline literal,
/// so a future regression that drifts ONE arm (e.g. swaps
/// `#t`/`#f` for `true`/`false`, or strips `Str`'s quote marks)
/// fails loudly.
/// * `sexp_atom_display_arm_routes_through_atom_display_for_every_variant`
/// — pins the lifted boundary: `Sexp::Atom(a).to_string() ==
/// a.to_string()` for every atomic payload variant, AND that
/// both equal the legacy inline rendering. Catches a future
/// drift where one surface's per-variant body changes without
/// the other.
/// * `atom_display_round_trips_through_reader_preserving_typed_identity`
/// — sweeps a representative atom of each variant, renders it
/// via `Atom::Display`, parses the rendering through
/// [`crate::reader::read`], and pins the parsed atom equals
/// the seed atom (modulo `Str`'s debug-quoted spelling — pinned
/// separately because the reader expects unquoted source-level
/// `"foo"`). Pins that the (`Atom::Display`, reader) pair forms
/// a typed round-trip at the atom layer, the same invariant
/// [`fmt_float`]'s `.0` suffix preserves for the float-vs-int
/// distinction at the Sexp layer.
///
/// Theory anchor: THEORY.md §VI.1 — generation over composition; the
/// (Atom variant, canonical rendering) pair appeared inline at THREE
/// production sites (`Display for Sexp`'s 7-sub-arm atom arm,
/// `sexp_to_json`'s 6 atom arms, `From<&Sexp> for SExpr`'s 6 atom arms)
/// — well past the ≥2 PRIME-DIRECTIVE trigger once the structural
/// shape is named. THIS lift retires the Display-surface site by
/// naming the typed primitive on the `Atom` algebra; future runs route
/// the JSON and iac-forge sites through parallel sibling projections
/// (`Atom::to_json`, `Atom::to_iac_forge_sexpr`) the same pattern
/// names. THEORY.md §II.1 invariant 1 — typed entry; the substrate's
/// [`Atom::from_lexeme`] is the typed-entry gate at the atomic-payload
/// boundary (lifted onto the typed [`Atom`] algebra from the reader's
/// pre-lift free function), and this impl is the typed-exit-side
/// mirror — the closed-set [`AtomKind`] algebra now threads BOTH gates
/// through ONE projection family, so a regression that drifts one side's
/// per-variant rendering from the other (e.g. extends `Atom` with a
/// `Char` variant the reader accepts but the writer can't emit) is no
/// longer a silent two-site divergence — rustc binds both sides to
/// the same closed-set enum. THEORY.md §II.1 invariant 2 — free middle;
/// the typed-exit rendering, the reader, the diagnostic surface
/// (`LispError::TypeMismatch.got` slot rendering an atomic witness),
/// and any future authoring tool (LSP / REPL pretty-printer) all
/// route through ONE per-variant rendering rather than per-callsite
/// re-derivation.
///
/// Frontier inspiration: Racket's `(syntax->datum stx)` / `write` pair
/// — where `syntax->datum` unwraps the homoiconic surface to its
/// atomic-payload layer and `write` emits the canonical S-expression
/// rendering bound to the reader's `read` inverse; `Atom::Display`
/// is the substrate's typed-algebra peer at the atomic-payload boundary,
/// with the closed-set [`AtomKind`] standing in for Racket's
/// datum-prim taxonomy. MLIR's `mlir::AsmPrinter::printAttribute` — the
/// typed-IR attribute printer dispatches on the closed-set
/// `AttributeKind` so every printer body for a kind lives at ONE
/// implementation site; `Atom::Display` is the unstructured Rust peer
/// for the `Sexp`/`Atom` algebra, with `fmt::Display` standing in for
/// MLIR's `AsmPrinter` interface.
impl fmt::Display for Atom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Symbol(s) => f.write_str(s),
Self::Keyword(s) => write!(f, "{}{s}", Self::KEYWORD_MARKER),
// NOT `{s:?}`. Rust's `str` Debug escapes NUL as `\0`, and this
// reader deliberately decodes `\0` as the DIGIT `0` — see
// `decode_str_escape`'s passthrough arm and the test pinning it.
// So `{s:?}` emitted an escape that means something else here, and
// `"nul\0byte"` round-tripped to `"nul0byte"`: silent corruption
// from two locally-correct decisions disagreeing.
//
// This escaper emits exactly what THIS reader decodes: the five
// named/self escapes, and `\u{…}` for anything else non-printable
// (which the reader gained an arm for alongside this fix). Display
// and read are inverses again.
Self::Str(s) => write!(f, "{}", Self::escape_str_payload(s)),
Self::Int(n) => write!(f, "{n}"),
Self::Float(n) => fmt_float(*n, f),
// Bool arm collapses to ONE branch routing through
// `Self::bool_literal` — the closed-set `bool` fork happens
// at the typed projection on the [`Atom`] algebra, not at
// this consumer's match body. Sibling lift to the Keyword
// arm, which routes through `Self::KEYWORD_MARKER` at the
// same algebra layer.
Self::Bool(b) => f.write_str(Self::bool_literal(*b)),
}
}
}
impl fmt::Display for Sexp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
// The empty-list rendering `()` composes BOTH structural
// delimiters — [`Self::LIST_OPEN`] followed by
// [`Self::LIST_CLOSE`] — on the closed-set outer [`Sexp`]
// algebra. Pre-lift the same two bytes lived inline as one
// `"()"` string literal at this arm; post-lift each byte
// binds to its typed constant, so a delimiter swap flips
// both this arm AND the `Self::List(_)` opener/closer arm
// below AND the reader's `Token::LParen` / `Token::RParen`
// outer-dispatch arms in lockstep — at ONE constant per
// side rather than at four inline bytes across two files.
Self::Nil => {
f.write_char(Self::LIST_OPEN)?;
f.write_char(Self::LIST_CLOSE)
}
// The atomic-payload rendering lives at the typed
// [`fmt::Display for Atom`] impl above — the seven inline
// sub-arms `Symbol → s`, `Keyword → ":{s}"`, `Str → "{s:?}"`,
// `Int → "{n}"`, `Float → fmt_float`, `Bool(true) → "#t"`,
// `Bool(false) → "#f"` all bind at ONE site on the closed-set
// `Atom` algebra rather than at this outer arm. A future
// atomic-kind extension (e.g. `Char` for `#\x` reader syntax,
// `Bigint` for arbitrary-precision integers) extends `Atom`'s
// Display impl once and this arm picks up the new variant
// for free.
Self::Atom(a) => fmt::Display::fmt(a, f),
// The `Self::List(_)` opener AND closer arms bind to
// [`Self::LIST_OPEN`] AND [`Self::LIST_CLOSE`] on the
// closed-set outer [`Sexp`] algebra — the SAME two typed
// constants the reader's `Token::LParen` / `Token::RParen`
// outer-dispatch arms AND the `Self::Nil` two-char
// rendering all route through. Adding a fifth structural
// outer-shape (e.g. an eventual `Self::Vector` for `[…]`
// reader syntax) lands as ONE new pair of `Sexp::VEC_OPEN`
// / `Sexp::VEC_CLOSE` constants with the reader arms +
// Display arms binding through them, extending the
// outer-structural algebra by ONE axis without touching
// this arm's `LIST_OPEN` / `LIST_CLOSE` binding.
Self::List(xs) => {
f.write_char(Self::LIST_OPEN)?;
for (i, x) in xs.iter().enumerate() {
if i > 0 {
f.write_str(" ")?;
}
write!(f, "{x}")?;
}
f.write_char(Self::LIST_CLOSE)
}
// The four quote-family variants share the
// `write!(f, "<prefix>{inner}")` Display shape — all route
// through `as_quote_form`'s typed-marker projection so the
// per-variant prefix (`'`, `` ` ``, `,`, `,@`) binds at ONE
// site on the closed-set `QuoteForm` algebra and the
// recursive `inner` rendering composes through the unified
// Display arm. The (prefix, variant) pairing IS the structural
// dual of the reader's `read_quoted` (prefix, variant-ctor)
// dispatch — naming it once threads the round-trip discipline
// through ONE rust function the reader and the Display impl
// both bind against.
Self::Quote(_) | Self::Quasiquote(_) | Self::Unquote(_) | Self::UnquoteSplice(_) => {
let (qf, inner) = self.expect_quote_form();
write!(f, "{}{inner}", qf.prefix())
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
// ── head_symbol: the operator-position projection ───────────────────
//
// `head_symbol` lifts the `self.as_list()?.first()?.as_symbol()` chain
// that recurred at four soft-dispatch sites (compile.rs `compile_typed`
// + `compile_named_from_forms`, macro_expand.rs `Expander::expand` +
// `macro_def_from`) into ONE named query on the Sexp algebra. These
// tests pin its contract directly; the existing dispatch tests in
// compile.rs / macro_expand.rs are the path-uniformity guards proving
// the four sites route through it without behavior drift.
#[test]
fn head_symbol_returns_operator_for_list_form() {
// `(defpoint obs :class x)` — the operator is the head symbol.
let form = Sexp::List(vec![
Sexp::symbol("defpoint"),
Sexp::symbol("obs"),
Sexp::keyword("class"),
Sexp::symbol("x"),
]);
assert_eq!(form.head_symbol(), Some("defpoint"));
}
#[test]
fn head_symbol_none_for_non_list_shapes() {
// A bare atom is not an invocation — there is no operator position.
assert_eq!(Sexp::symbol("foo").head_symbol(), None);
assert_eq!(Sexp::int(5).head_symbol(), None);
assert_eq!(Sexp::keyword("k").head_symbol(), None);
assert_eq!(Sexp::string("s").head_symbol(), None);
assert_eq!(Sexp::boolean(true).head_symbol(), None);
assert_eq!(Sexp::float(1.5).head_symbol(), None);
assert_eq!(Sexp::Nil.head_symbol(), None);
// Quote-family wrappers are not lists at the outer layer either.
assert_eq!(Sexp::Quote(Box::new(Sexp::symbol("x"))).head_symbol(), None);
}
#[test]
fn head_symbol_none_for_empty_list() {
// `()` has no first element to read an operator from.
assert_eq!(Sexp::List(vec![]).head_symbol(), None);
}
#[test]
fn head_symbol_none_for_non_symbol_head() {
// A list whose head is present but not a symbol is not a dispatchable
// invocation — the soft projection yields None (the STRICT sibling
// `compile_from_sexp` is the one that rejects these loudly).
assert_eq!(
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]).head_symbol(),
None
);
assert_eq!(
Sexp::List(vec![Sexp::keyword("kw"), Sexp::symbol("a")]).head_symbol(),
None
);
assert_eq!(
Sexp::List(vec![Sexp::string("s"), Sexp::symbol("a")]).head_symbol(),
None
);
assert_eq!(
Sexp::List(vec![
Sexp::List(vec![Sexp::symbol("nested")]),
Sexp::symbol("a")
])
.head_symbol(),
None
);
assert_eq!(
Sexp::List(vec![Sexp::Nil, Sexp::symbol("a")]).head_symbol(),
None
);
}
#[test]
fn head_symbol_reads_singleton_list_operator() {
// `(defcompiler)` — a keyword-only form still has an operator head;
// this is exactly the arity-gate input compile_named dispatches on
// before rejecting the missing NAME.
assert_eq!(
Sexp::List(vec![Sexp::symbol("defcompiler")]).head_symbol(),
Some("defcompiler")
);
}
#[test]
fn head_symbol_borrows_the_actual_head_string() {
// The returned &str borrows the head atom's contents verbatim — no
// copy, no normalization. Pin that a multi-segment symbol round-trips
// unchanged so the dispatch comparison against `T::KEYWORD` is exact.
let form = Sexp::List(vec![Sexp::symbol("defalert-policy"), Sexp::symbol("p")]);
assert_eq!(form.head_symbol(), Some("defalert-policy"));
}
// ── as_call: the call-form decomposition ────────────────────────────
//
// `as_call` pairs `head_symbol` (the operator projection) with the
// argument tail every dispatch site reads right after matching the
// operator — `Some((op, &args))` for a symbol-headed list, `None` for
// everything else. It lifts the `as_list()`-for-the-tail +
// `head_symbol()`-for-the-operator pairing that recurred at the three
// soft-dispatch sites (compile.rs `compile_typed` + `compile_named_
// from_forms`, macro_expand.rs `Expander::expand`) into ONE match.
// `head_symbol` now delegates to it, so the `as_list()?.first()?.
// as_symbol()` chain lives in exactly one place. These tests pin the
// decomposition's contract directly; the existing dispatch tests in
// compile.rs / macro_expand.rs are the path-uniformity guards proving
// the three sites route through it without behavior drift.
#[test]
fn as_call_decomposes_list_form_into_operator_and_args() {
// `(defpoint obs :class x)` — the operator is the head symbol and
// the args are everything after it.
let args = [
Sexp::symbol("obs"),
Sexp::keyword("class"),
Sexp::symbol("x"),
];
let form = Sexp::List(
std::iter::once(Sexp::symbol("defpoint"))
.chain(args.iter().cloned())
.collect(),
);
assert_eq!(form.as_call(), Some(("defpoint", &args[..])));
}
#[test]
fn as_call_none_for_non_call_shapes() {
// Every shape `head_symbol` rejects, `as_call` rejects identically:
// non-lists, the empty list, and non-symbol heads have no operator
// to apply, hence no call decomposition.
assert_eq!(Sexp::symbol("foo").as_call(), None);
assert_eq!(Sexp::int(5).as_call(), None);
assert_eq!(Sexp::keyword("k").as_call(), None);
assert_eq!(Sexp::string("s").as_call(), None);
assert_eq!(Sexp::Nil.as_call(), None);
assert_eq!(Sexp::Quote(Box::new(Sexp::symbol("x"))).as_call(), None);
assert_eq!(Sexp::List(vec![]).as_call(), None);
assert_eq!(
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]).as_call(),
None
);
assert_eq!(
Sexp::List(vec![Sexp::keyword("kw"), Sexp::symbol("a")]).as_call(),
None
);
}
#[test]
fn as_call_yields_empty_args_for_singleton_list() {
// `(defcompiler)` — a keyword-only form decomposes to its operator
// with an EMPTY argument tail. This is exactly the arity-gate input
// `compile_named_from_forms` dispatches on before rejecting the
// missing NAME via `rest.split_first()` returning `None`.
assert_eq!(
Sexp::List(vec![Sexp::symbol("defcompiler")]).as_call(),
Some(("defcompiler", &[][..]))
);
}
#[test]
fn as_call_args_are_exactly_the_tail_after_the_operator() {
// The args slice borrows `&list[1..]` verbatim — the head is
// excluded, every following element is included in order.
let form = Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::symbol("cpu"),
Sexp::keyword("threshold"),
Sexp::int(90),
]);
let (op, args) = form.as_call().expect("symbol-headed list decomposes");
assert_eq!(op, "defmonitor");
assert_eq!(args.len(), 3);
assert_eq!(args[0], Sexp::symbol("cpu"));
assert_eq!(args[2], Sexp::int(90));
}
#[test]
fn head_symbol_is_the_operator_projection_of_as_call() {
// The structural relationship the lift establishes: `head_symbol`
// is `as_call().map(|(h, _)| h)`. Pin it across every shape so a
// regression that drifts one query's head-recognition from the
// other — e.g. `as_call` accepting a keyword head that `head_symbol`
// still rejects — fails loudly. The two share ONE chain.
let shapes = [
Sexp::symbol("foo"),
Sexp::int(5),
Sexp::keyword("k"),
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::symbol("defpoint"), Sexp::symbol("p")]),
Sexp::List(vec![Sexp::symbol("solo")]),
];
for s in &shapes {
assert_eq!(
s.head_symbol(),
s.as_call().map(|(h, _)| h),
"head_symbol must equal the operator component of as_call for {s}"
);
}
}
// ── as_call_to: the keyword-typed call decomposition ────────────────
//
// `as_call_to(keyword)` answers "is this a call to ONE specific
// operator, and what are its arguments?" — the keyword-aware sibling
// of `as_call`. It lifts the `as_call() + head == T::KEYWORD` two-step
// chain that recurred at the two `compile.rs` dispatch sites
// (`compile_typed` and `compile_named_from_forms`) into ONE structural
// query on the Sexp algebra. The tests below pin its contract
// directly; the existing `compile_*` tests are the path-uniformity
// guards proving the two production sites route through it without
// behavior drift.
#[test]
fn as_call_to_returns_args_for_matching_head() {
// `(defmonitor :name "x")` — head is the exact symbol `defmonitor`,
// so `as_call_to("defmonitor")` returns `Some(args)` with the tail
// after the head verbatim.
let form = Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("x"),
]);
let args = form
.as_call_to("defmonitor")
.expect("matching head must yield Some(args)");
assert_eq!(args.len(), 2);
assert_eq!(args[0], Sexp::keyword("name"));
assert_eq!(args[1], Sexp::string("x"));
}
#[test]
fn as_call_to_returns_none_for_mismatched_head() {
// `(defmonitor …)` against keyword `"defpoint"` — same form is a
// call (so `as_call().is_some()`), but the head doesn't equal the
// requested keyword. `as_call_to` is the keyword-typed projection,
// so it yields `None` exactly when the head doesn't match. Pin the
// gate: the two pre-lift inline sites both rejected this case via
// `if head != T::KEYWORD { continue }` / `if head == T::KEYWORD`,
// and the lifted primitive must reject identically.
let form = Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("x"),
]);
assert!(form.as_call().is_some());
assert_eq!(form.as_call_to("defpoint"), None);
assert_eq!(form.as_call_to(""), None);
assert_eq!(form.as_call_to("DEFMONITOR"), None);
}
#[test]
fn as_call_to_yields_empty_args_for_singleton_matching_call() {
// `(defcompiler)` against keyword `"defcompiler"` — the head
// matches and the argument tail is the empty slice. Pin the
// empty-tail posture: this is exactly the input
// `compile_named_from_forms` dispatches on before rejecting the
// missing NAME via `rest.split_first()` returning `None`, so the
// lifted primitive must yield `Some(&[])` here (NOT `None`) so
// the downstream split-first gate fires structurally.
let form = Sexp::List(vec![Sexp::symbol("defcompiler")]);
assert_eq!(form.as_call_to("defcompiler"), Some(&[][..]));
}
#[test]
fn as_call_to_returns_none_for_non_call_shapes() {
// Every shape `as_call` rejects, `as_call_to` rejects identically
// regardless of the requested keyword: non-lists, the empty list,
// and non-symbol heads have no operator to compare to. Pin
// path-uniformity with the `as_call` sibling so a regression that
// narrows the keyword-typed projection to admit a shape the bare
// soft projection rejected (e.g. accepting a keyword head when
// `keyword` matches the keyword's symbol-string projection) fails
// here.
let shapes = [
Sexp::symbol("foo"),
Sexp::int(5),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::boolean(true),
Sexp::float(1.5),
Sexp::Nil,
Sexp::Quote(Box::new(Sexp::symbol("foo"))),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::keyword("foo"), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::string("foo"), Sexp::symbol("a")]),
];
for s in &shapes {
assert_eq!(
s.as_call_to("foo"),
None,
"non-call shape must yield None for any keyword, got Some for {s}"
);
assert_eq!(s.as_call_to("anything"), None);
}
}
#[test]
fn as_call_to_args_borrow_is_same_pointer_as_as_call_tail() {
// The structural identity binding `as_call_to` to its `as_call`
// sibling: on the matching-head path, the returned `args` slice IS
// the same `&[Sexp]` slice `as_call` would return as the tail
// component. Pin pointer equality so a regression that
// re-allocates or copies the tail in the keyword-typed projection
// fails loudly — the soft-projection contract is borrow, not
// clone, AND `as_call_to` inherits the contract verbatim from
// `as_call`.
let form = Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("x"),
]);
let (_, via_as_call) = form.as_call().expect("call shape");
let via_as_call_to = form
.as_call_to("defmonitor")
.expect("matching keyword shape");
assert!(
std::ptr::eq(via_as_call.as_ptr(), via_as_call_to.as_ptr()),
"as_call_to args must borrow the SAME slice as as_call's tail"
);
assert_eq!(via_as_call.len(), via_as_call_to.len());
}
#[test]
fn as_call_to_is_the_keyword_typed_projection_of_as_call() {
// The structural identity the lift establishes:
// `as_call_to(k) == as_call().and_then(|(h, args)| (h == k).then_some(args))`
// `as_call_to(k).is_some() == (head_symbol() == Some(k))`
// Pin both across every shape so a regression that drifts the
// keyword-typed projection from its closed-form definition fails
// loudly. The three soft-projection primitives — `head_symbol`,
// `as_call`, `as_call_to` — must agree on operator-position
// recognition at every shape they share.
let shapes = [
Sexp::symbol("foo"),
Sexp::int(5),
Sexp::keyword("k"),
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::symbol("defpoint"), Sexp::symbol("p")]),
Sexp::List(vec![Sexp::symbol("defmonitor"), Sexp::keyword("name")]),
Sexp::List(vec![Sexp::symbol("solo")]),
];
for s in &shapes {
for k in ["defpoint", "defmonitor", "solo", "foo", ""] {
let via_chain = s.as_call().and_then(|(h, args)| (h == k).then_some(args));
assert_eq!(
s.as_call_to(k),
via_chain,
"as_call_to({k:?}) must equal as_call+filter for {s}"
);
assert_eq!(
s.as_call_to(k).is_some(),
s.head_symbol() == Some(k),
"as_call_to({k:?}).is_some() must equal (head_symbol() == Some({k:?})) for {s}"
);
}
}
}
// ── as_call_to_any: the typed-decoded call decomposition ────────────
//
// `as_call_to_any(decode)` answers "is this a call whose head decodes
// through `decode`, and what are its arguments?" — the closure-typed
// sibling of `as_call_to`. It lifts the
// `as_list() + head_symbol() + decode(head)` three-step chain that
// recurred at the macro-expander's `macro_def_from` site (the typed
// `MacroDefHead::from_keyword` dispatch surface) into ONE structural
// query on the Sexp algebra. The tests below pin its contract
// directly; the existing macro-expansion tests are the path-
// uniformity guards proving the production site routes through it
// without behavior drift.
//
// The test classifier `Op::from_keyword` mirrors `MacroDefHead::from_keyword`
// — a closed-set typed enum projection from a `&str` head — so the
// tests cover the macro-expander's real consumer shape rather than a
// synthetic predicate.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Op {
Quote,
If,
Let,
}
impl Op {
fn from_keyword(head: &str) -> Option<Self> {
match head {
"quote" => Some(Self::Quote),
"if" => Some(Self::If),
"let" => Some(Self::Let),
_ => None,
}
}
}
#[test]
fn as_call_to_any_returns_decoded_head_and_args_for_matching_head() {
// `(if c t e)` — head `if` decodes to `Op::If`, args are the
// three-element tail verbatim. Pin both halves of the returned
// tuple: the decoded typed witness AND the borrowed args slice.
let form = Sexp::List(vec![
Sexp::symbol("if"),
Sexp::symbol("c"),
Sexp::symbol("t"),
Sexp::symbol("e"),
]);
let (op, args) = form
.as_call_to_any(Op::from_keyword)
.expect("matching head must yield Some((decoded, args))");
assert_eq!(op, Op::If);
assert_eq!(args.len(), 3);
assert_eq!(args[0], Sexp::symbol("c"));
assert_eq!(args[2], Sexp::symbol("e"));
}
#[test]
fn as_call_to_any_returns_none_when_decoder_rejects_head() {
// `(defmonitor :name "x")` — head `defmonitor` is a valid symbol
// (so `as_call().is_some()`), but `Op::from_keyword` rejects it
// (it's not one of the closed `{quote, if, let}` set). Pin the
// gate: `as_call_to_any` yields `None` exactly when the decoder
// rejects the head, mirroring how the pre-lift inline chain in
// `macro_def_from` returned `Ok(None)` when
// `MacroDefHead::from_keyword(head_str)` returned `None`.
let form = Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("x"),
]);
assert!(form.as_call().is_some());
assert!(form.as_call_to_any(Op::from_keyword).is_none());
}
#[test]
fn as_call_to_any_yields_empty_args_for_singleton_decoded_call() {
// `(quote)` against the classifier — head decodes to `Op::Quote`
// and the argument tail is the empty slice. Pin the empty-tail
// posture: a downstream arity gate (analogous to
// `if list.len() < 4` inside `macro_def_from`) dispatches on
// `args.is_empty()` AFTER the decoder accepts the head; the
// helper must yield `Some((decoded, &[]))` (NOT `None`) so that
// gate fires structurally.
let form = Sexp::List(vec![Sexp::symbol("quote")]);
let (op, args) = form
.as_call_to_any(Op::from_keyword)
.expect("singleton matching call must decompose");
assert_eq!(op, Op::Quote);
assert_eq!(args.len(), 0);
}
#[test]
fn as_call_to_any_returns_none_for_non_call_shapes() {
// Every shape `as_call` rejects, `as_call_to_any` rejects
// identically regardless of the decoder: non-lists, the empty
// list, and non-symbol heads have no operator string to feed
// the decoder. Pin path-uniformity with the `as_call` sibling so
// a regression that admits a non-call shape (e.g. accepting a
// bare symbol via a permissive decoder) fails here. Pass
// `Some` for every input to prove the call-shape gate fires
// BEFORE the decoder runs — the decoder cannot rescue a
// non-call.
let shapes = [
Sexp::symbol("foo"),
Sexp::int(5),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::boolean(true),
Sexp::float(1.5),
Sexp::Nil,
Sexp::Quote(Box::new(Sexp::symbol("foo"))),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::keyword("foo"), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::string("foo"), Sexp::symbol("a")]),
];
for s in &shapes {
// The promiscuous decoder accepts every &str head, so the
// only way to see `None` here is if the call-shape gate
// rejects the shape upstream of the decoder.
assert_eq!(
s.as_call_to_any(|h: &str| Some(h.to_string())),
None,
"non-call shape must yield None even for a promiscuous decoder, got Some for {s}"
);
}
}
#[test]
fn as_call_to_any_args_borrow_is_same_pointer_as_as_call_tail() {
// The structural identity binding `as_call_to_any` to its
// `as_call` sibling: on the decoded path, the returned `args`
// slice IS the same `&[Sexp]` slice `as_call` would return as
// the tail component. Pin pointer equality so a regression that
// re-allocates or copies the tail in the typed-decoded
// projection fails loudly — the soft-projection contract is
// borrow, not clone, AND `as_call_to_any` inherits the contract
// verbatim from `as_call`. Parallel to the
// `as_call_to_args_borrow_is_same_pointer_as_as_call_tail` pin
// for `as_call_to`.
let form = Sexp::List(vec![
Sexp::symbol("if"),
Sexp::symbol("c"),
Sexp::symbol("t"),
]);
let (_, via_as_call) = form.as_call().expect("call shape");
let (_, via_as_call_to_any) = form
.as_call_to_any(Op::from_keyword)
.expect("decoded shape");
assert!(
std::ptr::eq(via_as_call.as_ptr(), via_as_call_to_any.as_ptr()),
"as_call_to_any args must borrow the SAME slice as as_call's tail"
);
assert_eq!(via_as_call.len(), via_as_call_to_any.len());
}
#[test]
fn as_call_to_any_is_the_decoded_projection_of_as_call() {
// The structural identity the lift establishes:
// `as_call_to_any(decode) == as_call().and_then(|(h, args)| decode(h).map(|d| (d, args)))`
// `as_call_to_any(decode).is_some() == as_call().map_or(false, |(h, _)| decode(h).is_some())`
// Pin both across every shape so a regression that drifts the
// typed-decoded projection from its closed-form definition fails
// loudly. The four soft-projection primitives — `head_symbol`,
// `as_call`, `as_call_to`, `as_call_to_any` — must agree on
// operator-position recognition at every shape they share.
let shapes = [
Sexp::symbol("foo"),
Sexp::int(5),
Sexp::keyword("k"),
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::symbol("if"), Sexp::symbol("c")]),
Sexp::List(vec![Sexp::symbol("quote"), Sexp::symbol("x")]),
Sexp::List(vec![Sexp::symbol("let"), Sexp::List(vec![])]),
Sexp::List(vec![Sexp::symbol("defpoint"), Sexp::symbol("p")]),
Sexp::List(vec![Sexp::symbol("solo")]),
];
for s in &shapes {
let via_chain = s
.as_call()
.and_then(|(h, args)| Op::from_keyword(h).map(|d| (d, args)));
assert_eq!(
s.as_call_to_any(Op::from_keyword),
via_chain,
"as_call_to_any(Op::from_keyword) must equal as_call+decode for {s}"
);
}
}
#[test]
fn as_call_to_any_subsumes_as_call_to_via_unit_decoder() {
// The closed-form composition `as_call_to(k) == as_call_to_any
// (|h| (h == k).then_some(())).map(|(_, a)| a)` (modulo the
// discarded `()` decoded witness). Pin it across every shape ×
// keyword pair so a regression that drifts the typed-decoded
// projection from its single-keyword sibling fails loudly. This
// makes the family closure: `as_call_to` is the trivial-decoder
// instance of `as_call_to_any`, and naming both lets each
// consumer pick the projection that fits its call site.
let shapes = [
Sexp::symbol("foo"),
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::symbol("if"), Sexp::symbol("c")]),
Sexp::List(vec![Sexp::symbol("defpoint"), Sexp::symbol("p")]),
];
for s in &shapes {
for k in ["if", "defpoint", "let", "foo", "", "DEFPOINT"] {
let via_unit_decoder = s
.as_call_to_any(|h: &str| (h == k).then_some(()))
.map(|(_, args)| args);
assert_eq!(
s.as_call_to(k),
via_unit_decoder,
"as_call_to({k:?}) must equal as_call_to_any+unit-decoder for {s}"
);
}
}
}
// ── iter_calls_to: the slice-side projection of as_call_to ──────────
//
// `iter_calls_to(forms, keyword)` lifts the per-form projection
// `as_call_to` onto a `&[Sexp]`, yielding the args tails of every
// matching form in source order — the substrate's typed-keyword
// filter over a batch of forms. The two inline `for form in
// &expanded { if let Some(args) = form.as_call_to(T::KEYWORD) { … } }`
// walks at the `compile_typed` + `compile_named_from_forms` dispatch
// sites (compile.rs) collapse to ONE `iter_calls_to(&expanded,
// T::KEYWORD)` call. Tests pin the slice-side primitive's contract
// directly; the existing dispatch tests in compile.rs are the
// path-uniformity guards proving the two consumers route through it
// without behavior drift.
#[test]
fn iter_calls_to_yields_args_for_every_matching_form_in_slice() {
// Three forms: two match "defmonitor", one matches "defalert".
// `iter_calls_to("defmonitor")` yields the two matching args
// slices in source order — the matched forms' tails verbatim,
// skipping the non-matching `defalert` form silently.
let forms = vec![
Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("a"),
]),
Sexp::List(vec![
Sexp::symbol("defalert"),
Sexp::keyword("name"),
Sexp::string("p"),
]),
Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("b"),
]),
];
let args: Vec<&[Sexp]> = iter_calls_to(&forms, "defmonitor").collect();
assert_eq!(args.len(), 2);
assert_eq!(args[0], &[Sexp::keyword("name"), Sexp::string("a")][..]);
assert_eq!(args[1], &[Sexp::keyword("name"), Sexp::string("b")][..]);
}
#[test]
fn iter_calls_to_skips_every_non_call_shape_silently() {
// Every shape `as_call_to` rejects, `iter_calls_to` skips: non-
// lists (atoms across all 6 atom kinds, Nil, quote-family
// wrapper), the empty list, and non-symbol-head lists. Pin
// path-uniformity with the per-form sibling: passing ANY keyword
// against a slice of non-call shapes yields zero items. Closes
// the soft-projection posture at the slice level — a regression
// that admits a non-call shape (e.g. accepting a bare symbol
// whose name matches the keyword) fails here.
let forms = vec![
Sexp::symbol("foo"),
Sexp::int(5),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::boolean(true),
Sexp::float(1.5),
Sexp::Nil,
Sexp::Quote(Box::new(Sexp::symbol("foo"))),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::keyword("foo"), Sexp::symbol("a")]),
];
for k in ["foo", "anything", "", "defpoint"] {
let args: Vec<&[Sexp]> = iter_calls_to(&forms, k).collect();
assert!(
args.is_empty(),
"non-call slice must yield zero items for keyword {k:?}, got {} items",
args.len()
);
}
}
#[test]
fn iter_calls_to_yields_empty_args_slice_for_singleton_matching_call() {
// `(defcompiler)` — the head matches and the args tail is the
// empty slice. Pin the empty-tail posture: `iter_calls_to` must
// yield `Some(&[])` for the matching singleton (NOT skip it),
// mirroring `as_call_to`'s contract — the (possibly-empty) args
// slice on a match, NOT `None` on an empty tail. This is exactly
// the input `compile_named_from_forms` dispatches on before
// rejecting the missing NAME via `rest.split_first()`'s `None`.
let forms = vec![Sexp::List(vec![Sexp::symbol("defcompiler")])];
let args: Vec<&[Sexp]> = iter_calls_to(&forms, "defcompiler").collect();
assert_eq!(args.len(), 1);
assert_eq!(args[0], &[][..]);
}
#[test]
fn iter_calls_to_yields_nothing_for_empty_slice() {
// An empty forms slice yields zero items regardless of keyword.
// Pin the slice-side primitive's degenerate boundary: empty in,
// empty out — the iterator is fused-empty without consulting
// `as_call_to` at all.
let forms: Vec<Sexp> = vec![];
let mut iter = iter_calls_to(&forms, "anything");
assert!(iter.next().is_none());
}
#[test]
fn iter_calls_to_yields_nothing_when_keyword_matches_no_form() {
// A slice of valid call forms whose heads none match the
// requested keyword yields zero items. Pin path-uniformity with
// the per-form sibling: every form's `as_call_to(missing)` is
// `None`, so the slice-side iterator yields nothing — the filter
// fires uniformly across the batch.
let forms = vec![
Sexp::List(vec![Sexp::symbol("defmonitor"), Sexp::int(1)]),
Sexp::List(vec![Sexp::symbol("defalert"), Sexp::int(2)]),
Sexp::List(vec![Sexp::symbol("defpoint"), Sexp::int(3)]),
];
let args: Vec<&[Sexp]> = iter_calls_to(&forms, "missing").collect();
assert!(args.is_empty());
}
#[test]
fn iter_calls_to_args_borrow_is_same_pointer_as_per_form_as_call_to_tail() {
// The structural identity binding `iter_calls_to` to its per-form
// sibling: each yielded `&[Sexp]` IS the same slice `as_call_to`
// would return as the tail component for the corresponding form
// (pinned via `std::ptr::eq` on `as_ptr()`). The soft-projection
// contract is borrow, not clone, AND `iter_calls_to` inherits the
// contract verbatim from `as_call_to`. Parallel to the
// `as_call_to_args_borrow_is_same_pointer_as_as_call_tail` pin
// for `as_call_to`.
let forms = vec![Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("a"),
])];
let via_iter: &[Sexp] = iter_calls_to(&forms, "defmonitor")
.next()
.expect("one match");
let via_per_form: &[Sexp] = forms[0].as_call_to("defmonitor").expect("one match");
assert!(
std::ptr::eq(via_iter.as_ptr(), via_per_form.as_ptr()),
"iter_calls_to args must borrow the SAME slice as as_call_to's tail"
);
assert_eq!(via_iter.len(), via_per_form.len());
}
#[test]
fn iter_calls_to_is_the_slice_side_projection_of_as_call_to() {
// The structural identity the lift establishes:
// `iter_calls_to(forms, k) == forms.iter().filter_map(|f| f.as_call_to(k))`
// Pin shape AND ordering AND pointer-identity across mixed inputs
// and a range of keywords (including matching, non-matching, and
// edge-case empty/case-mismatched keywords) so a regression that
// drifts the slice-side projection from its closed-form
// definition fails loudly. The five soft-projection primitives —
// `head_symbol`, `as_call`, `as_call_to`, `as_call_to_any`, AND
// `iter_calls_to` — must agree on operator-position recognition
// at every shape/slice they share.
let forms = vec![
Sexp::symbol("foo"),
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(1)]),
Sexp::Nil,
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(2)]),
Sexp::int(99),
Sexp::List(vec![Sexp::symbol("b"), Sexp::int(3)]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::keyword("a"), Sexp::int(4)]),
];
for k in ["a", "b", "c", "", "A"] {
let via_iter: Vec<&[Sexp]> = iter_calls_to(&forms, k).collect();
let via_chain: Vec<&[Sexp]> = forms.iter().filter_map(|f| f.as_call_to(k)).collect();
assert_eq!(
via_iter.len(),
via_chain.len(),
"len drift for keyword {k:?}"
);
for (a, b) in via_iter.iter().zip(via_chain.iter()) {
assert!(
std::ptr::eq(a.as_ptr(), b.as_ptr()),
"ptr drift at keyword {k:?}: iter slice does not borrow the SAME tail as the per-form chain"
);
assert_eq!(a.len(), b.len(), "len drift at keyword {k:?}");
}
}
}
// ── iter_calls_to_any: the typed-decoded slice-side projection ──────
//
// `iter_calls_to_any(forms, decode)` lifts the per-form projection
// `as_call_to_any` onto a `&[Sexp]`, yielding the `(decoded,
// &[Sexp])` pair of every form whose head decodes through `decode`
// — the substrate's typed-decoded filter over a batch of forms,
// closing the (per-form, slice-side) × (keyword, classifier) 2×2
// of soft-dispatch primitives at the slice-side classifier corner.
// The slice-side keyword projection `iter_calls_to` now routes
// through THIS primitive with a constant-keyword decoder, so the
// filter-and-fuse implementation lives at ONE site on the slice
// algebra. Tests pin the slice-side primitive's contract directly
// alongside the (slice-side keyword, slice-side classifier)
// composition law that the keyword projection's re-routing
// establishes.
#[test]
fn iter_calls_to_any_yields_decoded_pair_for_every_matching_form_in_slice() {
// Three forms: two decode through `Op::from_keyword`, one does
// not (the head `"defalert"` is outside the closed set). The
// typed-decoded slice walk yields the `(decoded, args)` pair
// for each matching form in source order, skipping non-decoding
// forms silently — parallel to how `iter_calls_to` yields ONLY
// the args slice for keyword-matching forms.
#[derive(Debug, PartialEq, Eq)]
enum Op {
Defmonitor,
Defpoint,
}
impl Op {
fn from_keyword(h: &str) -> Option<Self> {
match h {
"defmonitor" => Some(Self::Defmonitor),
"defpoint" => Some(Self::Defpoint),
_ => None,
}
}
}
let forms = vec![
Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("a"),
]),
Sexp::List(vec![
Sexp::symbol("defalert"),
Sexp::keyword("name"),
Sexp::string("p"),
]),
Sexp::List(vec![
Sexp::symbol("defpoint"),
Sexp::keyword("name"),
Sexp::string("b"),
]),
];
let decoded: Vec<(Op, &[Sexp])> = iter_calls_to_any(&forms, Op::from_keyword).collect();
assert_eq!(decoded.len(), 2);
assert_eq!(decoded[0].0, Op::Defmonitor);
assert_eq!(
decoded[0].1,
&[Sexp::keyword("name"), Sexp::string("a")][..]
);
assert_eq!(decoded[1].0, Op::Defpoint);
assert_eq!(
decoded[1].1,
&[Sexp::keyword("name"), Sexp::string("b")][..]
);
}
#[test]
fn iter_calls_to_any_skips_every_shape_per_form_sibling_rejects() {
// Every shape `as_call_to_any` rejects, `iter_calls_to_any`
// skips: non-list shapes, the empty list, non-symbol-head
// lists, AND lists whose head is a symbol the decoder rejects.
// Pin the soft-projection contract at the slice level —
// parallel to `iter_calls_to_skips_every_non_call_shape_silently`
// but with the decoder rejection axis added so the per-form
// sibling's two rejection sources (shape-level + decoder-level)
// both route through the slice-side filter uniformly.
let forms = vec![
Sexp::symbol("foo"),
Sexp::int(5),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::boolean(true),
Sexp::float(1.5),
Sexp::Nil,
Sexp::Quote(Box::new(Sexp::symbol("foo"))),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(5), Sexp::symbol("a")]),
Sexp::List(vec![Sexp::keyword("foo"), Sexp::symbol("a")]),
// A call whose head IS a symbol but the decoder rejects —
// this is the decoder-level rejection axis the per-form
// sibling's classifier closure adds beyond the keyword
// sibling's `head == k` axis.
Sexp::List(vec![Sexp::symbol("unknown-head"), Sexp::int(1)]),
];
let decoded: Vec<(&'static str, &[Sexp])> =
iter_calls_to_any(&forms, |_h: &str| None::<&'static str>).collect();
assert!(
decoded.is_empty(),
"non-call / decoder-rejecting slice must yield zero items, got {} items",
decoded.len()
);
}
#[test]
fn iter_calls_to_any_yields_empty_args_slice_for_singleton_decoded_call() {
// `(defcompiler)` decoded through a classifier that accepts
// the head — the args tail is the empty slice. Pin the
// empty-tail posture: the typed-decoded slice walk must yield
// `(decoded, &[])` for the matching singleton (NOT skip it),
// mirroring the per-form sibling's contract — the
// (possibly-empty) args slice on a decoded match, NOT `None`
// on an empty tail. Parallel to
// `iter_calls_to_yields_empty_args_slice_for_singleton_matching_call`
// for the keyword sibling and
// `as_call_to_any_yields_empty_args_for_singleton_decoded_call`
// for the per-form sibling.
let forms = vec![Sexp::List(vec![Sexp::symbol("defcompiler")])];
let decoded: Vec<(&'static str, &[Sexp])> = iter_calls_to_any(&forms, |h: &str| {
(h == "defcompiler").then_some("defcompiler")
})
.collect();
assert_eq!(decoded.len(), 1);
assert_eq!(decoded[0].0, "defcompiler");
assert_eq!(decoded[0].1, &[][..]);
}
#[test]
fn iter_calls_to_any_yields_nothing_for_empty_slice() {
// An empty forms slice yields zero items regardless of
// decoder. Pin the slice-side primitive's degenerate boundary:
// empty in, empty out — the iterator is fused-empty without
// consulting `as_call_to_any` at all. The decoder's body must
// never run (we assert with an explicitly-panicking closure
// body to prove the fused-empty contract holds before the
// per-form sibling is consulted). Parallel to
// `iter_calls_to_yields_nothing_for_empty_slice` for the
// keyword sibling.
let forms: Vec<Sexp> = vec![];
let mut iter = iter_calls_to_any(&forms, |_h: &str| -> Option<()> {
panic!("decoder must not run on an empty forms slice")
});
assert!(iter.next().is_none());
}
#[test]
fn iter_calls_to_any_args_borrow_is_same_pointer_as_per_form_as_call_to_any_tail() {
// The structural identity binding `iter_calls_to_any` to its
// per-form sibling: each yielded `&[Sexp]` IS the same slice
// `as_call_to_any` would return as the tail component for the
// corresponding form (pinned via `std::ptr::eq` on `as_ptr()`).
// The soft-projection contract is borrow, not clone, AND
// `iter_calls_to_any` inherits the contract verbatim from
// `as_call_to_any`. Parallel to the
// `iter_calls_to_args_borrow_is_same_pointer_as_per_form_as_call_to_tail`
// pin for the keyword sibling and the
// `as_call_to_any_args_borrow_is_same_pointer_as_as_call_tail`
// pin for the per-form sibling.
let forms = vec![Sexp::List(vec![
Sexp::symbol("defmonitor"),
Sexp::keyword("name"),
Sexp::string("a"),
])];
let (_, via_iter): (&'static str, &[Sexp]) = iter_calls_to_any(&forms, |h: &str| {
(h == "defmonitor").then_some("defmonitor")
})
.next()
.expect("one decoded match");
let (_, via_per_form): (&'static str, &[Sexp]) = forms[0]
.as_call_to_any(|h: &str| (h == "defmonitor").then_some("defmonitor"))
.expect("one decoded match");
assert!(
std::ptr::eq(via_iter.as_ptr(), via_per_form.as_ptr()),
"iter_calls_to_any args must borrow the SAME slice as as_call_to_any's tail"
);
assert_eq!(via_iter.len(), via_per_form.len());
}
#[test]
fn iter_calls_to_any_is_the_slice_side_projection_of_as_call_to_any() {
// The structural identity the lift establishes:
// iter_calls_to_any(forms, decode) ==
// forms.iter().filter_map(|f| f.as_call_to_any(&mut decode))
// Pin shape AND ordering AND pointer-identity across mixed
// inputs and a range of decoders (closed-set classifier,
// always-accept identity, always-reject `None`, partial
// closed-set on a single head) so a regression that drifts
// the slice-side projection from its closed-form definition
// fails loudly. The six soft-projection primitives —
// `head_symbol`, `as_call`, `as_call_to`, `as_call_to_any`,
// `iter_calls_to`, AND `iter_calls_to_any` — must agree on
// operator-position recognition at every shape/slice they
// share. Parallel to
// `iter_calls_to_is_the_slice_side_projection_of_as_call_to`
// for the keyword sibling.
let forms = vec![
Sexp::symbol("foo"),
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(1)]),
Sexp::Nil,
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(2)]),
Sexp::int(99),
Sexp::List(vec![Sexp::symbol("b"), Sexp::int(3)]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::keyword("a"), Sexp::int(4)]),
Sexp::List(vec![Sexp::symbol("c"), Sexp::int(5)]),
];
// Closed-set classifier: accept "a" and "c", reject everything
// else (including the call whose head is "b", to pin the
// decoder-level rejection axis the keyword sibling does not
// have).
let decode_set =
|h: &str| -> Option<&'static str> { matches!(h, "a" | "c").then_some("ac") };
let via_iter: Vec<(&'static str, &[Sexp])> =
iter_calls_to_any(&forms, decode_set).collect();
let via_chain: Vec<(&'static str, &[Sexp])> = forms
.iter()
.filter_map(|f| f.as_call_to_any(decode_set))
.collect();
assert_eq!(
via_iter.len(),
via_chain.len(),
"len drift between slice-side and per-form-chain"
);
for (a, b) in via_iter.iter().zip(via_chain.iter()) {
assert_eq!(a.0, b.0, "decoded drift");
assert!(
std::ptr::eq(a.1.as_ptr(), b.1.as_ptr()),
"ptr drift: slice-side does not borrow the SAME tail as the per-form chain"
);
assert_eq!(a.1.len(), b.1.len(), "len drift");
}
}
#[test]
fn iter_calls_to_routes_through_iter_calls_to_any_via_constant_classifier_composition() {
// The post-lift composition law binding the slice-side
// keyword projection to the slice-side classifier projection:
//
// iter_calls_to(forms, k) ==
// iter_calls_to_any(forms, |h| (h == k).then_some(())).map(|(_, a)| a)
//
// Pin shape AND ordering AND pointer-identity across a mixed
// slice and three representative keywords (matching some,
// matching none, edge-case empty string) so a regression that
// drifts `iter_calls_to`'s body away from the typed-decoded
// routing (e.g. re-inlines the `forms.iter().filter_map(|f|
// f.as_call_to(keyword))` triple directly) fails loudly even
// though the rendered slice-of-slices would still match the
// keyword sibling's output. The pointer-equality axis is
// load-bearing: a regression that re-derives the filter at
// both sites would yield byte-identical slices but with
// distinct closure-capture state, which the
// pointer-identity check rejects only because both routes
// share the SAME underlying form-tail borrow chain.
//
// Sibling-shape lift to prior-run `UnquoteForm::marker` ⊂
// `to_quote_form().prefix()` composition (commit 250c001) and
// `AtomKind::label` ⊂ `sexp_shape().label()` composition
// (commit 1db697f): both pin the invariant that a typed
// subset/keyword projection is structurally derived from its
// parent superset/classifier projection, not a parallel
// implementation the type system happens to not catch when
// the two drift.
let forms = vec![
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(1)]),
Sexp::List(vec![Sexp::symbol("b"), Sexp::int(2)]),
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(3)]),
Sexp::List(vec![Sexp::symbol("c"), Sexp::int(4)]),
Sexp::int(99),
];
for k in ["a", "missing", ""] {
let via_keyword: Vec<&[Sexp]> = iter_calls_to(&forms, k).collect();
let via_classifier: Vec<&[Sexp]> =
iter_calls_to_any(&forms, |h: &str| (h == k).then_some(()))
.map(|(_, a)| a)
.collect();
assert_eq!(
via_keyword.len(),
via_classifier.len(),
"len drift between keyword projection and classifier composition for k={k:?}"
);
for (a, b) in via_keyword.iter().zip(via_classifier.iter()) {
assert!(
std::ptr::eq(a.as_ptr(), b.as_ptr()),
"ptr drift at k={k:?}: keyword projection does not share the SAME borrow with the classifier composition"
);
assert_eq!(a.len(), b.len(), "len drift at k={k:?}");
}
}
}
#[test]
fn iter_calls_to_any_admits_fnmut_classifier_maintaining_state_across_batch_walk() {
// The slice-side primitive's `FnMut` constraint (vs the
// per-form sibling's `FnOnce`) admits a classifier that
// captures mutable state — a counter, a registry cache, a
// visited-set. Pin the mutable-state contract: a counter
// closure increments once per matching form (NOT once per
// call to `f.as_call_to_any(decode)` at every form, since
// `as_call_to_any` short-circuits before running `decode` on
// non-list / empty-list / non-symbol-head shapes — only forms
// that pass the shape gate reach the decoder). The counter's
// post-walk value pins the exact number of forms that
// (a) passed the shape gate AND (b) had a head matching the
// classifier's predicate.
let forms = vec![
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(1)]),
Sexp::int(99), // not a call — `as_call_to_any` short-circuits, decoder never runs
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(2)]),
Sexp::List(vec![Sexp::symbol("b"), Sexp::int(3)]),
Sexp::List(vec![]), // empty list — `as_call_to_any` short-circuits before decoder
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(4)]),
];
let mut decoder_calls = 0usize;
// Consume the iterator into a count (NOT a Vec) so the closure
// capture of `decoder_calls` is dropped at the iterator's end,
// releasing the mutable borrow before the post-walk assertions
// re-read `decoder_calls` immutably. A `Vec<((), &[Sexp])>`
// collection would inherit the closure's `'a` lifetime through
// the `iter_calls_to_any` return type's unified lifetime
// parameter and keep the mutable borrow live across the assert
// (the rust-borrow-checker contract — `decoded`'s lifetime
// ties to `min(forms, closure)` even though the items
// themselves only borrow from `forms`).
let decoded_count = iter_calls_to_any(&forms, |h: &str| {
decoder_calls += 1;
(h == "a").then_some(())
})
.count();
// Three forms have head "a"; one form has head "b"; the
// non-call shapes (Int + empty list) short-circuit before the
// decoder runs. Decoder is called 4 times (the 4 shape-gate-
// passing forms); yields 3 matches.
assert_eq!(
decoder_calls, 4,
"decoder must run once per shape-gate-passing form"
);
assert_eq!(
decoded_count, 3,
"three forms decode through the classifier"
);
}
// ── iter_named_calls_to_any / iter_named_calls_to: slice-side closure
// of the (slice × classifier × named) and (slice × constant × named)
// corners of the soft-dispatch cube. Pre-lift the named gate
// composition (`split_name_slot` over a classifier-decoded args
// tail) lived ONLY inside `Expander::expand_and_collect_named_calls_to_any`'s
// projection closure — the slice algebra had no named sibling to
// the bare [`iter_calls_to_any`]. Post-lift the gate is composed
// at the slice level and the Expander surface routes through it
// via the SAME `expand_program + iter + map + collect` pipeline
// the bare expander surface uses. The tests below pin the slice
// primitive's contract DIRECTLY — independent of the Expander
// surface — so a classifier-NAME consumer that already holds
// expanded forms (a `tatara-check` runner, an LSP buffer walker,
// a REPL exhaustive lister) sees the SAME `NamedFormMissingName`
// / `NamedFormNonSymbolName` rejection chain the Expander
// consumer sees through the surface method.
#[test]
fn iter_named_calls_to_any_yields_decoded_triple_for_every_matching_named_form_in_slice() {
// Closed-set classifier (`Kind::{Foo, Bar}`) that rejects one head
// out of three on a slice. Every matching form yields a
// `Result<(Kind, &str, &[Sexp])>` triple in source order; the
// unmatched form is skipped silently (NOT yielded as `Err`).
// Fail-before-pass-after: this assert requires the slice
// primitive to exist AND to yield the typed witness ALONGSIDE
// the borrowed NAME slot AND the borrowed spec args tail — pre-
// lift the slice algebra had no named sibling; consumers had
// to re-derive the four-step `iter_calls_to_any(forms,
// decode).map(|(d, args)| split_name_slot(args, k).map(|(n,
// r)| (d, n, r)))` composition at their call site.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Kind {
Foo,
Bar,
}
let forms = crate::reader::read(
"(deffoo alpha 1) (defbaz gamma 2) (defbar beta 3) (deffoo delta 4)",
)
.unwrap();
let yielded: Vec<(Kind, String, usize)> =
super::iter_named_calls_to_any(&forms, |h: &str| match h {
"deffoo" => Some((Kind::Foo, "deffoo")),
"defbar" => Some((Kind::Bar, "defbar")),
_ => None,
})
.map(|maybe_triple| {
maybe_triple.map(|(kind, name, args)| (kind, name.to_string(), args.len()))
})
.collect::<crate::error::Result<Vec<_>>>()
.expect("slice-side named-classifier walk must succeed on well-formed forms");
assert_eq!(
yielded,
vec![
(Kind::Foo, "alpha".to_string(), 1),
(Kind::Bar, "beta".into(), 1),
(Kind::Foo, "delta".into(), 1),
],
"iter_named_calls_to_any must yield (decoded, NAME, args_len) in source order, skipping defbaz",
);
}
#[test]
fn iter_named_calls_to_any_skips_every_non_matching_form_shape_silently() {
// Soft-projection contract: the slice primitive must skip every
// shape the classifier rejects — non-list atoms, empty lists,
// lists with non-symbol heads, lists with unrecognized symbol
// heads — WITHOUT emitting the `NamedFormMissingName` /
// `NamedFormNonSymbolName` variants. The named gate fires ONLY
// for matched-keyword forms whose NAME slot is malformed, NEVER
// for forms the classifier filtered out first.
let forms = crate::reader::read(r#":kw "str" 42 () (unrecognized x) (5 y)"#).unwrap();
let yielded: Vec<()> = super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "deffoo").then_some(((), "deffoo"))
})
.map(|maybe_triple| maybe_triple.map(|_| ()))
.collect::<crate::error::Result<Vec<_>>>()
.expect("slice-side named-classifier walk must succeed when zero forms match");
assert!(
yielded.is_empty(),
"slice-side named-classifier walk must yield empty Vec when zero forms match",
);
}
#[test]
fn iter_named_calls_to_any_emits_named_form_missing_name_for_matched_form_with_no_name_slot() {
// `(deffoo)` — head matches the classifier (yielding the typed
// witness AND the classifier-supplied static keyword), but the
// NAME slot is missing. `split_name_slot`'s arity gate fires
// inside the slice primitive and emits `NamedFormMissingName {
// keyword: "deffoo" }`. Pin that the keyword threaded through
// is the CLASSIFIER-supplied keyword (NOT a hardcoded fallback,
// NOT the form's head symbol) — a regression that drifted the
// keyword binding from `decode`'s tuple's second element to the
// head symbol or to a constant would fail loudly here.
let forms = crate::reader::read("(deffoo)").unwrap();
let mut iter = super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "deffoo").then_some(((), "deffoo"))
});
let first = iter.next().expect("matched form must yield an item");
let err = first.expect_err("matched form with missing NAME must yield Err");
assert!(
matches!(
err,
crate::error::LispError::NamedFormMissingName { keyword: "deffoo" }
),
"expected NamedFormMissingName {{ keyword: \"deffoo\" }} through slice primitive, got: {err:?}"
);
}
#[test]
fn iter_named_calls_to_any_emits_named_form_non_symbol_name_for_matched_form_with_int_name() {
// `(deffoo 42)` — head matches and the NAME-slot arity gate
// passes, but the NAME slot's shape gate rejects the int
// literal. Pin that BOTH the classifier-supplied keyword AND
// the typed `SexpShape::Int` projection flow into the
// structural variant, identically to how
// `Expander::expand_and_collect_named_calls_to_any` emits the
// same variant when its projection composes the same gate.
let forms = crate::reader::read("(deffoo 42)").unwrap();
let mut iter = super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "deffoo").then_some(((), "deffoo"))
});
let first = iter.next().expect("matched form must yield an item");
let err = first.expect_err("matched form with non-symbol NAME must yield Err");
assert!(
matches!(
err,
crate::error::LispError::NamedFormNonSymbolName {
keyword: "deffoo",
got: crate::error::SexpShape::Int,
}
),
"expected NamedFormNonSymbolName {{ keyword: \"deffoo\", got: Int }} through slice primitive, got: {err:?}"
);
}
#[test]
fn iter_named_calls_to_any_emits_named_form_non_symbol_name_for_matched_form_with_keyword_name()
{
// `(deffoo :name)` — sibling shape pin to the int case: a
// matched form whose NAME slot is a keyword. Together with the
// int case this closes path-uniformity across distinct
// non-symbol-or-string `SexpShape` cells at the slice primitive
// boundary — every consumer routes through the SAME gate
// composition regardless of the offending shape.
let forms = crate::reader::read("(deffoo :name)").unwrap();
let mut iter = super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "deffoo").then_some(((), "deffoo"))
});
let first = iter.next().expect("matched form must yield an item");
let err = first.expect_err("matched form with keyword NAME must yield Err");
assert!(
matches!(
err,
crate::error::LispError::NamedFormNonSymbolName {
keyword: "deffoo",
got: crate::error::SexpShape::Keyword,
}
),
"expected NamedFormNonSymbolName {{ keyword: \"deffoo\", got: Keyword }} through slice primitive, got: {err:?}"
);
}
#[test]
fn iter_named_calls_to_any_accepts_string_name_slot_routing_past_the_gate() {
// `(deffoo "quoted-name" :k v)` — NAME slot is a string
// literal, which `as_symbol_or_string` (inside `split_name_slot`)
// accepts alongside symbols. Pin that the slice primitive
// erases the quote-vs-symbol distinction at the boundary so a
// consumer sees ONE `&str` shape regardless of authoring
// choice, matching the equivalent gate in the typed-domain
// consumer downstream of `named_form_projection<T>`.
let forms = crate::reader::read(r#"(deffoo "quoted-name" :k "v")"#).unwrap();
let yielded: Vec<(String, usize)> = super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "deffoo").then_some(((), "deffoo"))
})
.map(|maybe_triple| maybe_triple.map(|(_, name, args)| (name.to_string(), args.len())))
.collect::<crate::error::Result<Vec<_>>>()
.expect("string-author NAME slot must route past gate");
assert_eq!(yielded, vec![("quoted-name".into(), 2)]);
}
#[test]
fn iter_named_calls_to_any_short_circuits_on_first_malformed_name_under_collect() {
// `(deffoo good 1) (deffoo) (deffoo also-good 2)` — three
// matched forms; the SECOND has no NAME slot. Pin that
// `.collect::<Result<Vec<_>, _>>()` short-circuits at the
// second form (yielding `Err`) WITHOUT yielding the third
// form's payload. The iterator's lazy iteration combined with
// `Result::collect`'s short-circuit gives consumers
// first-failure semantics at the slice boundary, identical to
// how `Expander::expand_and_collect_named_calls_to_any` already
// short-circuits.
let forms = crate::reader::read("(deffoo good 1) (deffoo) (deffoo also-good 2)").unwrap();
let collected: crate::error::Result<Vec<()>> =
super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "deffoo").then_some(((), "deffoo"))
})
.map(|maybe_triple| maybe_triple.map(|_| ()))
.collect();
let err = collected.expect_err("collect must surface the first failure");
assert!(
matches!(
err,
crate::error::LispError::NamedFormMissingName { keyword: "deffoo" }
),
"expected NamedFormMissingName at the first malformed NAME, got: {err:?}"
);
}
#[test]
fn iter_named_calls_to_yields_name_and_spec_args_for_every_matching_form_in_slice() {
// Constant-keyword sibling of `iter_named_calls_to_any` —
// discards the `()` typed witness and yields `Result<(&str,
// &[Sexp])>` per matching form. Pin that the constant-keyword
// primitive yields the SAME source-ordered set of triples the
// typed-decoded sibling does on the same source, modulo the
// discarded typed witness.
let forms =
crate::reader::read("(defcheck alpha 1) (other beta) (defcheck gamma 2 3)").unwrap();
let yielded: Vec<(String, usize)> = super::iter_named_calls_to(&forms, "defcheck")
.map(|maybe_pair| maybe_pair.map(|(name, args)| (name.to_string(), args.len())))
.collect::<crate::error::Result<Vec<_>>>()
.expect("constant-keyword named slice walk must succeed on well-formed forms");
assert_eq!(
yielded,
vec![("alpha".into(), 1), ("gamma".into(), 2)],
"iter_named_calls_to must yield (NAME, args_len) in source order, skipping unrelated forms",
);
}
#[test]
fn iter_named_calls_to_routes_through_iter_named_calls_to_any_via_constant_classifier_composition(
) {
// Pin the closed-form composition law binding the constant-
// keyword named cell to the typed-decoded named-classifier cell
// at the slice algebra boundary:
//
// iter_named_calls_to(forms, k) ==
// iter_named_calls_to_any(forms, |h| (h == k).then_some(((), k)))
// .map(|maybe| maybe.map(|(_, n, a)| (n, a)))
//
// This makes the typed-decoded named-classifier slice primitive
// the CANONICAL composition point the constant-keyword sibling
// routes through — parallel to how `iter_calls_to` /
// `iter_calls_to_any` bind their composition law on the bare-
// kwargs axis at the slice level. A regression that drifts ONE
// sibling's pipeline from the other becomes loudly visible at
// this assertion.
let forms =
crate::reader::read("(defcheck alpha 1) (other beta) (defcheck gamma 2 3)").unwrap();
let via_constant: Vec<(String, usize)> = super::iter_named_calls_to(&forms, "defcheck")
.map(|maybe| maybe.map(|(name, args)| (name.to_string(), args.len())))
.collect::<crate::error::Result<Vec<_>>>()
.expect("constant-keyword named slice walk must succeed");
let via_classifier: Vec<(String, usize)> =
super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "defcheck").then_some(((), "defcheck"))
})
.map(|maybe| maybe.map(|(_, name, args)| (name.to_string(), args.len())))
.collect::<crate::error::Result<Vec<_>>>()
.expect("typed-decoded named slice walk with constant-classifier decoder must succeed");
assert_eq!(
via_constant, via_classifier,
"iter_named_calls_to(forms, k) must yield byte-identical payload to iter_named_calls_to_any(forms, |h| (h == k).then_some(((), k))).map(strip)",
);
}
#[test]
fn iter_named_calls_to_threads_static_keyword_through_missing_variant() {
// Path-uniformity at the constant-keyword slice primitive
// boundary: a static `&'static str` keyword threaded into the
// primitive routes verbatim through the
// `NamedFormMissingName.keyword` slot when a matched form has
// no NAME — same threading discipline `split_name_slot` pins at
// its boundary. Pin three distinct keywords ALL round-trip
// through the variant's keyword slot.
for keyword in ["defmonitor", "defalertpolicy", "defcheck"] {
let src = format!("({keyword})");
let forms = crate::reader::read(&src).unwrap();
let mut iter = super::iter_named_calls_to(&forms, keyword);
let first = iter.next().expect("matched form must yield an item");
let err = first.expect_err("matched form with missing NAME must yield Err");
match err {
crate::error::LispError::NamedFormMissingName { keyword: got } => {
assert_eq!(
got, keyword,
"constant-keyword slice primitive must thread keyword verbatim"
);
}
other => {
panic!("expected NamedFormMissingName for keyword {keyword:?}, got: {other:?}")
}
}
}
}
#[test]
fn iter_named_calls_to_any_admits_fnmut_classifier_maintaining_state_across_batch_walk() {
// The slice-side typed-decoded named primitive's `FnMut`
// classifier constraint admits a closure that captures mutable
// state across the batch walk — counter, registry cache,
// visited-set — matching the bare-kwargs slice sibling's
// contract. Pin: a counter-bumping decoder increments once per
// shape-gate-passing form (NOT once per slice element, since
// `iter_calls_to_any` short-circuits before the decoder on
// non-list / empty-list / non-symbol-head shapes), and the
// post-walk counter equals the number of forms that reached
// the decoder.
let forms =
crate::reader::read("(deffoo a 1) 42 (deffoo b 2) () (defbar c 3) (deffoo d 4)")
.unwrap();
let mut decoder_calls = 0usize;
let yielded: Vec<String> = super::iter_named_calls_to_any(&forms, |h: &str| {
decoder_calls += 1;
(h == "deffoo").then_some(((), "deffoo"))
})
.map(|maybe| maybe.map(|(_, name, _)| name.to_string()))
.collect::<crate::error::Result<Vec<_>>>()
.expect("FnMut classifier dispatch must succeed on well-formed NAME slots");
// Four (defX …) call forms in the slice pass the shape gate;
// the int atom and empty list short-circuit before the
// decoder. Three of the four pass-through-decoder forms
// dispatch to deffoo; one dispatches to defbar (rejected by
// the decoder).
assert_eq!(
decoder_calls, 4,
"FnMut decoder must run once per shape-gate-passing form (4 call forms)"
);
assert_eq!(
yielded,
vec!["a".to_string(), "b".into(), "d".into()],
"three (deffoo …) forms match; one (defbar …) form is rejected by the decoder",
);
}
#[test]
fn iter_named_calls_to_any_yields_borrowed_name_and_args_with_form_lifetime() {
// Pin the borrow-lifetime contract at the slice primitive
// boundary: the yielded `&'a str` NAME slot and `&'a [Sexp]`
// spec args tail must borrow from the input slice verbatim —
// no copy, no allocation. A consumer that holds the iterator's
// yields alongside the input slice borrow can use the NAME as
// a lookup key against a registry without paying for a clone.
let forms = crate::reader::read("(deffoo my-name :k 1 :j 2)").unwrap();
let mut iter = super::iter_named_calls_to_any(&forms, |h: &str| {
(h == "deffoo").then_some(((), "deffoo"))
});
let (_, name, spec_args) = iter
.next()
.expect("matched form must yield an item")
.expect("well-formed NAME slot must split");
// Identity-check the NAME borrow: it must point at the same
// bytes the form's NAME slot symbol borrows from.
let form_list = forms[0].as_list().expect("form must be a list");
let form_name = form_list[1]
.as_symbol()
.expect("form NAME must be a symbol");
assert!(
std::ptr::eq(name.as_ptr(), form_name.as_ptr()),
"iter_named_calls_to_any must yield the borrowed NAME, NOT an allocated copy"
);
// Spec args tail must borrow from the form's tail starting at
// index 2 (after the NAME slot at index 1).
assert!(
std::ptr::eq(spec_args.as_ptr(), &form_list[2] as *const Sexp),
"iter_named_calls_to_any must yield the borrowed spec args tail, NOT an allocated copy"
);
assert_eq!(spec_args.len(), 4);
}
// ── as_named_call_to_any / as_named_call_to: per-form × named cell ──
//
// The per-form × named corner of the soft-dispatch cube the slice
// primitive `iter_named_calls_to_any`'s docstring table identified as
// the documented gap pre-lift ("(composed inline at each named
// consumer)"). Post-lift the per-form × named row binds to ONE
// primitive every per-form named consumer composes through, and the
// slice-side `iter_named_calls_to_any` routes through it via the SAME
// `forms.iter().filter_map(_)` skeleton `iter_calls_to_any` uses to
// route through `as_call_to_any`. These tests pin: (a) the three-arm
// result shape (None for non-match, Some(Ok) for matched-and-
// well-formed, Some(Err) for matched-but-malformed-NAME) across each
// distinct shape, (b) the constant-keyword sibling routes through
// the typed-decoded sibling via constant-classifier composition, (c)
// the slice-side `iter_named_calls_to_any` IS the
// `forms.iter().filter_map(|f| f.as_named_call_to_any(_))` projection
// — the structural identity binding the per-form to the slice row.
#[test]
fn as_named_call_to_any_returns_decoded_triple_for_matched_well_formed_form() {
// `(deffoo my-name :k 1)` — head matches the classifier's `deffoo`
// arm, NAME slot is the symbol `my-name`, spec args tail is the
// two-element `:k 1` pair. Pin Some(Ok((decoded, name, args))).
// Fail-before-pass-after: this assert requires the per-form
// method to exist AND to thread the typed witness + borrowed
// NAME + borrowed spec args through ONE projection.
#[derive(Debug, PartialEq, Eq)]
enum Kind {
Foo,
}
let form = crate::reader::read("(deffoo my-name :k 1)").unwrap()[0].clone();
let res = form
.as_named_call_to_any(|h: &str| match h {
"deffoo" => Some((Kind::Foo, "deffoo")),
_ => None,
})
.expect("matched head must yield Some(_)")
.expect("well-formed NAME slot must split");
assert_eq!(res.0, Kind::Foo);
assert_eq!(res.1, "my-name");
assert_eq!(res.2.len(), 2);
}
#[test]
fn as_named_call_to_any_returns_none_when_decoder_rejects_head() {
// `(unrelated my-name :k 1)` — head is a symbol, but the
// classifier returns `None`. Pin: the classifier filter face is
// identical to `as_call_to_any` — `None` short-circuits BEFORE
// the named gate runs, so a non-matching head with a malformed
// NAME slot still yields `None`, NOT `Some(Err)`. The soft-
// filter face is preserved across the cube row.
let form = crate::reader::read("(unrelated my-name :k 1)").unwrap()[0].clone();
assert!(form
.as_named_call_to_any(|h: &str| (h == "deffoo").then_some(((), "deffoo")))
.is_none());
}
#[test]
fn as_named_call_to_any_returns_none_for_non_call_shapes() {
// Every shape `as_call_to_any` rejects, `as_named_call_to_any`
// rejects identically — atom, keyword, empty list, list with
// non-symbol head. The classifier-filter face is uniformly the
// soft per-form posture of every other `as_*` method on `Sexp`.
let shapes: Vec<Sexp> = vec![
Sexp::int(5),
Sexp::keyword("deffoo"),
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(1), Sexp::symbol("my-name")]),
];
for s in shapes {
assert!(
s.as_named_call_to_any(|h: &str| (h == "deffoo").then_some(((), "deffoo")))
.is_none(),
"non-call shape must yield None for as_named_call_to_any: {s}"
);
}
}
#[test]
fn as_named_call_to_any_returns_some_err_for_matched_head_with_no_name_slot() {
// `(deffoo)` — head matches the classifier's `deffoo` arm but
// the form is a singleton: NO NAME slot at all. The named gate
// (`split_name_slot`'s arity gate) fires structurally, yielding
// `Some(Err(LispError::NamedFormMissingName { keyword: "deffoo" }))`.
// Pin the strict-gate face on the named row: matched-and-
// malformed yields the typed structural rejection variant, NOT
// `None` (which would conflate "not our head" with "our head
// but missing NAME" and break the cube's strict-vs-soft split).
let form = crate::reader::read("(deffoo)").unwrap()[0].clone();
let err = form
.as_named_call_to_any(|h: &str| (h == "deffoo").then_some(((), "deffoo")))
.expect("matched head must yield Some(_)")
.expect_err("missing NAME slot must yield Err");
assert!(
matches!(
err,
crate::error::LispError::NamedFormMissingName { keyword: "deffoo" }
),
"expected NamedFormMissingName through per-form primitive, got: {err:?}"
);
}
#[test]
fn as_named_call_to_any_returns_some_err_for_matched_head_with_non_symbol_name() {
// `(deffoo 5 :k 1)` — head matches but NAME slot is an int
// literal. The named gate's `as_symbol_or_string` shape gate
// fires, yielding `Some(Err(LispError::NamedFormNonSymbolName
// { keyword: "deffoo", got: SexpShape::Int }))`. Pin the strict-
// gate face for the second structural rejection variant of the
// named gate AND the typed `SexpShape` projection of the
// offending slot.
let form = crate::reader::read("(deffoo 5 :k 1)").unwrap()[0].clone();
let err = form
.as_named_call_to_any(|h: &str| (h == "deffoo").then_some(((), "deffoo")))
.expect("matched head must yield Some(_)")
.expect_err("non-symbol NAME slot must yield Err");
assert!(
matches!(
err,
crate::error::LispError::NamedFormNonSymbolName {
keyword: "deffoo",
got: crate::error::SexpShape::Int,
}
),
"expected NamedFormNonSymbolName through per-form primitive, got: {err:?}"
);
}
#[test]
fn as_named_call_to_constant_keyword_routes_through_as_named_call_to_any() {
// Pin the closed-form composition binding the constant-keyword
// sibling to the typed-decoded sibling:
// as_named_call_to(k) ==
// as_named_call_to_any(|h| (h == k).then_some(((), k)))
// .map(|res| res.map(|(_, name, rest)| (name, rest)))
// across every shape in the test fixture set. A regression
// that re-implements the constant-keyword sibling without
// routing through the classifier sibling fails this assertion
// for the matched-and-well-formed AND matched-but-malformed
// AND non-match arms simultaneously.
let shapes: Vec<Sexp> = vec![
crate::reader::read("(defcompiler my-comp :a 1)").unwrap()[0].clone(),
crate::reader::read("(defcompiler)").unwrap()[0].clone(),
crate::reader::read("(defcompiler 5)").unwrap()[0].clone(),
crate::reader::read("(unrelated my-name :k 1)").unwrap()[0].clone(),
Sexp::int(99),
Sexp::List(vec![]),
];
// `LispError` is not `PartialEq` (it transitively wraps `Sexp`,
// which carries an `Atom::Float` whose `f64` is not `Eq`).
// Compare via formatted-debug strings on the Err arm; Ok arms and
// None arm compare structurally. The closed-form composition
// `as_named_call_to(k) == as_named_call_to_any+unit-decoder` is
// pinned across all three arms.
for s in &shapes {
let via_constant = s.as_named_call_to("defcompiler").map(|res| {
res.map(|(name, rest)| (name.to_string(), rest.len()))
.map_err(|e| format!("{e:?}"))
});
let via_classifier = s
.as_named_call_to_any(|h: &str| (h == "defcompiler").then_some(((), "defcompiler")))
.map(|res| {
res.map(|(_, name, rest)| (name.to_string(), rest.len()))
.map_err(|e| format!("{e:?}"))
});
assert_eq!(
via_constant, via_classifier,
"as_named_call_to(k) must equal as_named_call_to_any+unit-decoder for {s}"
);
}
}
#[test]
fn iter_named_calls_to_any_is_the_slice_side_filter_map_of_as_named_call_to_any() {
// Pin the structural identity binding the slice algebra to the
// per-form algebra:
// iter_named_calls_to_any(forms, decode) ==
// forms.iter().filter_map(|f| f.as_named_call_to_any(&mut decode))
// Both sides must yield the SAME Result shape per element in
// source order — `Ok(triple)` for matched-and-well-formed,
// `Err(LispError)` for matched-but-malformed, with non-matches
// skipped by the filter_map. Sibling pin to
// `iter_calls_to_any_is_the_slice_side_projection_of_as_call_to_any`
// on the bare-kwargs row — both rows now share ONE
// `forms.iter().filter_map(_)` skeleton.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Kind {
Foo,
Bar,
}
let src = "(deffoo a :k 1)
(other thing)
(defbar 7 :j 2)
(deffoo b)
(defbaz c :m 3)";
let forms = crate::reader::read(src).unwrap();
let decode = |h: &str| match h {
"deffoo" => Some((Kind::Foo, "deffoo")),
"defbar" => Some((Kind::Bar, "defbar")),
_ => None,
};
let via_iter: Vec<crate::error::Result<(Kind, String, usize)>> =
super::iter_named_calls_to_any(&forms, decode)
.map(|res| res.map(|(k, name, args)| (k, name.to_string(), args.len())))
.collect();
let via_filter_map: Vec<crate::error::Result<(Kind, String, usize)>> = forms
.iter()
.filter_map(|f| f.as_named_call_to_any(decode))
.map(|res| res.map(|(k, name, args)| (k, name.to_string(), args.len())))
.collect();
assert_eq!(
via_iter.len(),
via_filter_map.len(),
"slice-side iter must yield the same number of items as the per-form filter_map",
);
for (a, b) in via_iter.iter().zip(via_filter_map.iter()) {
match (a, b) {
(Ok(ta), Ok(tb)) => assert_eq!(ta, tb),
(Err(ea), Err(eb)) => assert_eq!(format!("{ea:?}"), format!("{eb:?}")),
_ => panic!(
"variant drift between slice iter and per-form filter_map: {a:?} vs {b:?}"
),
}
}
// Concretely: 3 matched forms (deffoo a, defbar 7, deffoo b);
// `defbar 7` yields Err (int NAME), other two yield Ok.
assert_eq!(via_iter.len(), 3);
assert!(via_iter[0].is_ok());
assert!(via_iter[1].is_err());
assert!(via_iter[2].is_ok());
}
#[test]
fn as_named_call_to_any_borrows_name_and_spec_args_from_form_verbatim() {
// Pin the borrow-lifetime contract at the per-form primitive
// boundary: the yielded `&str` NAME slot and `&[Sexp]` spec
// args tail must borrow from the underlying form verbatim — no
// copy, no allocation. Sibling pin to
// `iter_named_calls_to_any_yields_borrowed_name_and_args_with_form_lifetime`
// on the slice algebra — both rows preserve the borrow
// contract.
let forms = crate::reader::read("(deffoo my-name :k 1 :j 2)").unwrap();
let form = &forms[0];
let (_, name, spec_args) = form
.as_named_call_to_any(|h: &str| (h == "deffoo").then_some(((), "deffoo")))
.expect("matched head must yield Some(_)")
.expect("well-formed NAME slot must split");
let form_list = form.as_list().expect("form must be a list");
let form_name = form_list[1]
.as_symbol()
.expect("form NAME must be a symbol");
assert!(
std::ptr::eq(name.as_ptr(), form_name.as_ptr()),
"as_named_call_to_any must yield the borrowed NAME, NOT an allocated copy"
);
assert!(
std::ptr::eq(spec_args.as_ptr(), &form_list[2] as *const Sexp),
"as_named_call_to_any must yield the borrowed spec args tail, NOT an allocated copy"
);
assert_eq!(spec_args.len(), 4);
}
// ── as_unquote: the unquote-family projection ───────────────────────
//
// `as_unquote` lifts the per-callsite `Sexp::Unquote(inner) /
// Sexp::UnquoteSplice(inner)` arms paired with their `UnquoteForm::
// Unquote / UnquoteForm::Splice` literals — three sites pre-lift
// (`compile_node` 2 arms + `substitute` top-level + `substitute`
// list-inner) — into ONE typed projection on the `Sexp` algebra.
// These tests pin its contract; the existing path tests in
// macro_expand.rs are the path-uniformity guards proving the three
// sites route through it without behavior drift.
#[test]
fn as_unquote_decomposes_unquote_into_typed_marker_and_inner() {
// `,x` — Sexp::Unquote wrapping a symbol. Pin Some((Unquote, &inner)).
let inner = Sexp::symbol("x");
let form = Sexp::Unquote(Box::new(inner.clone()));
let (marker, body) = form
.as_unquote()
.expect("`,x` must project to Some((Unquote, _))");
assert_eq!(marker, UnquoteForm::Unquote);
assert_eq!(body, &inner);
}
#[test]
fn as_unquote_decomposes_unquote_splice_into_typed_marker_and_inner() {
// `,@xs` — Sexp::UnquoteSplice wrapping a symbol. Pin
// Some((Splice, &inner)). Sibling positive control to the Unquote
// arm: pins BOTH unquote-family variants project to their typed
// closed-set UnquoteForm pair through ONE projection function.
let inner = Sexp::symbol("xs");
let form = Sexp::UnquoteSplice(Box::new(inner.clone()));
let (marker, body) = form
.as_unquote()
.expect("`,@xs` must project to Some((Splice, _))");
assert_eq!(marker, UnquoteForm::Splice);
assert_eq!(body, &inner);
}
#[test]
fn as_unquote_none_for_non_unquote_shapes() {
// Every Sexp shape OUTSIDE the unquote family — atoms, lists, nil,
// and the OTHER quote-family variants (Quote `'x`, Quasiquote ``x`) —
// yields None. Pins the projection's exhaustive negative coverage:
// a regression that drifts the matched-variant set (e.g. a future
// emitter that projects `'x` into Some((Unquote, _))) would fail
// here, even before any downstream dispatcher tests fire.
assert_eq!(Sexp::symbol("foo").as_unquote(), None);
assert_eq!(Sexp::int(5).as_unquote(), None);
assert_eq!(Sexp::keyword("k").as_unquote(), None);
assert_eq!(Sexp::string("s").as_unquote(), None);
assert_eq!(Sexp::boolean(true).as_unquote(), None);
assert_eq!(Sexp::float(1.5).as_unquote(), None);
assert_eq!(Sexp::Nil.as_unquote(), None);
assert_eq!(Sexp::List(vec![]).as_unquote(), None);
assert_eq!(
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(1)]).as_unquote(),
None
);
// `'x` — Quote-family but NOT unquote-family. The closed-set
// UnquoteForm projection covers only `,` and `,@`; `'` and `` ` ``
// are siblings that this projection does NOT match.
assert_eq!(Sexp::Quote(Box::new(Sexp::symbol("x"))).as_unquote(), None);
assert_eq!(
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))).as_unquote(),
None
);
}
#[test]
fn as_unquote_is_some_iff_matches_unquote_family() {
// Structural identity: as_unquote().is_some() agrees with the
// pre-lift `matches!(self, Sexp::Unquote(_) | Sexp::UnquoteSplice(_))`
// discriminant across the closed Sexp variant set. Sweep every
// representative Sexp shape and pin equality of the two discriminants
// — a regression that drifts ONE shape's projection (e.g. adds
// Quasiquote to the matched set) becomes a typed test failure.
let shapes: Vec<(&str, Sexp, bool)> = vec![
("nil", Sexp::Nil, false),
("symbol", Sexp::symbol("x"), false),
("keyword", Sexp::keyword("k"), false),
("string", Sexp::string("s"), false),
("int", Sexp::int(7), false),
("float", Sexp::float(2.5), false),
("bool", Sexp::boolean(true), false),
("empty list", Sexp::List(vec![]), false),
(
"non-empty list",
Sexp::List(vec![Sexp::symbol("op")]),
false,
),
("quote", Sexp::Quote(Box::new(Sexp::symbol("x"))), false),
(
"quasiquote",
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))),
false,
),
("unquote", Sexp::Unquote(Box::new(Sexp::symbol("x"))), true),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
true,
),
];
for (label, sexp, expect_some) in &shapes {
let via_proj = sexp.as_unquote().is_some();
let via_pat = matches!(sexp, Sexp::Unquote(_) | Sexp::UnquoteSplice(_));
assert_eq!(
via_proj, *expect_some,
"as_unquote().is_some() drifted from expected at {label}"
);
assert_eq!(
via_proj, via_pat,
"as_unquote().is_some() != pre-lift `matches!(_, Unquote | UnquoteSplice)` at {label}"
);
}
}
#[test]
fn as_unquote_inner_pointer_is_the_boxed_body() {
// The returned `&Sexp` borrows the inner box's body verbatim — no
// clone, no allocation, same lifetime as `&self`. Pin pointer
// identity: the returned `&Sexp` shares its address with the
// contents of the original Box, proving no intermediate copy fires
// at the projection boundary (so consumers walking deeply nested
// template bodies pay zero allocation per unquote node).
let inner = Sexp::symbol("payload");
let boxed = Box::new(inner);
let inner_ptr: *const Sexp = boxed.as_ref();
let form = Sexp::Unquote(boxed);
let (_, body) = form
.as_unquote()
.expect("Sexp::Unquote must project to Some");
assert!(
std::ptr::eq(body, inner_ptr),
"as_unquote inner pointer drifted from the boxed body — projection allocates or clones"
);
let inner_splice = Sexp::symbol("payload-splice");
let boxed_splice = Box::new(inner_splice);
let inner_splice_ptr: *const Sexp = boxed_splice.as_ref();
let form_splice = Sexp::UnquoteSplice(boxed_splice);
let (_, body_splice) = form_splice
.as_unquote()
.expect("Sexp::UnquoteSplice must project to Some");
assert!(
std::ptr::eq(body_splice, inner_splice_ptr),
"as_unquote inner pointer drifted from the boxed body (splice arm)"
);
}
// ── fmt_float: Display→read round-trip preserves Float identity ──────
//
// Rust's stdlib Display for f64 elides trailing `.0` on integral
// floats — `format!("{}", 1.0_f64) == "1"` — and the substrate's
// reader tries `i64::parse` before `f64::parse`, so a bare `1` re-reads
// as `Atom::Int(1)`, NOT `Atom::Float(1.0)`. The Display→read
// round-trip pre-lift dropped the typed Float identity on every
// integral float: `Float(1.0)` displayed as `"1"`, re-read as `Int(1)`,
// and downstream consumers silently typed the slot as Int. The
// `fmt_float` helper appends `.0` for finite integral values so the
// round-trip preserves the typed identity. Tests below pin:
// (a) Display of `Float(1.0)` is `"1.0"` (fail-before-pass-after);
// (b) the Display→read round-trip lands as `Float(1.0)`, NOT
// `Int(1)` (the typed-identity preservation contract);
// (c) non-integral floats render unchanged through the default
// impl (`Float(1.5)` is still `"1.5"`);
// (d) negative integral floats inherit the `.0` suffix
// (`Float(-2.0)` is `"-2.0"`);
// (e) integer Display is unaffected (`Int(1)` is still `"1"`) —
// pin path-uniformity so the helper is precisely scoped to
// the Float arm.
#[test]
fn fmt_float_renders_integral_float_with_trailing_zero() {
// Fail-before-pass-after: pre-lift `Sexp::float(1.0).to_string()`
// was `"1"`; post-lift the typed Float identity is preserved by
// the `.0` suffix.
assert_eq!(Sexp::float(1.0).to_string(), "1.0");
assert_eq!(Sexp::float(100.0).to_string(), "100.0");
assert_eq!(Sexp::float(0.0).to_string(), "0.0");
}
#[test]
fn fmt_float_round_trips_integral_float_through_reader_as_float() {
// The structural contract the lift establishes: a `Float`
// serialized via `Display` re-reads as `Float`, NOT `Int`. Pin
// the round-trip via the reader so a regression that drops the
// `.0` suffix (or that re-orders the reader's i64/f64 parse
// attempts to drop the float arm) surfaces here.
let orig = Sexp::float(1.0);
let rendered = orig.to_string();
let forms =
crate::reader::read(&rendered).expect("integral float must round-trip through reader");
assert_eq!(forms.len(), 1);
match &forms[0] {
Sexp::Atom(Atom::Float(n)) => assert_eq!(*n, 1.0),
other => panic!("Display->read round-trip dropped the Float identity, got: {other:?}"),
}
// Sibling-shape control: a SECOND integral magnitude reinforces
// that the round-trip preserves the value, not only the type.
let orig2 = Sexp::float(-42.0);
let rendered2 = orig2.to_string();
let forms2 = crate::reader::read(&rendered2)
.expect("negative integral float must round-trip through reader");
match &forms2[0] {
Sexp::Atom(Atom::Float(n)) => assert_eq!(*n, -42.0),
other => panic!(
"Display->read of negative integral float dropped Float identity, got: {other:?}"
),
}
}
#[test]
fn fmt_float_preserves_non_integral_float_display() {
// Path-uniformity: non-integral floats (the case the stdlib impl
// already handled correctly) must render unchanged. A regression
// that always-appends `.0` would write `"1.5.0"` and fail
// here AND fail the reader round-trip below.
assert_eq!(Sexp::float(1.5).to_string(), "1.5");
assert_eq!(Sexp::float(0.99).to_string(), "0.99");
assert_eq!(Sexp::float(-2.75).to_string(), "-2.75");
// Round-trip control for the non-integral case stays valid: the
// helper is precisely scoped, so the fractional component is
// preserved verbatim through the reader.
let orig = Sexp::float(0.99);
let forms = crate::reader::read(&orig.to_string())
.expect("non-integral float must round-trip through reader");
match &forms[0] {
Sexp::Atom(Atom::Float(n)) => assert_eq!(*n, 0.99),
other => panic!("non-integral float round-trip drift, got: {other:?}"),
}
}
// ── QuoteForm + as_quote_form: closed-set quote-family projection ─────
//
// `as_quote_form` lifts the per-callsite `Sexp::Quote(inner)
// / Sexp::Quasiquote(inner) / Sexp::Unquote(inner) /
// Sexp::UnquoteSplice(inner)` arm-set paired with their
// per-variant prefix string (`'`, `` ` ``, `,`, `,@`) and
// discriminator byte (3, 4, 5, 6) into ONE typed projection on
// the `Sexp` algebra. Three consumers in this file route through
// it (`Hash for Sexp`, `Display for Sexp`, `Sexp::as_unquote`)
// so the (Sexp variant, marker, prefix, discriminator) tuple
// binds at ONE site. Tests below pin:
// (a) the projection lands `Some((QuoteForm::*, inner))` for
// each of the four wrapper variants AND `None` for every
// non-quote-family shape;
// (b) `QuoteForm::prefix` returns the canonical reader-token
// prefix for each variant — load-bearing for the round-trip
// property the `Display`→reader dual encodes;
// (c) `QuoteForm::hash_discriminator` returns the same byte
// values the pre-lift Hash arms emitted (3, 4, 5, 6) — pin
// the cache-key contract so a regression that drifts a
// discriminator silently invalidates every cached expansion
// fails loudly here;
// (d) `QuoteForm::as_unquote_form` projects the 2-of-4 subset
// `{Unquote → UnquoteForm::Unquote, UnquoteSplice →
// UnquoteForm::Splice}` and yields `None` for `{Quote,
// Quasiquote}` — the structural-subset gate the
// `Sexp::as_unquote` derivation routes through;
// (e) `Sexp::as_unquote` derived from `as_quote_form +
// QuoteForm::as_unquote_form` agrees with the pre-lift
// arm-based semantic across every Sexp shape — path
// uniformity across the subset gate;
// (f) the four homoiconic prefixes round-trip through the
// reader via `read(format!("{prefix}{inner}"))` into the
// matching `Sexp::*` variant — the typed dual of the
// reader's prefix dispatch, pinned end-to-end on the four
// wrappers (sibling to `fmt_float`'s Float round-trip pin
// at the Display→read boundary).
#[test]
fn as_quote_form_projects_each_wrapper_variant_to_typed_marker_and_inner() {
// `'foo` — Sexp::Quote wrapping a symbol. Pin Some((Quote, &inner))
// with the typed marker AND the borrowed inner body.
let inner = Sexp::symbol("foo");
let form = Sexp::Quote(Box::new(inner.clone()));
let (qf, body) = form.as_quote_form().expect("Sexp::Quote must project");
assert_eq!(qf, QuoteForm::Quote);
assert_eq!(body, &inner);
// `` `foo `` — Sexp::Quasiquote wrapping a symbol.
let form_qq = Sexp::Quasiquote(Box::new(inner.clone()));
let (qf_qq, body_qq) = form_qq
.as_quote_form()
.expect("Sexp::Quasiquote must project");
assert_eq!(qf_qq, QuoteForm::Quasiquote);
assert_eq!(body_qq, &inner);
// `,foo` — Sexp::Unquote wrapping a symbol.
let form_u = Sexp::Unquote(Box::new(inner.clone()));
let (qf_u, body_u) = form_u.as_quote_form().expect("Sexp::Unquote must project");
assert_eq!(qf_u, QuoteForm::Unquote);
assert_eq!(body_u, &inner);
// `,@xs` — Sexp::UnquoteSplice wrapping a symbol.
let form_us = Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs")));
let (qf_us, body_us) = form_us
.as_quote_form()
.expect("Sexp::UnquoteSplice must project");
assert_eq!(qf_us, QuoteForm::UnquoteSplice);
assert_eq!(body_us, &Sexp::symbol("xs"));
}
#[test]
fn as_quote_form_none_for_non_quote_family_shapes() {
// Every shape OUTSIDE the closed quote-family must project to
// None: Nil, every Atom variant, and List (empty + populated).
// Pin the closed-set boundary so a regression that accidentally
// promotes a non-wrapper variant into the quote family becomes
// a typed test failure.
assert_eq!(Sexp::Nil.as_quote_form(), None);
assert_eq!(Sexp::symbol("x").as_quote_form(), None);
assert_eq!(Sexp::keyword("k").as_quote_form(), None);
assert_eq!(Sexp::string("s").as_quote_form(), None);
assert_eq!(Sexp::int(7).as_quote_form(), None);
assert_eq!(Sexp::float(2.5).as_quote_form(), None);
assert_eq!(Sexp::boolean(true).as_quote_form(), None);
assert_eq!(Sexp::List(vec![]).as_quote_form(), None);
assert_eq!(
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]).as_quote_form(),
None
);
}
#[test]
fn as_quote_form_inner_pointer_is_the_boxed_body() {
// The returned `&Sexp` borrows the inner box's body verbatim —
// no clone, no allocation, same lifetime as `&self`. Pin
// pointer identity for each of the four wrapper variants so a
// regression that adds an intermediate copy at the projection
// boundary surfaces here. Same posture as
// `as_unquote_inner_pointer_is_the_boxed_body` for its 2-of-4
// subset.
let payload = Sexp::symbol("payload");
let boxed = Box::new(payload);
let inner_ptr: *const Sexp = boxed.as_ref();
let form = Sexp::Quote(boxed);
let (_, body) = form.as_quote_form().expect("Sexp::Quote must project");
assert!(
std::ptr::eq(body, inner_ptr),
"as_quote_form inner pointer drifted from the boxed body — projection allocates or clones"
);
let payload_qq = Sexp::symbol("payload-qq");
let boxed_qq = Box::new(payload_qq);
let inner_ptr_qq: *const Sexp = boxed_qq.as_ref();
let form_qq = Sexp::Quasiquote(boxed_qq);
let (_, body_qq) = form_qq
.as_quote_form()
.expect("Sexp::Quasiquote must project");
assert!(
std::ptr::eq(body_qq, inner_ptr_qq),
"as_quote_form inner pointer drifted (quasiquote arm)"
);
}
#[test]
fn expect_quote_form_projects_each_quote_family_variant_identically_to_as_quote_form() {
// ASSERTED-TOTAL-FACE CONTRACT: `expect_quote_form` is the
// asserted-total face of `as_quote_form` — for every quote-family
// variant it MUST yield the same `(QuoteForm, &Sexp)` projection
// that `as_quote_form` yields wrapped in `Some`. A regression
// that drifts the two projections (e.g. a future variant
// extension that updates `as_quote_form` but forgets to align
// `expect_quote_form`'s body) surfaces here.
let inner = Sexp::symbol("payload");
for variant in [
Sexp::Quote(Box::new(inner.clone())),
Sexp::Quasiquote(Box::new(inner.clone())),
Sexp::Unquote(Box::new(inner.clone())),
Sexp::UnquoteSplice(Box::new(inner.clone())),
] {
let via_total = variant.expect_quote_form();
let via_soft = variant.as_quote_form().expect("variant is quote-family");
assert_eq!(
via_total.0, via_soft.0,
"expect_quote_form's QuoteForm drifted from as_quote_form's at {variant}"
);
assert!(
std::ptr::eq(via_total.1, via_soft.1),
"expect_quote_form's inner pointer drifted from as_quote_form's at {variant}"
);
}
}
#[test]
fn expect_quote_form_panics_with_invariant_const_on_non_quote_family_variants() {
// STATIC-INVARIANT CONTRACT: every non-quote-family variant
// (Nil, every Atom subkind, List empty + populated) MUST trigger
// the asserted-total panic with the named
// `QUOTE_FAMILY_PROJECTION_INVARIANT` message. The const-vs-
// panic-payload pin catches a future drift where the const is
// edited without the projection picking it up (or vice versa).
for variant in [
Sexp::Nil,
Sexp::symbol("x"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(2.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
] {
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _ = variant.expect_quote_form();
}));
let payload = result.expect_err("expect_quote_form must panic on non-quote-family");
let msg = payload
.downcast_ref::<String>()
.map(String::as_str)
.or_else(|| payload.downcast_ref::<&'static str>().copied())
.expect("panic payload must be a string");
assert!(
msg.contains(QUOTE_FAMILY_PROJECTION_INVARIANT),
"expect_quote_form panic message {msg:?} did not name \
QUOTE_FAMILY_PROJECTION_INVARIANT at variant {variant:?}"
);
}
}
#[test]
fn quote_family_projection_invariant_const_matches_legacy_inline_literal() {
// CONST-PIN: pre-lift the panic literal "matched quote-family
// variant must project to Some via as_quote_form" appeared inline
// at FIVE production sites (`Hash for Sexp`, `Display for Sexp`,
// `domain::sexp_shape`, `domain::sexp_to_json`,
// `interop::iac_forge_tag`). Pin the lifted const to the legacy
// inline literal bit-for-bit so a regression that drifts the
// const silently from the historical diagnostic string surfaces
// here. Sibling shape to `quote_form_hash_discriminator_pins_
// legacy_cache_key_bytes` for the discriminator-byte algebra.
assert_eq!(
QUOTE_FAMILY_PROJECTION_INVARIANT,
"matched quote-family variant must project to Some via as_quote_form"
);
}
#[test]
fn quote_form_prefix_pins_canonical_reader_tokens_for_every_variant() {
// Pin every prefix string load-bearing for the Display→read
// round-trip. A regression that drifts the prefix (e.g. swaps
// `'` and `` ` `` between Quote and Quasiquote) silently
// re-routes every renderer through the wrong variant; this
// test fails loudly. Sibling-arm sweep so the (variant,
// prefix) pair stays load-bearing under reordering refactors.
assert_eq!(QuoteForm::Quote.prefix(), "'");
assert_eq!(QuoteForm::Quasiquote.prefix(), "`");
assert_eq!(QuoteForm::Unquote.prefix(), ",");
assert_eq!(QuoteForm::UnquoteSplice.prefix(), ",@");
}
// ── `QuoteForm::{QUOTE_PREFIX, QUASIQUOTE_PREFIX, UNQUOTE_PREFIX,
// UNQUOTE_SPLICE_PREFIX, PREFIXES}` — per-role `&'static str`
// reader-prefix algebra on the closed-set outer [`QuoteForm`]. Peer
// of [`crate::error::MacroDefHead::KEYWORDS`] (head-keyword
// algebra), [`Atom::BOOL_LITERALS`] (Scheme-bool spelling algebra),
// and [`crate::macro_expand::MacroParams::LAMBDA_LIST_KEYWORDS`]
// (CL lambda-list-keyword algebra) — every closed-set outer
// projection on the substrate now pins its canonical bytes at ONE
// `pub const` per role plus an ALL array for family-wide consumers.
#[test]
fn quote_form_quote_prefix_projects_canonical_single_quote_bytes() {
// Pin the exact `"'"` bytes at the typed constant. A regression
// that renames the constant to a different byte fails HERE
// rather than at silent reader-family drift where `'foo`
// classifies as a bare atom (or through a different quote-family
// variant) instead of `Sexp::Quote`.
assert_eq!(QuoteForm::QUOTE_PREFIX, "'");
}
#[test]
fn quote_form_quasiquote_prefix_projects_canonical_backtick_bytes() {
// Pin the exact `` "`" `` bytes at the typed constant. Sibling
// posture to `quote_form_quote_prefix_projects_canonical_single_quote_bytes`.
assert_eq!(QuoteForm::QUASIQUOTE_PREFIX, "`");
}
#[test]
fn quote_form_unquote_prefix_projects_canonical_comma_bytes() {
// Pin the exact `","` bytes at the typed constant.
assert_eq!(QuoteForm::UNQUOTE_PREFIX, ",");
}
#[test]
fn quote_form_unquote_splice_prefix_projects_canonical_comma_at_bytes() {
// Pin the exact `",@"` bytes at the typed constant — the ONLY
// two-char prefix on the closed set. A regression that lost the
// `@` discriminator (dropping to just `","`, colliding with
// `UNQUOTE_PREFIX`) surfaces HERE rather than as a silent
// reader classifier collision.
assert_eq!(QuoteForm::UNQUOTE_SPLICE_PREFIX, ",@");
}
#[test]
fn quote_form_prefix_routes_through_typed_per_role_constants() {
// PATH-UNIFORMITY: `Self::prefix(self)` returns the per-role
// `pub const` byte-for-byte per variant, catching a regression
// that reverts ONE arm to an inline `"'"` / `` "`" `` / `","`
// / `",@"` string literal (or drifts one arm's bytes silently).
// Sibling posture to
// `atom_bool_literal_routes_through_typed_per_variant_constants`
// on the Scheme-bool spelling algebra.
for (qf, expected) in [
(QuoteForm::Quote, QuoteForm::QUOTE_PREFIX),
(QuoteForm::Quasiquote, QuoteForm::QUASIQUOTE_PREFIX),
(QuoteForm::Unquote, QuoteForm::UNQUOTE_PREFIX),
(QuoteForm::UnquoteSplice, QuoteForm::UNQUOTE_SPLICE_PREFIX),
] {
let actual = qf.prefix();
assert_eq!(
actual, expected,
"QuoteForm::{qf:?}.prefix() `{actual}` drifted from \
per-role constant `{expected}` — the arm must route \
through the typed constant rather than an inline literal",
);
}
}
#[test]
fn quote_form_prefixes_has_expected_cardinality() {
// Cardinality contract: `Self::PREFIXES.len() == 4` — pinned at
// the declaration site by rustc's forced-arity check on
// `[&'static str; 4]`. This test surfaces the arity as a
// fail-loud runtime pin so a future refactor that switches the
// array type to `&[&'static str]` (dropping the compile-time
// arity forcing) doesn't silently loosen the closed-set
// discipline the family relies on. Sibling posture to
// `atom_bool_literals_has_expected_cardinality` and
// `macro_def_head_keywords_has_expected_cardinality`.
assert_eq!(
QuoteForm::PREFIXES.len(),
4,
"QuoteForm::PREFIXES cardinality drifted from 4 — the \
closed homoiconic-prefix domain admits exactly four \
wrappers by construction; a fifth extension surfaces here"
);
}
#[test]
fn quote_form_prefixes_align_with_all_by_index() {
// ALIGNMENT CONTRACT: `Self::PREFIXES[i] == Self::ALL[i].prefix()`
// element-wise. Pins that the typed variant ALL and the
// `&'static str` PREFIXES ALL stay in lockstep under any
// reorder — a regression that reorders ONE array without
// reordering the other silently misaligns every `zip(ALL,
// PREFIXES)` consumer (LSP completion providers, metric-label
// emitters, coverage reporters). Sibling posture to
// `macro_def_head_keywords_align_with_all_by_index`.
for (i, qf) in QuoteForm::ALL.iter().enumerate() {
assert_eq!(
QuoteForm::PREFIXES[i],
qf.prefix(),
"QuoteForm::PREFIXES[{i}] `{prefix}` drifted from \
QuoteForm::ALL[{i}] ({qf:?}).prefix() `{via_variant}` \
— the canonical declaration order of the ALL array \
and the prefix projection must match element-wise",
prefix = QuoteForm::PREFIXES[i],
via_variant = qf.prefix(),
);
}
}
#[test]
fn quote_form_prefixes_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every entry of the `PREFIXES` array
// must differ so the reader-entry classifier (whether inline
// as at [`crate::reader::tokenize`]'s outer arm or via a
// hypothetical future `PREFIXES.iter()` sweep) cannot route
// two homoiconic prefixes through the same arm. Family-wide
// sweep over `PREFIXES × PREFIXES` — supersedes any per-pair
// pin and picks up new prefixes mechanically. Sibling posture
// to `atom_bool_literals_pairwise_distinct` on the Scheme-bool
// algebra AND `macro_def_head_keywords_pairwise_distinct` on
// the head-keyword algebra.
for (i, a) in QuoteForm::PREFIXES.iter().enumerate() {
for (j, b) in QuoteForm::PREFIXES.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"QuoteForm::PREFIXES[{i}] `{a}` collides with \
QuoteForm::PREFIXES[{j}] `{b}` — the reader-entry \
classifier's cascade would route two homoiconic \
prefixes through the same arm"
);
}
}
}
#[test]
fn quote_form_per_role_prefixes_route_through_matching_lead_char_for_every_variant() {
// CROSS-AXIS ROUND-TRIP: every entry of `Self::PREFIXES` MUST
// start with the corresponding variant's `lead_char()` — the
// per-role `pub const` on the reader-prefix axis composes byte-
// for-byte with the per-role `char` on the reader-lead-byte axis
// ([`Self::QUOTE_LEAD`], [`Self::QUASIQUOTE_LEAD`],
// [`Self::UNQUOTE_LEAD`]) via the [`Self::lead_char`] projection.
// Both `Unquote` AND `UnquoteSplice` start with `UNQUOTE_LEAD`
// (the shared `,` lead byte) — the two-char splice prefix's
// second byte is [`Self::SPLICE_DISCRIMINATOR`], which the
// reader's peek-then-consume arm disambiguates on. Sibling
// posture to `atom_bool_literals_all_route_through_bool_literal_leading_byte`
// on the Scheme-bool spelling algebra.
for (i, qf) in QuoteForm::ALL.iter().enumerate() {
let prefix = QuoteForm::PREFIXES[i];
let expected_lead = qf.lead_char();
let actual_lead = prefix.chars().next().unwrap_or_else(|| {
panic!("QuoteForm::PREFIXES[{i}] `{prefix}` for {qf:?} must have at least one char")
});
assert_eq!(
actual_lead, expected_lead,
"QuoteForm::PREFIXES[{i}] `{prefix}` for {qf:?} — first \
char {actual_lead:?} drifted from lead_char {expected_lead:?} — \
the per-role prefix constant drifted from the shared \
lead byte"
);
}
}
#[test]
fn quote_form_unquote_splice_prefix_constant_composes_from_unquote_lead_and_splice_discriminator(
) {
// STRUCTURAL COMPOSITION LAW at the `pub const` level:
// [`Self::UNQUOTE_SPLICE_PREFIX`] decomposes cleanly into
// [`Self::UNQUOTE_LEAD`] + [`Self::SPLICE_DISCRIMINATOR`]. The
// ONLY two-char prefix on the closed set composes from the two
// `char`-level constants on the algebra. Section-for-retraction
// peer of the pre-existing
// `quote_form_unquote_splice_prefix_composes_from_unquote_lead_and_splice_discriminator`
// pin (which composes at the [`Self::prefix`] method level);
// where that pin composes through the runtime projection, this
// pin composes at the `pub const` level so a regression that
// drifts the two-char constant WITHOUT drifting the runtime
// projection (unlikely but structurally distinct) surfaces
// here.
let composed = format!(
"{}{}",
QuoteForm::UNQUOTE_LEAD,
QuoteForm::SPLICE_DISCRIMINATOR,
);
assert_eq!(
composed,
QuoteForm::UNQUOTE_SPLICE_PREFIX,
"QuoteForm::UNQUOTE_SPLICE_PREFIX drifted from UNQUOTE_LEAD + \
SPLICE_DISCRIMINATOR — the reader's two-char splice \
promotion identity is broken at the pub-const byte level",
);
}
#[test]
fn quote_form_lead_char_pins_first_char_of_prefix_for_every_variant() {
// Pin the (variant, lead char) pairing threaded through
// [`crate::reader::tokenize`]'s outer quote-family dispatch AND
// its bare-atom terminator disjunct. Quote/Quasiquote's
// singleton chars project to `'\''` / `` '`' `` respectively;
// Unquote AND UnquoteSplice BOTH project to `','` because the
// splice's two-char `,@` prefix shares its lead byte with bare
// unquote and the reader disambiguates on the peek-then-consume
// `@` second char. A regression that split the shared-lead-char
// collapse (e.g. gave UnquoteSplice a distinct lead char)
// silently re-shapes every splice tokenization; this test
// catches the drift at rustc + `cargo test` time rather than
// as an off-by-one reader miscue that surfaces only when a
// `,@xs` form parses wrong.
assert_eq!(QuoteForm::Quote.lead_char(), '\'');
assert_eq!(QuoteForm::Quasiquote.lead_char(), '`');
assert_eq!(QuoteForm::Unquote.lead_char(), ',');
assert_eq!(QuoteForm::UnquoteSplice.lead_char(), ',');
}
#[test]
fn quote_form_lead_char_is_first_char_of_prefix_for_every_variant() {
// COMPOSITION CONTRACT: `lead_char` MUST equal the first char of
// `prefix()` for every variant. Pin the composition so a
// regression that drifts one of the two projections (e.g. a
// rename of `Quote`'s prefix from `"'"` to `"‛"` without
// updating `lead_char`, or vice versa) surfaces immediately.
// The typed composition binds the (`QuoteForm`, lead char,
// full prefix) triple at ONE consistency check across every
// arm of the closed set — a future fifth homoiconic prefix
// extension must extend `prefix` AND `lead_char` in lockstep,
// and this sweep pins the invariant that connects them.
for qf in QuoteForm::ALL {
let prefix_first =
qf.prefix().chars().next().unwrap_or_else(|| {
panic!("QuoteForm::{qf:?} prefix must have at least one char")
});
assert_eq!(
qf.lead_char(),
prefix_first,
"QuoteForm::{qf:?} — lead_char {:?} drifted from first char of prefix {:?}",
qf.lead_char(),
qf.prefix(),
);
}
}
#[test]
fn quote_form_from_lead_char_decodes_every_distinct_lead_char_to_default_variant() {
// Pin the inverse projection at every distinct lead char across
// the closed set. Quote/Quasiquote decode to their singleton
// owners; `,` decodes to `Some(Unquote)` (the DEFAULT variant on
// the shared `,` lead char) — the `,@` splice promotion lives
// at the reader's peek arm, NOT at this decode. Every other
// char yields `None`. Includes the tokenizer's non-quote entry
// chars (`'('`, `')'`, `';'`, `Atom::STR_DELIMITER`, ` `) as
// the rejection sweep — a regression that leaks a quote-family
// variant onto a non-quote lead char silently re-shapes every
// top-level program's tokenization; this rejection sweep
// catches the drift at test time.
assert_eq!(QuoteForm::from_lead_char('\''), Some(QuoteForm::Quote));
assert_eq!(QuoteForm::from_lead_char('`'), Some(QuoteForm::Quasiquote));
assert_eq!(QuoteForm::from_lead_char(','), Some(QuoteForm::Unquote));
// Non-quote reader entry chars must reject.
assert_eq!(QuoteForm::from_lead_char('('), None);
assert_eq!(QuoteForm::from_lead_char(')'), None);
assert_eq!(QuoteForm::from_lead_char(';'), None);
assert_eq!(QuoteForm::from_lead_char(Atom::STR_DELIMITER), None);
assert_eq!(QuoteForm::from_lead_char(' '), None);
assert_eq!(QuoteForm::from_lead_char('a'), None);
assert_eq!(QuoteForm::from_lead_char('@'), None);
assert_eq!(QuoteForm::from_lead_char(':'), None);
assert_eq!(QuoteForm::from_lead_char('#'), None);
}
#[test]
fn quote_form_lead_char_round_trips_through_from_lead_char_with_shared_lead_char_collapse() {
// ROUND-TRIP CONTRACT: for every variant, decoding its
// `lead_char()` back through `from_lead_char` produces
// `Some(default_variant_on_that_lead_char)`. For the three
// variants with singleton lead chars (`Quote`, `Quasiquote`,
// `Unquote`) the round-trip is the identity. For `UnquoteSplice`
// — which shares `,` with `Unquote` — the round-trip yields
// `Some(QuoteForm::Unquote)` because `,` alone cannot signal
// splice; the reader's peek-then-consume `@` disambiguator is
// where the splice promotion happens. Pin this asymmetry so
// a regression that pushed the splice promotion into
// `from_lead_char` (a natural but wrong refactor) surfaces
// here at test time — decoupling the char-level decode from
// the streaming reader's two-char sequence is load-bearing
// for the tokenizer's structure.
for qf in QuoteForm::ALL {
let decoded = QuoteForm::from_lead_char(qf.lead_char());
let expected = match qf {
QuoteForm::Quote => Some(QuoteForm::Quote),
QuoteForm::Quasiquote => Some(QuoteForm::Quasiquote),
// Both `,`-lead-char variants collapse onto Unquote;
// splice promotion lives at the reader's peek arm.
QuoteForm::Unquote | QuoteForm::UnquoteSplice => Some(QuoteForm::Unquote),
};
assert_eq!(
decoded, expected,
"QuoteForm::{qf:?} — from_lead_char(lead_char) round-trip drifted",
);
}
}
#[test]
fn quote_form_from_lead_char_is_const_fn_over_the_closed_set() {
// Pin the `const fn` posture of both projections by binding a
// `const` array literal keyed on the closed set. A regression
// that removed the `const` qualifier (dropping the compile-
// time evaluability the reader's outer dispatch AND future
// static lookup tables key on) fails to compile HERE — the
// `const` context enforces the qualifier without a test-time
// assertion.
const _QUOTE: char = QuoteForm::Quote.lead_char();
const _QUASIQUOTE: char = QuoteForm::Quasiquote.lead_char();
const _UNQUOTE: char = QuoteForm::Unquote.lead_char();
const _SPLICE: char = QuoteForm::UnquoteSplice.lead_char();
const _FROM: Option<QuoteForm> = QuoteForm::from_lead_char(',');
assert_eq!(_QUOTE, '\'');
assert_eq!(_QUASIQUOTE, '`');
assert_eq!(_UNQUOTE, ',');
assert_eq!(_SPLICE, ',');
assert_eq!(_FROM, Some(QuoteForm::Unquote));
}
#[test]
fn quote_form_lead_constants_project_canonical_chars() {
// Pin each constant's byte identity so a typo (`'‛'` for
// `QUOTE_LEAD`, `'’'` for `QUASIQUOTE_LEAD`, `';'` for
// `UNQUOTE_LEAD`) or accidental redefinition surfaces
// immediately. Every canonical per-role reader-punctuation byte
// on the substrate has its own byte-identity pin at its owning
// algebra
// (`atom_str_delimiter_projects_canonical_quote_char`,
// `atom_str_escape_lead_projects_canonical_backslash_char`,
// `atom_keyword_marker_lead_projects_canonical_colon_char`,
// `atom_bool_literal_lead_projects_canonical_hash_char`,
// `sexp_list_open_projects_canonical_char`,
// `sexp_list_close_projects_canonical_char`,
// `sexp_comment_lead_projects_canonical_char`,
// `sexp_comment_term_projects_canonical_char`,
// `quote_form_splice_discriminator_projects_canonical_at_char`);
// this pin closes the three quote-family lead-byte constants at
// the SAME shape.
assert_eq!(QuoteForm::QUOTE_LEAD, '\'');
assert_eq!(QuoteForm::QUASIQUOTE_LEAD, '`');
assert_eq!(QuoteForm::UNQUOTE_LEAD, ',');
}
#[test]
fn quote_form_lead_constants_round_trip_through_lead_char_projections() {
// ROUND-TRIP CONTRACT: for each of the three distinct-lead-byte
// variants (`Quote`, `Quasiquote`, `Unquote`) the (variant →
// constant → variant) triangle closes exactly.
// `Self::from_lead_char(Self::X_LEAD) == Some(Self::X)` AND
// `Self::X.lead_char() == Self::X_LEAD` — the constants ARE the
// canonical per-variant lead byte both projections route
// through. `UnquoteSplice` shares its lead byte with `Unquote`
// (see the merged arm in `lead_char`), so `UnquoteSplice.lead_char()
// == Self::UNQUOTE_LEAD` too — the splice's SECOND-char
// `SPLICE_DISCRIMINATOR` promotion lives at the reader's peek
// arm, not at this decode. Pin the triangle at every variant so
// a regression that drifts EITHER a constant OR one of the two
// projection sites surfaces at test time.
assert_eq!(
QuoteForm::from_lead_char(QuoteForm::QUOTE_LEAD),
Some(QuoteForm::Quote),
);
assert_eq!(QuoteForm::Quote.lead_char(), QuoteForm::QUOTE_LEAD);
assert_eq!(
QuoteForm::from_lead_char(QuoteForm::QUASIQUOTE_LEAD),
Some(QuoteForm::Quasiquote),
);
assert_eq!(
QuoteForm::Quasiquote.lead_char(),
QuoteForm::QUASIQUOTE_LEAD,
);
assert_eq!(
QuoteForm::from_lead_char(QuoteForm::UNQUOTE_LEAD),
Some(QuoteForm::Unquote),
);
assert_eq!(QuoteForm::Unquote.lead_char(), QuoteForm::UNQUOTE_LEAD);
// UnquoteSplice's `lead_char` collapses onto the shared
// `UNQUOTE_LEAD` byte because the splice's `,@` prefix opens
// with `,`; the promotion is a two-char peek in the reader.
assert_eq!(
QuoteForm::UnquoteSplice.lead_char(),
QuoteForm::UNQUOTE_LEAD,
);
}
#[test]
fn quote_form_lead_constants_distinct_from_every_other_algebra_marker_char() {
// CROSS-AXIS DISJOINTNESS CONTRACT: each of the three quote-
// family lead bytes MUST differ from every other canonical
// reader-punctuation constant on the substrate — the other two
// quote-family lead bytes, `SPLICE_DISCRIMINATOR`,
// `Atom::STR_DELIMITER`, `Atom::STR_ESCAPE_LEAD`,
// `Atom::KEYWORD_MARKER_LEAD`, `Atom::BOOL_LITERAL_LEAD`,
// `Sexp::LIST_OPEN`, `Sexp::LIST_CLOSE`, `Sexp::COMMENT_LEAD`,
// and `Sexp::COMMENT_TERM`. Otherwise the reader's outer
// dispatch would ambiguously route a `'` / `` ` `` / `,` lead
// byte through the aliased sibling arm — e.g. if `QUOTE_LEAD`
// aliased `Sexp::LIST_OPEN`, a source `'foo` would ambiguously
// trigger the list-open arm before the quote-family arm ran.
// Sibling-shape peer of
// `quote_form_splice_discriminator_distinct_from_every_algebra_marker_char`
// one axis over.
// The three distinct-lead-byte rows bind through the typed
// [`QuoteForm::LEADS`] ALL array — the sub-vocabulary sweep
// now iterates ONE forced-arity `[char; 3]` array rather than
// three inline algebra-constant enumerations.
let leads = QuoteForm::LEADS;
// Within-family: the three lead bytes are pairwise distinct.
for (i, a) in leads.iter().enumerate() {
for b in &leads[i + 1..] {
assert_ne!(a, b, "quote-family lead bytes must be pairwise distinct",);
}
}
// Cross-family disjointness against every other single-char
// algebra marker on the substrate.
for lead in leads {
assert_ne!(lead, QuoteForm::SPLICE_DISCRIMINATOR);
assert_ne!(lead, Atom::STR_DELIMITER);
assert_ne!(lead, Atom::STR_ESCAPE_LEAD);
assert_ne!(lead, Atom::KEYWORD_MARKER_LEAD);
assert_ne!(lead, Atom::BOOL_LITERAL_LEAD);
assert_ne!(lead, Sexp::LIST_OPEN);
assert_ne!(lead, Sexp::LIST_CLOSE);
assert_ne!(lead, Sexp::COMMENT_LEAD);
assert_ne!(lead, Sexp::COMMENT_TERM);
}
}
#[test]
fn quote_form_unquote_splice_prefix_composes_from_unquote_lead_and_splice_discriminator() {
// STRUCTURAL COMPOSITION LAW: [`QuoteForm::UnquoteSplice`]'s
// two-char prefix `",@"` decomposes cleanly into
// [`QuoteForm::UNQUOTE_LEAD`] (the `,` byte shared with
// [`QuoteForm::Unquote`]) + [`QuoteForm::SPLICE_DISCRIMINATOR`]
// (the `@` byte promoted by the reader's peek arm). The two
// BYTE-LEVEL constants on the closed-set [`QuoteForm`] algebra
// compose the ONLY two-char [`Self::prefix`] in the closed set
// — a stronger form of the pre-existing
// `quote_form_unquote_splice_prefix_composes_from_unquote_prefix_and_splice_discriminator`
// pin (which composes through the `&'static str` prefix of the
// Unquote variant). Where that pin binds the `&'static str`-level
// composition, this pin binds the `char`-level composition; both
// pins fail loudly on any drift of the `,` or `@` bytes. The
// reader's two-char peek-then-consume splice-promotion arm
// reads `Self::UNQUOTE_LEAD` then peeks `Self::SPLICE_DISCRIMINATOR`
// to promote to `UnquoteSplice` — this identity closes the
// read↔write duality at the byte level.
let composed = format!(
"{}{}",
QuoteForm::UNQUOTE_LEAD,
QuoteForm::SPLICE_DISCRIMINATOR,
);
assert_eq!(
composed,
QuoteForm::UnquoteSplice.prefix(),
"UnquoteSplice.prefix() drifted from UNQUOTE_LEAD + \
SPLICE_DISCRIMINATOR — the reader's two-char splice \
promotion identity is broken at the byte level",
);
}
#[test]
fn quote_form_lead_constants_are_const_evaluable_over_the_closed_set() {
// Pin the `const` posture of the three lead constants by binding
// `const` bindings that ROUTE through the `const fn` lead_char /
// from_lead_char projections — the compile-time evaluation
// context enforces the qualifier without a test-time assertion.
// Sibling posture to
// `quote_form_from_lead_char_is_const_fn_over_the_closed_set`.
const _QUOTE: char = QuoteForm::QUOTE_LEAD;
const _QUASIQUOTE: char = QuoteForm::QUASIQUOTE_LEAD;
const _UNQUOTE: char = QuoteForm::UNQUOTE_LEAD;
const _FROM_QUOTE: Option<QuoteForm> = QuoteForm::from_lead_char(QuoteForm::QUOTE_LEAD);
const _FROM_QUASIQUOTE: Option<QuoteForm> =
QuoteForm::from_lead_char(QuoteForm::QUASIQUOTE_LEAD);
const _FROM_UNQUOTE: Option<QuoteForm> = QuoteForm::from_lead_char(QuoteForm::UNQUOTE_LEAD);
assert_eq!(_QUOTE, '\'');
assert_eq!(_QUASIQUOTE, '`');
assert_eq!(_UNQUOTE, ',');
assert_eq!(_FROM_QUOTE, Some(QuoteForm::Quote));
assert_eq!(_FROM_QUASIQUOTE, Some(QuoteForm::Quasiquote));
assert_eq!(_FROM_UNQUOTE, Some(QuoteForm::Unquote));
}
#[test]
fn quote_form_leads_composes_from_algebra_constants_in_declaration_order() {
// FAMILY COMPOSITION LAW: pin that the ALL array's rows are the
// three distinct-lead-byte algebra constants (`Self::QUOTE_LEAD`,
// `Self::QUASIQUOTE_LEAD`, `Self::UNQUOTE_LEAD`) in canonical
// declaration order matching [`QuoteForm::ALL`]'s three-of-four
// distinct-lead-byte projection through [`QuoteForm::lead_char`].
// A reorder of ONE row without reordering the underlying algebra
// constants silently misaligns every index-sweep consumer (a
// hypothetical reader outer-dispatch pre-check that keys on
// `QuoteForm::LEADS[0]`, an LSP completion generator that
// materialises the distinct-lead-byte set in this order). Sibling-
// shape pin to
// `sexp_list_delimiters_composes_from_algebra_constants_in_declaration_order`
// on the peer `[char; 2]` sub-vocabulary at
// [`Sexp::LIST_DELIMITERS`].
assert_eq!(
QuoteForm::LEADS,
[
QuoteForm::QUOTE_LEAD,
QuoteForm::QUASIQUOTE_LEAD,
QuoteForm::UNQUOTE_LEAD,
],
"QuoteForm::LEADS composition drifted from the canonical \
(QUOTE_LEAD, QUASIQUOTE_LEAD, UNQUOTE_LEAD) triple — the \
distinct-lead-byte sub-vocabulary lift must route through \
the three typed algebra constants in that order.",
);
}
#[test]
fn quote_form_leads_has_expected_cardinality() {
// CARDINALITY PIN: `[char; 3]` at rustc — this assert pins the
// runtime observable so a refactor that loosens the array's type
// to `&[char]` (dropping the compile-time arity forcing) fails
// HERE at the runtime cardinality assertion rather than silently
// allowing a fourth or absent row. The 3 vs [`QuoteForm::PREFIXES`]'s
// 4 shape asymmetry IS the structural axis distinguishing the
// DISTINCT-lead-byte sub-vocabulary from the PER-VARIANT-prefix
// sub-vocabulary — three-of-four distinct-lead-byte collapse is
// definitional (only [`QuoteForm::UnquoteSplice`]'s two-char
// `,@` prefix shares its lead byte with a sibling variant). A
// regression that grew LEADS to 4 without the shared-lead-byte
// collapse breaking (i.e. by adding a fourth distinct-lead-byte
// variant WITHOUT drifting [`QuoteForm::PREFIXES`]'s cardinality
// to 5 in lockstep) fails at this cardinality pin. Sibling-shape
// pin to `sexp_list_delimiters_has_expected_cardinality`.
assert_eq!(
QuoteForm::LEADS.len(),
3,
"QuoteForm::LEADS cardinality drifted from 3 — the distinct-\
lead-byte sub-vocabulary MUST be exactly three rows because \
UnquoteSplice shares its lead byte with Unquote by the \
splice's two-char `,@` prefix construction.",
);
}
#[test]
fn quote_form_leads_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: the three distinct-lead-byte rows MUST
// NOT alias — the closed-set outer [`QuoteForm`] algebra's
// three-of-four collapse identity depends on Quote / Quasiquote /
// Unquote owning distinct lead bytes (only UnquoteSplice shares
// Unquote's lead byte, via the splice's two-char `,@` prefix).
// A regression that collapsed Quote and Quasiquote onto the same
// lead byte would silently break the reader's outer dispatch
// (the tokenizer would ambiguously route both `'foo` and
// `` `foo `` through the same arm). Sibling-shape pin to
// `sexp_list_delimiters_pairwise_distinct` on the peer
// `[char; 2]` sub-vocabulary at [`Sexp::LIST_DELIMITERS`].
for (i, a) in QuoteForm::LEADS.iter().enumerate() {
for (j, b) in QuoteForm::LEADS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"QuoteForm::LEADS rows [{i}] and [{j}] share a byte \
({a:?} == {b:?}) — the distinct-lead-byte contract \
across Quote / Quasiquote / Unquote would collapse.",
);
}
}
}
#[test]
fn quote_form_leads_disjoint_from_splice_discriminator() {
// CROSS-AXIS DISJOINTNESS (splice discriminator): no row of
// [`QuoteForm::LEADS`] may alias
// [`QuoteForm::SPLICE_DISCRIMINATOR`] — otherwise the reader's
// two-char peek-then-consume splice-promotion arm inside
// [`crate::reader::tokenize`] would ambiguously promote on a
// sibling lead byte (e.g. if `SPLICE_DISCRIMINATOR` aliased
// [`QuoteForm::UNQUOTE_LEAD`], a source `,,foo` would silently
// promote to `UnquoteSplice(,foo)` rather than parsing as
// `Unquote(Unquote(foo))`). Sibling-shape pin to
// `sexp_list_delimiters_disjoint_from_str_delimiter`: both close
// the cross-sub-vocabulary disjointness contract at the ALL-array
// level rather than as an inline disjunction per consumer.
for (i, ch) in QuoteForm::LEADS.iter().enumerate() {
assert_ne!(
*ch,
QuoteForm::SPLICE_DISCRIMINATOR,
"QuoteForm::LEADS[{i}] ({ch:?}) aliases \
QuoteForm::SPLICE_DISCRIMINATOR ({:?}) — the reader's \
distinct-lead-byte arm would collide with the two-char \
splice promotion arm at the same byte.",
QuoteForm::SPLICE_DISCRIMINATOR,
);
}
}
#[test]
fn quote_form_lead_char_routes_through_leads_for_every_variant() {
// PATH-UNIFORMITY PIN: every [`QuoteForm::lead_char`] projection
// over the closed set MUST land on a row of [`QuoteForm::LEADS`]
// — the shared-lead-byte collapse identity (Quote / Quasiquote /
// Unquote / UnquoteSplice → three distinct lead bytes) binds
// through the ALL array's `.contains` sweep. A regression that
// reverted `lead_char`'s arms to inline `char` literals AND
// drifted one of the four arms without drifting a paired algebra
// constant fails HERE at the first mismatched variant rather than
// at a distant reader outer-dispatch drift where a quote-family
// form silently routes through a bare-atom arm. Sibling-shape
// pin to
// `sexp_is_bare_atom_boundary_routes_through_list_delimiters_for_every_row`
// on the peer `[char; 2]` sub-vocabulary at
// [`Sexp::LIST_DELIMITERS`], lifted to the four-variant closed
// set: every one of the four variants collapses onto one of the
// three LEADS rows.
for qf in QuoteForm::ALL {
assert!(
QuoteForm::LEADS.contains(&qf.lead_char()),
"QuoteForm::{qf:?}.lead_char() = {:?} is NOT a row of \
QuoteForm::LEADS — the shared-lead-byte collapse drifted \
from the ALL array's distinct-lead-byte sub-vocabulary.",
qf.lead_char(),
);
}
}
#[test]
fn quote_form_from_lead_char_decodes_every_row_of_leads_to_some() {
// INVERSE PATH-UNIFORMITY PIN: every row of [`QuoteForm::LEADS`]
// MUST decode through [`QuoteForm::from_lead_char`] to
// `Some(_variant_)` (the DEFAULT variant on that lead byte —
// Unquote on `,`, Quote on `'`, Quasiquote on `` ` ``). A
// regression that dropped one of the three arms in
// `from_lead_char`'s match without shrinking [`QuoteForm::LEADS`]
// in lockstep fails HERE at the first mismatched row rather than
// as a silent reader outer-dispatch drift where a quote-family
// lead byte silently falls through to the None arm. This pin
// closes the round-trip from the DISTINCT-lead-byte axis back
// through the decode projection at the ALL-array level. Sibling-
// shape pin to
// `atom_decode_str_escape_routes_through_self_escape_table_for_every_row`
// on the peer sub-vocabulary at [`Atom::SELF_ESCAPE_TABLE`].
for (i, ch) in QuoteForm::LEADS.iter().enumerate() {
assert!(
QuoteForm::from_lead_char(*ch).is_some(),
"QuoteForm::LEADS[{i}] ({ch:?}) decodes to None through \
QuoteForm::from_lead_char — the distinct-lead-byte \
sub-vocabulary drifted from the decode projection's \
non-None arm-set.",
);
}
}
#[test]
fn quote_form_leads_matches_dedup_of_prefixes_first_char_set() {
// CROSS-ARRAY IDENTITY: [`QuoteForm::LEADS`] IS the deduplicated
// first-char set of [`QuoteForm::PREFIXES`] — the four per-
// variant prefixes' first chars (`'\''`, `` '`' ``, `','`, `','`)
// deduplicate onto the three DISTINCT lead bytes exactly matching
// [`QuoteForm::LEADS`]'s rows. This pin binds the SHAPE-ASYMMETRIC
// (3 vs 4) relationship between the two ALL arrays: [`QuoteForm::PREFIXES`]
// enumerates the per-variant prefix-bytes axis; [`QuoteForm::LEADS`]
// enumerates the DISTINCT lead-byte axis; the two ALL arrays
// compose through the (first-char, dedup) projection. A regression
// that drifted EITHER array without drifting the other (e.g. an
// ELisp-compat port of Quote's prefix to `"#'"` without updating
// [`QuoteForm::QUOTE_LEAD`]) surfaces here rather than as a
// silent reader outer-dispatch drift. Sibling-shape pin to
// `quote_form_per_role_prefixes_route_through_matching_lead_char_for_every_variant`
// one axis over — that pin binds per-variant; this pin binds
// per-distinct-lead-byte via the dedup composition. Peer at the
// ALL-array level to the pre-existing composition tests between
// NAMED_ESCAPE_TABLE + SELF_ESCAPE_TABLE (which SPAN a total
// arm-set cardinality; this pin composes a DEDUP arm-set
// cardinality).
let mut deduped_first_chars: Vec<char> = QuoteForm::PREFIXES
.iter()
.map(|p| {
p.chars().next().unwrap_or_else(|| {
panic!("QuoteForm::PREFIXES entry `{p}` must have at least one char")
})
})
.collect();
deduped_first_chars.sort_unstable();
deduped_first_chars.dedup();
let mut leads_sorted: Vec<char> = QuoteForm::LEADS.to_vec();
leads_sorted.sort_unstable();
assert_eq!(
deduped_first_chars, leads_sorted,
"QuoteForm::LEADS drifted from the deduplicated first-char \
set of QuoteForm::PREFIXES — the (per-variant prefix axis) \
× (distinct-lead-byte axis) shape-asymmetric composition \
identity is broken.",
);
}
#[test]
fn quote_form_splice_discriminator_projects_canonical_at_char() {
// Pin the constant's byte identity so a typo (`'!'`, `'?'`,
// `'~'`) or accidental redefinition surfaces immediately. The
// reader's peek arm inside [`crate::reader::tokenize`] AND the
// splice-promotion table [`QuoteForm::promote_via_next_char`]
// BOTH bind to this constant; a drift here would silently re-
// shape every `,@xs` tokenization into a `,` + `@xs` two-token
// sequence (or into a phantom promotion on a different
// second-char), and this pin catches the drift at test time.
assert_eq!(QuoteForm::SPLICE_DISCRIMINATOR, '@');
}
#[test]
fn quote_form_splice_discriminator_distinct_from_every_algebra_marker_char() {
// CROSS-AXIS DISJOINTNESS CONTRACT: the splice discriminator
// `@` must NOT alias any other canonical reader-punctuation
// constant on the substrate — every [`QuoteForm::lead_char`]
// projection, [`crate::ast::Atom::STR_DELIMITER`],
// [`crate::ast::Atom::KEYWORD_MARKER`]'s lead byte,
// [`crate::ast::Sexp::LIST_OPEN`], [`crate::ast::Sexp::LIST_CLOSE`],
// [`crate::ast::Sexp::COMMENT_LEAD`], and both
// [`crate::ast::Atom::bool_literal`] spellings' lead bytes.
// Otherwise the two-char `,@` splice-promotion arm inside the
// reader would ambiguously route through the splice arm AND a
// sibling algebra's arm at the outer dispatch — e.g. if
// `SPLICE_DISCRIMINATOR` aliased [`Sexp::LIST_OPEN`], a source
// `,(a b)` would ambiguously promote-and-consume the `(` before
// the list-opening arm ran. Pin the disjointness across every
// sibling constant so a future rename catches the collision at
// test time rather than as a silent tokenizer drift.
assert_ne!(
QuoteForm::SPLICE_DISCRIMINATOR,
QuoteForm::Quote.lead_char()
);
assert_ne!(
QuoteForm::SPLICE_DISCRIMINATOR,
QuoteForm::Quasiquote.lead_char()
);
assert_ne!(
QuoteForm::SPLICE_DISCRIMINATOR,
QuoteForm::Unquote.lead_char()
);
assert_ne!(
QuoteForm::SPLICE_DISCRIMINATOR,
QuoteForm::UnquoteSplice.lead_char()
);
assert_ne!(QuoteForm::SPLICE_DISCRIMINATOR, Atom::STR_DELIMITER);
assert_ne!(QuoteForm::SPLICE_DISCRIMINATOR, Sexp::LIST_OPEN);
assert_ne!(QuoteForm::SPLICE_DISCRIMINATOR, Sexp::LIST_CLOSE);
assert_ne!(QuoteForm::SPLICE_DISCRIMINATOR, Sexp::COMMENT_LEAD);
// The KEYWORD_MARKER prefix's canonical LEAD `char` lives at
// the typed `Atom::KEYWORD_MARKER_LEAD` constant on the closed-
// set outer [`Atom`] algebra. Pre-lift this slot held an inline
// `Atom::KEYWORD_MARKER.chars().next().expect(_)` extraction;
// post-lift the byte lives at ONE named constant that the
// [`Atom::KEYWORD_MARKER`] `&'static str` projects to (pinned
// by `atom_keyword_marker_lead_prefixes_keyword_marker`).
assert_ne!(QuoteForm::SPLICE_DISCRIMINATOR, Atom::KEYWORD_MARKER_LEAD);
// Both `#t` / `#f` spellings share `Atom::BOOL_LITERAL_LEAD`
// (`'#'`) as the lead byte. Pre-lift each spelling was
// extracted via `Atom::bool_literal(b).chars().next().expect(_)`
// — TWO assertions for the SAME byte by construction. Post-
// lift both collapse to ONE assertion routing through the
// typed constant; the structural invariant "both spellings
// share the lead byte" lives at
// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`
// rather than as a per-spelling boilerplate duplication here.
assert_ne!(QuoteForm::SPLICE_DISCRIMINATOR, Atom::BOOL_LITERAL_LEAD);
}
#[test]
fn quote_form_promote_via_next_char_only_promotes_unquote_on_splice_discriminator() {
// Pin the closed-set promotion table: EXACTLY the singleton
// `(Unquote, SPLICE_DISCRIMINATOR) → Some(UnquoteSplice)` arm
// triggers; every other `(variant, char)` pairing yields
// `None`. Sweeps every `QuoteForm::ALL` variant against the
// splice discriminator AND against a broad rejection set
// (whitespace, `(`, `)`, `;`, `Atom::STR_DELIMITER`, `a`, `,`,
// `'`, `` ` ``) so a regression that widens the promotion
// table (e.g. promotes `Quote` on `@` to a phantom variant,
// or promotes `Unquote` on `'` after a copy-paste drift)
// surfaces at test time. Sibling to
// `quote_form_from_lead_char_decodes_every_distinct_lead_char_to_default_variant`
// one axis over on the closed-set entry-char algebra — this
// sweep pins the two-char extension of that one-char decode.
for qf in QuoteForm::ALL {
let promoted = qf.promote_via_next_char(QuoteForm::SPLICE_DISCRIMINATOR);
let expected = if matches!(qf, QuoteForm::Unquote) {
Some(QuoteForm::UnquoteSplice)
} else {
None
};
assert_eq!(
promoted, expected,
"QuoteForm::{qf:?} — promotion table drifted on SPLICE_DISCRIMINATOR",
);
// Every non-discriminator char must reject for every variant.
for rejection_char in [
' ',
'\n',
'\t',
Sexp::LIST_OPEN,
Sexp::LIST_CLOSE,
Sexp::COMMENT_LEAD,
Atom::STR_DELIMITER,
'a',
',',
'\'',
'`',
'#',
':',
'!',
'?',
'~',
] {
assert_eq!(
qf.promote_via_next_char(rejection_char),
None,
"QuoteForm::{qf:?} — promotion table leaked on non-\
discriminator char {rejection_char:?}",
);
}
}
}
#[test]
fn quote_form_promote_via_next_char_is_const_fn_over_the_closed_set() {
// Pin the `const fn` posture by binding a `const` array
// literal of promotions keyed on the closed set. A regression
// that removed the `const` qualifier (dropping the compile-
// time evaluability the reader's peek arm AND future static
// lookup tables key on) fails to compile HERE — the `const`
// context enforces the qualifier without a test-time
// assertion. Sibling posture to
// `quote_form_from_lead_char_is_const_fn_over_the_closed_set`.
const _QUOTE: Option<QuoteForm> =
QuoteForm::Quote.promote_via_next_char(QuoteForm::SPLICE_DISCRIMINATOR);
const _QUASIQUOTE: Option<QuoteForm> =
QuoteForm::Quasiquote.promote_via_next_char(QuoteForm::SPLICE_DISCRIMINATOR);
const _UNQUOTE: Option<QuoteForm> =
QuoteForm::Unquote.promote_via_next_char(QuoteForm::SPLICE_DISCRIMINATOR);
const _SPLICE: Option<QuoteForm> =
QuoteForm::UnquoteSplice.promote_via_next_char(QuoteForm::SPLICE_DISCRIMINATOR);
assert_eq!(_QUOTE, None);
assert_eq!(_QUASIQUOTE, None);
assert_eq!(_UNQUOTE, Some(QuoteForm::UnquoteSplice));
assert_eq!(_SPLICE, None);
}
#[test]
fn quote_form_promote_via_next_char_composes_prefix_from_source_prefix_and_next_char() {
// COMPOSITION IDENTITY: for every `qf: QuoteForm` and every
// `c: char`, if `qf.promote_via_next_char(c) == Some(promoted)`
// then `format!("{}{}", qf.prefix(), c) == promoted.prefix()`.
// Pin the (variant, next char) → promoted-variant projection
// agrees with the reader's rendered `Self::prefix` composition,
// so a regression that drifts one side of the identity
// surfaces immediately. Sibling to
// `quote_form_lead_char_is_first_char_of_prefix_for_every_variant`
// one axis up on the closed-set entry-char algebra.
for qf in QuoteForm::ALL {
if let Some(promoted) = qf.promote_via_next_char(QuoteForm::SPLICE_DISCRIMINATOR) {
let composed = format!("{}{}", qf.prefix(), QuoteForm::SPLICE_DISCRIMINATOR);
assert_eq!(
composed,
promoted.prefix(),
"QuoteForm::{qf:?} — promotion composition drifted from \
promoted prefix ({promoted:?}.prefix() = {:?})",
promoted.prefix(),
);
}
}
}
#[test]
fn quote_form_unquote_splice_prefix_composes_from_unquote_prefix_and_splice_discriminator() {
// STRUCTURAL COMPOSITION LAW: [`QuoteForm::UnquoteSplice`]'s
// two-char prefix `",@"` decomposes cleanly into
// [`QuoteForm::Unquote`]'s prefix `","` + the splice
// discriminator byte `'@'`. Pin the identity directly rather
// than through the promotion table so a regression that
// renamed the discriminator without touching the promotion
// table (or vice versa) surfaces here. This IS the structural
// identity the reader's peek-then-consume arm depends on: the
// tokenizer sees `,` (Unquote lead char), peeks `@`
// (SPLICE_DISCRIMINATOR), and emits UnquoteSplice — the
// rendered prefix identity closes the read↔write duality.
let composed = format!(
"{}{}",
QuoteForm::Unquote.prefix(),
QuoteForm::SPLICE_DISCRIMINATOR,
);
assert_eq!(
composed,
QuoteForm::UnquoteSplice.prefix(),
"UnquoteSplice.prefix() drifted from Unquote.prefix() + \
SPLICE_DISCRIMINATOR — the reader's two-char splice \
promotion identity is broken",
);
}
// ── `QuoteForm::PROMOTIONS` — the closed-set forced-arity array of
// promotion triples on the substrate's quote-family algebra. Pins
// the singleton `(Unquote, SPLICE_DISCRIMINATOR, UnquoteSplice)`
// entry AND its alignment with `promote_via_next_char`'s Some-arm
// AND the family-wide contract sweeps below. Sibling-shape tests to
// the `quote_form_hash_discriminators_*` block on the outer-Sexp
// cache-key axis — that block anchors the `[u8; 4]` byte algebra;
// this block anchors the `[(Self, char, Self); 1]` promotion
// algebra one axis over on the same closed set.
#[test]
fn quote_form_promotions_has_expected_cardinality() {
// FORCED-ARITY CONTRACT: [`QuoteForm::PROMOTIONS`]'s
// cardinality is `1` at the type level — the substrate's
// current promotion algebra has EXACTLY ONE promotion arm
// (`(Unquote, SPLICE_DISCRIMINATOR, UnquoteSplice)`). A
// regression that widened the array without extending
// [`QuoteForm::promote_via_next_char`]'s match body (or vice
// versa) fails compilation because the array literal's arity
// is forced by the `[_; 1]` type annotation. This runtime
// pin closes the same law at a runtime cardinality check
// so a callsite that expects the singleton shape without
// static-arity inference (a dynamic iteration site, an
// audit-log emitter that reports the promotion-algebra size
// for observability) reads through ONE substrate primitive
// rather than through a hand-rolled `1usize` literal.
assert_eq!(
QuoteForm::PROMOTIONS.len(),
1,
"QuoteForm::PROMOTIONS cardinality drifted from the \
substrate's singleton promotion algebra — the closed-set \
array's forced arity is load-bearing on the `(Unquote, \
SPLICE_DISCRIMINATOR) → UnquoteSplice` singleton identity",
);
}
#[test]
fn quote_form_promotions_pin_legacy_splice_promotion_triple() {
// LEGACY-TRIPLE CONTRACT: [`QuoteForm::PROMOTIONS`]'s
// singleton entry is byte-for-byte `(Self::Unquote,
// Self::SPLICE_DISCRIMINATOR, Self::UnquoteSplice)`. Pin each
// column of the triple against its typed source:
// * head == QuoteForm::Unquote (the `,` variant)
// * disc == QuoteForm::SPLICE_DISCRIMINATOR (`'@'`)
// * promoted == QuoteForm::UnquoteSplice (the `,@` variant)
// A regression that drifts ONE column of the triple silently
// redirects the reader's promotion arm to a phantom variant
// AND fails HERE at the per-column identity check rather
// than at silent tokenizer drift where every `,@xs` source
// tokenizes to the wrong closed-set marker.
assert_eq!(
QuoteForm::PROMOTIONS[0].0,
QuoteForm::Unquote,
"QuoteForm::PROMOTIONS[0].0 (head) drifted from Unquote — \
the substrate's singleton promotion arm's head variant \
MUST be Unquote (the only variant whose prefix is the \
lead byte of a longer variant's prefix)",
);
assert_eq!(
QuoteForm::PROMOTIONS[0].1,
QuoteForm::SPLICE_DISCRIMINATOR,
"QuoteForm::PROMOTIONS[0].1 (discriminator) drifted from \
SPLICE_DISCRIMINATOR — the substrate's singleton \
promotion arm's discriminator MUST be the byte the \
reader's peek arm consumes to promote the head variant \
(the ONE `'@'` byte on the closed-set algebra)",
);
assert_eq!(
QuoteForm::PROMOTIONS[0].2,
QuoteForm::UnquoteSplice,
"QuoteForm::PROMOTIONS[0].2 (promoted) drifted from \
UnquoteSplice — the substrate's singleton promotion \
arm's promoted variant MUST be UnquoteSplice (the only \
two-char-prefix variant on the closed-set algebra)",
);
}
#[test]
fn quote_form_promotions_align_with_promote_via_next_char_for_every_entry() {
// ALIGNMENT CONTRACT: sweep [`QuoteForm::PROMOTIONS`] and
// assert that for every `(head, disc, promoted)` entry,
// `head.promote_via_next_char(disc) == Some(promoted)`. This
// is the projection method's forward composition law at the
// closed set — a regression that drifts the promoted-variant
// column of the constant (or the projection method's Some-arm
// return literal) surfaces here rather than as a silent
// tokenizer redirect. Sibling-shape pin to
// `quote_form_hash_discriminators_align_with_all_by_index`
// one axis over on the cache-key byte algebra — that pin
// aligns the `[u8; 4]` array with the projection method's
// per-variant arm; this pin aligns the `[(Self, char, Self);
// 1]` array with the projection method's per-triple arm.
for (head, disc, promoted) in QuoteForm::PROMOTIONS {
let projected = head.promote_via_next_char(disc);
assert_eq!(
projected,
Some(promoted),
"QuoteForm::PROMOTIONS[({head:?}, {disc:?}, \
{promoted:?})] — `promote_via_next_char` drifted \
from the constant's promoted-variant column (got \
{projected:?})",
);
}
}
#[test]
fn quote_form_promotions_compose_prefix_from_source_prefix_and_discriminator_for_every_entry() {
// COMPOSITION LAW (rendered-prefix identity): sweep
// [`QuoteForm::PROMOTIONS`] and assert that for every
// `(head, disc, promoted)` entry, `format!("{}{}",
// head.prefix(), disc) == promoted.prefix()`. The
// (head prefix + discriminator) source-text composition
// agrees byte-for-byte with the promoted variant's rendered
// prefix — the reader's peek-then-consume arm's rendered
// prefix identity closes the read↔write duality across
// every entry in the promotion algebra.
//
// Sibling to the pre-existing
// `quote_form_promote_via_next_char_composes_prefix_from_source_prefix_and_next_char`
// which pins the same law through
// [`QuoteForm::promote_via_next_char`]'s Some-arm rather
// than through the constant's triple directly — this pin
// closes the law at the constant, that pin closes it at the
// projection method. Together the two pins bind the
// rendered-prefix identity to BOTH the substrate primitive
// AND the projection method so a regression that drifts
// ONE side of the identity fails at BOTH pins rather than at
// silent read/write drift where a reader-tokenized `,@xs`
// form's rendered prefix disagrees with its typed marker's
// rendered prefix.
for (head, disc, promoted) in QuoteForm::PROMOTIONS {
let composed = format!("{}{}", head.prefix(), disc);
assert_eq!(
composed,
promoted.prefix(),
"QuoteForm::PROMOTIONS[({head:?}, {disc:?}, \
{promoted:?})] — head.prefix() + disc drifted from \
promoted.prefix() ({:?})",
promoted.prefix(),
);
}
}
#[test]
fn quote_form_promotions_close_promote_via_next_char_against_every_non_promotion_pair() {
// REJECTION CONTRACT: sweep [`QuoteForm::ALL`] × (every
// (head, disc) pair from [`QuoteForm::PROMOTIONS`] plus every
// rejection discriminator distinct from the promotion set's
// discriminator column) and assert that every pair NOT in
// [`QuoteForm::PROMOTIONS`]'s `(head, disc)` projection
// rejects with `None`. A regression that widened the
// promotion algebra (e.g. phantom-promoted [`QuoteForm::Quote`]
// on `'@'` after a copy-paste drift on the match arm's head
// pattern, OR silently promoted `Unquote` on a non-`@`
// discriminator after a drift on the match arm's char
// pattern) fails HERE at the sweep-time rejection assertion
// rather than at silent tokenizer drift where bare `'@xs`
// forms degrade to a phantom `UnquoteSplice`-shaped sequence
// OR bare `,'xs` forms silently promote through the reader.
//
// Sibling-shape pin to the pre-existing
// `quote_form_promote_via_next_char_only_promotes_unquote_on_splice_discriminator`
// which sweeps every variant against SPLICE_DISCRIMINATOR
// AND a hand-rolled rejection char set; this pin extends the
// rejection sweep to compose the rejection set STRUCTURALLY
// from [`QuoteForm::PROMOTIONS`]'s complement rather than
// hand-rolling a rejection char literal list at a callsite
// that would silently drift as the algebra grows.
//
// The rejection char set is composed as: every
// [`QuoteForm::ALL`] variant's [`QuoteForm::lead_char`] (the
// three quote-family lead bytes `{'\'', '`', ','}`), every
// char in [`QuoteForm::PROMOTIONS`]'s discriminator column
// (the ONE `'@'` byte — used to verify that variants NOT in
// the promotion set's head column reject on the same
// discriminator), and a hand-rolled sweep of non-quote-family
// rejection chars (whitespace, structural, reader-punctuation)
// to cover the closed-set-complement rejection surface.
let mut discriminators: Vec<char> =
QuoteForm::ALL.iter().map(|qf| qf.lead_char()).collect();
for (_, disc, _) in QuoteForm::PROMOTIONS {
if !discriminators.contains(&disc) {
discriminators.push(disc);
}
}
for extra in [
' ',
'\n',
'\t',
Sexp::LIST_OPEN,
Sexp::LIST_CLOSE,
Sexp::COMMENT_LEAD,
Atom::STR_DELIMITER,
'a',
'#',
':',
'!',
'?',
'~',
] {
if !discriminators.contains(&extra) {
discriminators.push(extra);
}
}
let promotion_pairs: Vec<(QuoteForm, char)> = QuoteForm::PROMOTIONS
.iter()
.map(|(head, disc, _)| (*head, *disc))
.collect();
for head in QuoteForm::ALL {
for disc in &discriminators {
let in_promotion_set = promotion_pairs.contains(&(head, *disc));
let projected = head.promote_via_next_char(*disc);
if in_promotion_set {
// Positive arms are covered by
// `quote_form_promotions_align_with_promote_via_next_char_for_every_entry`;
// skip here to keep this pin's focus on the
// rejection surface exclusively.
continue;
}
assert_eq!(
projected, None,
"QuoteForm::{head:?}.promote_via_next_char({disc:?}) \
— promotion algebra leaked on a pair NOT in \
QuoteForm::PROMOTIONS (got {projected:?}, \
expected None)",
);
}
}
}
#[test]
fn quote_form_promote_via_next_char_routes_promoted_variant_through_promotions_constant() {
// ROUTING CONTRACT: pin that
// [`QuoteForm::promote_via_next_char`]'s Some-arm return
// BINDS through [`QuoteForm::PROMOTIONS`]`[0].2` rather than
// through an inline [`QuoteForm::UnquoteSplice`] literal.
// Post-lift the projection method's Some-arm reads:
// `Some(Self::PROMOTIONS[0].2)`
// — so a regression that reverts the arm to an inline
// `Some(Self::UnquoteSplice)` fails HERE at the byte-identity
// sweep, WHERE the projected value is compared against
// [`QuoteForm::PROMOTIONS`]`[0].2` directly rather than
// against an inline literal.
//
// Sibling-shape pin to
// `sexp_shape_hash_discriminator_atomic_arms_route_through_atom_kind_outer_hash_discriminator`
// (prior-run 39537b2) one axis over on the cache-key byte
// algebra — that pin binds the shape-level projection's
// atomic-arm collapse to the typed constant; this pin binds
// the promotion projection's Some-arm to the typed triple's
// promoted-variant column. Together the two pins close the
// "projection routes through the substrate primitive" pattern
// across the cache-key axis AND the promotion axis on the
// closed-set algebra.
let projected = QuoteForm::Unquote.promote_via_next_char(QuoteForm::SPLICE_DISCRIMINATOR);
assert_eq!(
projected,
Some(QuoteForm::PROMOTIONS[0].2),
"QuoteForm::Unquote.promote_via_next_char(SPLICE_DISCRIMINATOR) \
— Some-arm return drifted from routing through \
QuoteForm::PROMOTIONS[0].2 (got {projected:?})",
);
}
#[test]
fn quote_form_hash_discriminator_pins_legacy_cache_key_bytes() {
// CACHE-KEY CONTRACT: pre-lift `Hash for Sexp` used the literal
// byte values 3/4/5/6 for Quote/Quasiquote/Unquote/UnquoteSplice
// as the per-variant discriminator. The expansion cache
// (`Expander::cache`) keys on Hash; ANY change to a
// discriminator byte silently invalidates every cached
// expansion across the substrate AND risks collision with the
// reserved bytes the non-quote-family Hash arms use (0=Nil,
// 1=Atom, 2=List). Pin the four legacy values explicitly so a
// regression that re-numbers them surfaces immediately — the
// `QuoteForm` algebra MUST preserve the prior byte mapping
// bit-for-bit.
assert_eq!(QuoteForm::Quote.hash_discriminator(), 3);
assert_eq!(QuoteForm::Quasiquote.hash_discriminator(), 4);
assert_eq!(QuoteForm::Unquote.hash_discriminator(), 5);
assert_eq!(QuoteForm::UnquoteSplice.hash_discriminator(), 6);
}
// ── `QuoteForm::{QUOTE_HASH_DISCRIMINATOR,
// QUASIQUOTE_HASH_DISCRIMINATOR, UNQUOTE_HASH_DISCRIMINATOR,
// UNQUOTE_SPLICE_HASH_DISCRIMINATOR, HASH_DISCRIMINATORS}` —
// per-role `u8` cache-key byte algebra on the closed-set outer
// [`QuoteForm`]. Fourth per-role axis on the algebra alongside the
// reader-prefix (commit a08e61f), diagnostic-label (commit
// 70be157), and iac-forge canonical-form tag (commit bdd624b)
// `&'static str` axes — closes the FOUR production
// byte-vocabularies the closed set carries at ONE `pub(crate)
// const` per (role, vocabulary) pair plus a family-wide ALL array
// per vocabulary.
#[test]
fn quote_form_hash_discriminators_pin_legacy_cache_key_bytes() {
// Pin each per-role `pub(crate) const` at its exact canonical
// `u8` byte. Sibling of
// `quote_form_hash_discriminator_pins_legacy_cache_key_bytes`
// (which pins the method's projection) — this pin asserts the
// `pub(crate) const` value itself, so a regression that drifts
// the constant but leaves the method's arm literal in place
// (unlikely post-lift but structurally distinct) surfaces
// here. The cache-key partition `{3, 4, 5, 6}` is load-bearing
// for the outer-`Sexp` `Hash` body's disjointness contract
// with the reserved bytes `{0, 1, 2}` the non-quote-family
// arms use — a `4u8` drift to `2u8` would silently collide
// with `StructuralKind::List`'s cache-key byte and mis-hash
// every quasi-quote through the list-arm's path.
assert_eq!(QuoteForm::QUOTE_HASH_DISCRIMINATOR, 3);
assert_eq!(QuoteForm::QUASIQUOTE_HASH_DISCRIMINATOR, 4);
assert_eq!(QuoteForm::UNQUOTE_HASH_DISCRIMINATOR, 5);
assert_eq!(QuoteForm::UNQUOTE_SPLICE_HASH_DISCRIMINATOR, 6);
}
#[test]
fn quote_form_hash_discriminator_routes_through_typed_per_role_constants() {
// PATH-UNIFORMITY: `Self::hash_discriminator(self)` returns
// the per-role `pub(crate) const` byte-for-byte per variant,
// catching a regression that reverts ONE arm to an inline
// `3` / `4` / `5` / `6` `u8` literal (or drifts one arm's
// byte silently). Sibling posture to
// `quote_form_prefix_routes_through_typed_per_role_constants`
// on the reader-prefix axis of the SAME closed set.
for (qf, expected) in [
(QuoteForm::Quote, QuoteForm::QUOTE_HASH_DISCRIMINATOR),
(
QuoteForm::Quasiquote,
QuoteForm::QUASIQUOTE_HASH_DISCRIMINATOR,
),
(QuoteForm::Unquote, QuoteForm::UNQUOTE_HASH_DISCRIMINATOR),
(
QuoteForm::UnquoteSplice,
QuoteForm::UNQUOTE_SPLICE_HASH_DISCRIMINATOR,
),
] {
let actual = qf.hash_discriminator();
assert_eq!(
actual, expected,
"QuoteForm::{qf:?}.hash_discriminator() `{actual}` \
drifted from per-role constant `{expected}` — the \
arm must route through the typed `pub(crate) const` \
rather than an inline `u8` literal",
);
}
}
#[test]
fn quote_form_hash_discriminators_has_expected_cardinality() {
// Cardinality contract: `Self::HASH_DISCRIMINATORS.len() == 4`
// — pinned at the declaration site by rustc's forced-arity
// check on `[u8; 4]`. This test surfaces the arity as a
// fail-loud runtime pin so a future refactor that switches
// the array type to `&[u8]` (dropping the compile-time arity
// forcing) doesn't silently loosen the closed-set discipline
// the family relies on. Sibling posture to
// `quote_form_prefixes_has_expected_cardinality`,
// `quote_form_labels_has_expected_cardinality`, and
// `quote_form_iac_forge_tags_has_expected_cardinality` on the
// other three per-role axes of the SAME [`QuoteForm`] closed
// set.
assert_eq!(
QuoteForm::HASH_DISCRIMINATORS.len(),
4,
"QuoteForm::HASH_DISCRIMINATORS cardinality drifted from \
4 — the closed homoiconic-prefix domain admits exactly \
four wrappers by construction; a fifth extension \
surfaces here"
);
}
#[test]
fn quote_form_hash_discriminators_align_with_all_by_index() {
// ALIGNMENT CONTRACT: `Self::HASH_DISCRIMINATORS[i] ==
// Self::ALL[i].hash_discriminator()` element-wise. Pins that
// the typed variant ALL and the `u8` HASH_DISCRIMINATORS ALL
// stay in lockstep under any reorder — a regression that
// reorders ONE array without reordering the other silently
// misaligns every `zip(ALL, HASH_DISCRIMINATORS)` consumer.
// Sibling posture to `quote_form_prefixes_align_with_all_by_index`
// on the reader-prefix axis.
for (i, qf) in QuoteForm::ALL.iter().enumerate() {
assert_eq!(
QuoteForm::HASH_DISCRIMINATORS[i],
qf.hash_discriminator(),
"QuoteForm::HASH_DISCRIMINATORS[{i}] `{disc}` drifted \
from QuoteForm::ALL[{i}] ({qf:?}).hash_discriminator() \
`{via_variant}` — the canonical declaration order of \
the ALL array and the hash_discriminator projection \
must match element-wise",
disc = QuoteForm::HASH_DISCRIMINATORS[i],
via_variant = qf.hash_discriminator(),
);
}
}
#[test]
fn quote_form_hash_discriminators_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every entry of the
// `HASH_DISCRIMINATORS` array must differ so the outer-`Sexp`
// `Hash` body cannot route two homoiconic prefixes through
// the same cache-key byte — a collision would silently mis-
// hash two structurally-distinct forms to the same
// `Expander::cache` slot. Family-wide sweep over
// `HASH_DISCRIMINATORS × HASH_DISCRIMINATORS` — supersedes
// any per-pair pin and picks up new discriminators
// mechanically. Sibling posture to
// `quote_form_prefixes_pairwise_distinct`.
for (i, a) in QuoteForm::HASH_DISCRIMINATORS.iter().enumerate() {
for (j, b) in QuoteForm::HASH_DISCRIMINATORS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"QuoteForm::HASH_DISCRIMINATORS[{i}] `{a}` \
collides with QuoteForm::HASH_DISCRIMINATORS[{j}] \
`{b}` — the outer-Sexp Hash body's cache-key \
partition would route two homoiconic prefixes \
through the same slot"
);
}
}
}
#[test]
fn quote_form_hash_discriminators_disjoint_from_reserved_outer_sexp_bytes() {
// CROSS-AXIS DISJOINTNESS CONTRACT: every entry of
// `Self::HASH_DISCRIMINATORS` must differ from the reserved
// outer-`Sexp` bytes the non-quote-family arms use — `0u8`
// for [`crate::error::StructuralKind::Nil`], `1u8` for the
// [`crate::ast::Sexp::Atom`] outer-carve marker, `2u8` for
// [`crate::error::StructuralKind::List`]. The three carvings
// of the outer-`Sexp` cache-key space jointly cover
// `{0, 1, 2, 3, 4, 5, 6}` with no gaps AND no overlaps; a
// regression that re-numbers a quote-family discriminator
// into the reserved region silently mis-hashes every affected
// form. Pin the disjointness across every reserved byte so a
// future rename catches the collision at test time rather
// than as a silent cache-key drift where
// `Expander::cache` mis-collides live expansions.
let reserved_non_quote_family_bytes: [u8; 3] = [
crate::error::StructuralKind::Nil.hash_discriminator(),
1u8, // Sexp::Atom outer-carve marker (pre-lift inline literal in Hash for Sexp)
crate::error::StructuralKind::List.hash_discriminator(),
];
for (i, quote_family_byte) in QuoteForm::HASH_DISCRIMINATORS.iter().enumerate() {
for reserved_byte in reserved_non_quote_family_bytes {
assert_ne!(
*quote_family_byte, reserved_byte,
"QuoteForm::HASH_DISCRIMINATORS[{i}] `{quote_family_byte}` \
collides with reserved non-quote-family cache-key byte \
`{reserved_byte}` — the outer-Sexp Hash body's three-\
carving partition is broken"
);
}
}
}
#[test]
fn quote_form_as_unquote_form_projects_two_of_four_subset() {
// The structural-subset gate: only `{Unquote, UnquoteSplice}`
// are template-substitution markers; `{Quote, Quasiquote}` are
// wrappers whose semantic does NOT include substitution. Pin
// the 2-of-4 partition so the `Sexp::as_unquote` derivation's
// closed-set arithmetic stays correct.
assert_eq!(
QuoteForm::Unquote.as_unquote_form(),
Some(UnquoteForm::Unquote)
);
assert_eq!(
QuoteForm::UnquoteSplice.as_unquote_form(),
Some(UnquoteForm::Splice)
);
assert_eq!(QuoteForm::Quote.as_unquote_form(), None);
assert_eq!(QuoteForm::Quasiquote.as_unquote_form(), None);
}
#[test]
fn quote_form_iac_forge_tag_pins_canonical_lisp_tag_strings_for_every_variant() {
// CROSS-CRATE CANONICAL-FORM CONTRACT: the four canonical
// iac-forge tags are load-bearing for inter-crate compatibility
// — `iac_forge::sexpr::SExpr` consumers (BLAKE3 attestation,
// render cache) key on the canonical 2-element-list shape
// `(<tag> <inner>)`. A regression that drifts ONE tag silently
// invalidates every cached canonical form across the substrate
// AND mis-collides with the legacy `SexpShape::label` projection
// that uses the shorter `"unquote-splice"` for the diagnostic
// surface. Pin the four legacy tag values explicitly so a
// regression that re-spells them surfaces immediately.
assert_eq!(QuoteForm::Quote.iac_forge_tag(), "quote");
assert_eq!(QuoteForm::Quasiquote.iac_forge_tag(), "quasiquote");
assert_eq!(QuoteForm::Unquote.iac_forge_tag(), "unquote");
assert_eq!(QuoteForm::UnquoteSplice.iac_forge_tag(), "unquote-splicing");
}
// ── `QuoteForm::{QUOTE_IAC_FORGE_TAG, QUASIQUOTE_IAC_FORGE_TAG,
// UNQUOTE_IAC_FORGE_TAG, UNQUOTE_SPLICE_IAC_FORGE_TAG,
// IAC_FORGE_TAGS}` — per-role `&'static str` iac-forge canonical-
// form tag algebra on the closed-set outer [`QuoteForm`]. Peer of
// the reader-prefix axis's [`QuoteForm::{QUOTE_PREFIX,
// QUASIQUOTE_PREFIX, UNQUOTE_PREFIX, UNQUOTE_SPLICE_PREFIX,
// PREFIXES}`] block above — the same closed set carries TWO
// orthogonal byte vocabularies (the Lisp reader prefixes the
// tokenizer classifies on, the iac-forge canonical-form tags the
// cross-crate attestation layer round-trips through), each now
// pinned at a per-role `pub const` plus a paired ALL array.
#[test]
fn quote_form_per_role_iac_forge_tags_pin_canonical_bytes() {
// Pin each per-role `pub const` at its exact canonical byte
// sequence. Sweeping via a per-variant pair rather than four
// hand-rolled `assert_eq!(QuoteForm::X_IAC_FORGE_TAG, "x")`
// asserts (a) that each constant IS the load-bearing byte
// string, and (b) that the pairing between the const and the
// spelling is enforced at rustc's constant-folding-level so a
// future rename of the const surfaces here as a spelling drift
// rather than as a silent canonical-form regression.
for (label, actual, expected) in [
(
"QUOTE_IAC_FORGE_TAG",
QuoteForm::QUOTE_IAC_FORGE_TAG,
"quote",
),
(
"QUASIQUOTE_IAC_FORGE_TAG",
QuoteForm::QUASIQUOTE_IAC_FORGE_TAG,
"quasiquote",
),
(
"UNQUOTE_IAC_FORGE_TAG",
QuoteForm::UNQUOTE_IAC_FORGE_TAG,
"unquote",
),
(
"UNQUOTE_SPLICE_IAC_FORGE_TAG",
QuoteForm::UNQUOTE_SPLICE_IAC_FORGE_TAG,
"unquote-splicing",
),
] {
assert_eq!(
actual, expected,
"QuoteForm::{label} drifted from canonical `{expected}` bytes"
);
}
}
#[test]
fn quote_form_iac_forge_tag_routes_through_typed_per_role_constants() {
// PATH-UNIFORMITY: `Self::iac_forge_tag(self)` returns the
// per-role `pub const` byte-for-byte per variant, catching a
// regression that reverts ONE arm to an inline `"quote"` /
// `"quasiquote"` / `"unquote"` / `"unquote-splicing"` string
// literal (or drifts one arm's bytes silently). Sibling posture
// to `quote_form_prefix_routes_through_typed_per_role_constants`
// on the reader-prefix axis of the SAME closed set.
for (qf, expected) in [
(QuoteForm::Quote, QuoteForm::QUOTE_IAC_FORGE_TAG),
(QuoteForm::Quasiquote, QuoteForm::QUASIQUOTE_IAC_FORGE_TAG),
(QuoteForm::Unquote, QuoteForm::UNQUOTE_IAC_FORGE_TAG),
(
QuoteForm::UnquoteSplice,
QuoteForm::UNQUOTE_SPLICE_IAC_FORGE_TAG,
),
] {
let actual = qf.iac_forge_tag();
assert_eq!(
actual, expected,
"QuoteForm::{qf:?}.iac_forge_tag() `{actual}` drifted from \
per-role constant `{expected}` — the arm must route \
through the typed constant rather than an inline literal",
);
}
}
#[test]
fn quote_form_iac_forge_tags_has_expected_cardinality() {
// Cardinality contract: `Self::IAC_FORGE_TAGS.len() == 4` —
// pinned at the declaration site by rustc's forced-arity check
// on `[&'static str; 4]`. This test surfaces the arity as a
// fail-loud runtime pin so a future refactor that switches the
// array type to `&[&'static str]` (dropping the compile-time
// arity forcing) doesn't silently loosen the closed-set
// discipline the family relies on. Sibling posture to
// `quote_form_prefixes_has_expected_cardinality` on the peer
// reader-prefix axis.
assert_eq!(
QuoteForm::IAC_FORGE_TAGS.len(),
4,
"QuoteForm::IAC_FORGE_TAGS cardinality drifted from 4 — the \
closed homoiconic-prefix domain admits exactly four \
wrappers by construction; a fifth extension surfaces here"
);
}
#[test]
fn quote_form_iac_forge_tags_align_with_all_by_index() {
// ALIGNMENT CONTRACT: `Self::IAC_FORGE_TAGS[i] ==
// Self::ALL[i].iac_forge_tag()` element-wise. Pins that the
// typed variant ALL and the `&'static str` IAC_FORGE_TAGS ALL
// stay in lockstep under any reorder — a regression that
// reorders ONE array without reordering the other silently
// misaligns every `zip(ALL, IAC_FORGE_TAGS)` consumer (cross-
// crate attestation renderers, LSP canonical-form completion
// providers, metric-label emitters, coverage reporters).
// Sibling posture to `quote_form_prefixes_align_with_all_by_index`
// on the peer reader-prefix axis.
for (i, qf) in QuoteForm::ALL.iter().enumerate() {
assert_eq!(
QuoteForm::IAC_FORGE_TAGS[i],
qf.iac_forge_tag(),
"QuoteForm::IAC_FORGE_TAGS[{i}] `{tag}` drifted from \
QuoteForm::ALL[{i}] ({qf:?}).iac_forge_tag() `{via_variant}` \
— the canonical declaration order of the ALL array \
and the iac-forge tag projection must match element-wise",
tag = QuoteForm::IAC_FORGE_TAGS[i],
via_variant = qf.iac_forge_tag(),
);
}
}
#[test]
fn quote_form_iac_forge_tags_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every entry of the `IAC_FORGE_TAGS`
// array must differ so the cross-crate canonical-form decoder
// (any future `IAC_FORGE_TAGS.iter().find(|t| *t == head)`
// sweep, any BLAKE3 attestation key comparison) cannot route
// two homoiconic prefixes through the same tag arm. Family-wide
// sweep over `IAC_FORGE_TAGS × IAC_FORGE_TAGS` — supersedes any
// per-pair pin and picks up new tags mechanically. Sibling
// posture to `quote_form_prefixes_pairwise_distinct` on the
// peer reader-prefix axis.
for (i, a) in QuoteForm::IAC_FORGE_TAGS.iter().enumerate() {
for (j, b) in QuoteForm::IAC_FORGE_TAGS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"QuoteForm::IAC_FORGE_TAGS[{i}] `{a}` collides with \
QuoteForm::IAC_FORGE_TAGS[{j}] `{b}` — the \
canonical-form decoder's cascade would route two \
homoiconic prefixes through the same tag arm"
);
}
}
}
#[test]
fn quote_form_iac_forge_tags_diverge_from_prefixes_pairwise() {
// AXIS-ORTHOGONALITY: `IAC_FORGE_TAGS` (the cross-crate
// canonical-form axis) and `PREFIXES` (the Lisp reader-prefix
// axis) span two distinct byte vocabularies on the SAME closed
// set. Every per-variant pair must disagree: the canonical
// tags are word-length identifiers (`"quote"`, `"quasiquote"`,
// `"unquote"`, `"unquote-splicing"`) while the reader prefixes
// are punctuation (`"'"`, `` "`" ``, `","`, `",@"`). A
// regression that collapsed the two axes (a hypothetical
// consolidation PR that reused `iac_forge_tag()`'s bytes at
// the reader prefix site, or vice versa) would silently break
// either the source-code round-trip (readers no longer see
// `"'"`) OR the canonical-form round-trip (attestation keys
// no longer see `"quote"`). Sweep every variant's per-axis
// pair — supersedes any per-variant pin and picks up new
// prefix/tag pairs mechanically.
for (i, qf) in QuoteForm::ALL.iter().enumerate() {
let prefix = QuoteForm::PREFIXES[i];
let tag = QuoteForm::IAC_FORGE_TAGS[i];
assert_ne!(
prefix, tag,
"QuoteForm::{qf:?} — reader prefix `{prefix}` collides \
with iac-forge tag `{tag}`; the two axes must span \
distinct byte vocabularies on the closed set",
);
}
}
#[test]
fn quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice() {
// BOUNDARY-DISTINCT CONTRACT: the iac-forge canonical tag for
// `UnquoteSplice` is `"unquote-splicing"` (Common Lisp idiom,
// load-bearing for canonical-form round-trip with the iac-forge
// ecosystem), distinct from `SexpShape::label`'s shorter
// `"unquote-splice"` (the substrate's diagnostic label idiom).
// The two projections key the SAME closed-set on TWO distinct
// boundaries — pinning the divergence here documents the
// intent: a future "consolidation" PR that homogenizes them
// would silently break either the iac-forge canonical-form
// round-trip OR the operator-facing diagnostic surface. The
// three other variants (Quote, Quasiquote, Unquote) DO match
// across both projections — pin that path-uniformity too so a
// regression that drifts one of the three matched arms surfaces
// immediately. Sibling-arm sweep so the (variant, tag) AND
// (variant, label) pairings stay load-bearing under reordering
// refactors.
use crate::error::SexpShape;
assert_eq!(
QuoteForm::Quote.iac_forge_tag(),
SexpShape::Quote.label(),
"quote tag/label agreement"
);
assert_eq!(
QuoteForm::Quasiquote.iac_forge_tag(),
SexpShape::Quasiquote.label(),
"quasiquote tag/label agreement"
);
assert_eq!(
QuoteForm::Unquote.iac_forge_tag(),
SexpShape::Unquote.label(),
"unquote tag/label agreement"
);
// The intentional divergence — load-bearing for the iac-forge
// canonical form vs the substrate's diagnostic label.
assert_eq!(QuoteForm::UnquoteSplice.iac_forge_tag(), "unquote-splicing");
assert_eq!(SexpShape::UnquoteSplice.label(), "unquote-splice");
assert_ne!(
QuoteForm::UnquoteSplice.iac_forge_tag(),
SexpShape::UnquoteSplice.label(),
"the two projections must disagree at UnquoteSplice — the CL canonical \
form requires '-splicing' while the substrate's diagnostic label uses \
the shorter '-splice'; consolidating them would break either side",
);
}
#[test]
fn quote_form_from_iac_forge_tag_decodes_each_canonical_tag_to_its_variant() {
// TYPED INVERSE CONTRACT: the four canonical CL tag literals
// `"quote"` / `"quasiquote"` / `"unquote"` / `"unquote-splicing"`
// decode through `QuoteForm::from_iac_forge_tag` to their exact
// `QuoteForm` variant — the inbound iac-forge canonical-form
// decode surface's per-arm truth table. Sibling posture to
// `quote_form_iac_forge_tag_pins_canonical_lisp_tag_strings_for_every_variant`
// on the OUTBOUND projection axis: that pin binds each variant to
// its canonical tag; THIS pin binds each canonical tag to its
// variant, closing the (outbound, inbound) roundtrip pair at ONE
// typed method on the algebra rather than at TWO surfaces the
// consumer would have to hand-roll independently.
//
// A regression that drifts ONE arm's inbound decode (a future
// refactor that inlines the four-arm sweep and drops the
// `"quasiquote"` arm, a byte-drifted rename that leaves the
// outbound `iac_forge_tag()` unchanged but breaks the inverse)
// fails-loudly here on the affected arm before any downstream
// iac-forge canonical-form consumer surfaces the drift.
assert_eq!(
QuoteForm::from_iac_forge_tag("quote"),
Some(QuoteForm::Quote),
);
assert_eq!(
QuoteForm::from_iac_forge_tag("quasiquote"),
Some(QuoteForm::Quasiquote),
);
assert_eq!(
QuoteForm::from_iac_forge_tag("unquote"),
Some(QuoteForm::Unquote),
);
assert_eq!(
QuoteForm::from_iac_forge_tag("unquote-splicing"),
Some(QuoteForm::UnquoteSplice),
);
}
#[test]
fn quote_form_from_iac_forge_tag_round_trips_through_iac_forge_tag_for_every_variant() {
// TYPED ROUNDTRIP CONTRACT: for every `qf` in `QuoteForm::ALL`,
// `QuoteForm::from_iac_forge_tag(qf.iac_forge_tag()) == Some(qf)`
// — the composition of the outbound projection with the inbound
// inverse decoder yields the identity on the closed four-arm
// domain. Sibling posture to
// `quote_form_lead_char_round_trips_through_from_lead_char_for_every_variant`
// one axis over on the reader-lead-char inverse decoder — both
// pin the (forward, inverse) composition-identity at the closed
// set's canonical carrier variants without relying on the
// per-arm inbound truth table above (which pins the arm-by-arm
// decoder mapping; this pin binds the closed-set-wide roundtrip
// property that emerges from the arm mapping).
//
// A regression that breaks ONE variant's roundtrip (a future
// refactor that drops `QuoteForm::Unquote` from `Self::ALL`
// silently while leaving the outbound `iac_forge_tag()` arm
// intact, an inbound decoder that returns `Some(Self::Quote)`
// for an unrelated variant's tag) fails-loudly here through the
// closed-set sweep, catching the drift on the affected variant.
for &qf in QuoteForm::ALL.iter() {
let outbound = qf.iac_forge_tag();
let inbound = QuoteForm::from_iac_forge_tag(outbound);
assert_eq!(
inbound,
Some(qf),
"QuoteForm::{qf:?} — outbound iac_forge_tag `{outbound}` \
failed to round-trip through from_iac_forge_tag",
);
}
}
#[test]
fn quote_form_from_iac_forge_tag_rejects_empty_input() {
// EMPTY-INPUT REJECTION: the empty string `""` is structurally
// outside the four-arm canonical CL tag closed set — no variant
// projects to `""` through `iac_forge_tag`, so the inverse
// decode rejects cleanly with `None`. Pins the empty-input
// boundary case operators hit when a canonical-form field is
// absent or blank but the decode is reached anyway (a
// deserialization codepath that reads an empty tag slot, an
// LSP quick-fix that surfaces an empty completion buffer).
// Sibling posture to `parse_label_rejects_empty_input` on the
// closed-set trait's parse-rejection axis one vocabulary over
// (reader-punctuation) — both pin the empty-input rejection so
// no future implementor can drift the decoder's empty-input
// behavior accidentally.
assert_eq!(QuoteForm::from_iac_forge_tag(""), None);
}
#[test]
fn quote_form_from_iac_forge_tag_is_case_sensitive() {
// CASE-SENSITIVE CONTRACT: the four canonical CL tag literals
// are the exact byte sequences the iac-forge canonical form
// renders; case drift between the caller's input and the
// canonical literal is a REJECTION, not a normalization. Pin
// the case-sensitive contract across (a) an all-uppercase
// drift (`"QUOTE"`), (b) a title-case drift (`"Quote"`), and
// (c) an internal-uppercase drift on the multi-word tag
// (`"Unquote-Splicing"`, `"unquote-Splicing"`) — the three
// representative case-drift shapes future operator input
// could reach.
//
// A regression that relaxes the decode to case-insensitive (an
// overzealous normalization pass, an `eq_ignore_ascii_case`
// introduction) silently subsumes the substrate-wide
// case-sensitive convention that binds the iac-forge
// canonical-form bytes to the SexpShape diagnostic-label bytes'
// path-uniformity (the two vocabularies share three of four
// arms byte-for-byte and disagree at UnquoteSplice — any
// future case-insensitive relaxation on ONE axis would silently
// bifurcate the two vocabularies' convention).
assert_eq!(QuoteForm::from_iac_forge_tag("QUOTE"), None);
assert_eq!(QuoteForm::from_iac_forge_tag("Quote"), None);
assert_eq!(QuoteForm::from_iac_forge_tag("Unquote-Splicing"), None);
assert_eq!(QuoteForm::from_iac_forge_tag("unquote-Splicing"), None);
}
#[test]
fn quote_form_from_iac_forge_tag_rejects_substrate_diagnostic_label_bytes() {
// AXIS-BOUNDARY CONTRACT: the SHORTER substrate diagnostic
// label `"unquote-splice"` (which `SexpShape::UnquoteSplice.label()`
// renders) MUST reject through the iac-forge canonical-form
// decoder — the CL canonical form requires the LONGER
// `"unquote-splicing"` per the intentional divergence pinned by
// `quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice`.
// The two vocabularies are ORTHOGONAL axes on the SAME closed
// four-arm outer set; a decoder keyed on the iac-forge axis
// MUST reject an input on the diagnostic-label axis, or the
// (canonical-form, diagnostic-label) axis-orthogonality
// collapses silently.
//
// A regression that accepts the shorter substrate diagnostic
// label at the iac-forge inbound decode (a hypothetical
// "consolidation" that merges the two vocabularies at the
// decoder boundary, a future decoder that walks BOTH
// `SexpShape::LABELS` AND `Self::IAC_FORGE_TAGS`) would
// silently bifurcate every iac-forge round-trip consumer:
// the outbound `iac_forge_tag()` still renders
// `"unquote-splicing"`, but the inbound decode accepts BOTH
// spellings — a canonical form emitted with the shorter
// substrate diagnostic label would re-decode as
// `QuoteForm::UnquoteSplice` even though it was never a valid
// iac-forge canonical form to begin with. Pin the rejection
// explicitly so the axis boundary stays enforced at the
// decoder itself, not just at the outbound projection.
assert_eq!(QuoteForm::from_iac_forge_tag("unquote-splice"), None);
}
#[test]
fn quote_form_from_iac_forge_tag_rejects_non_canonical_tag_strings() {
// GENERAL-REJECTION CONTRACT: inputs outside the four-arm
// canonical CL tag image reject cleanly with `None`. Pins a
// representative sweep across (a) arbitrary non-tag words that
// share no substring with the canonical vocabulary
// (`"hello"`, `"foo"`), (b) reader-punctuation bytes that
// belong to the ORTHOGONAL `Self::PREFIXES` axis and MUST
// route through `FromStr` (not this decoder) — the vocabulary
// boundary the axis-orthogonality contract carries, (c) the
// SexpShape diagnostic labels for non-quote-family arms
// (`"symbol"`, `"list"`) which project to `None` through
// `SexpShape::iac_forge_tag` and therefore MUST reject here
// too.
//
// A regression that accepts a reader-punctuation byte here (a
// future consolidated decoder that walks BOTH the prefix
// vocabulary AND the iac-forge-tag vocabulary) would silently
// subsume the [`FromStr`] surface's exclusive claim to the
// reader-punctuation axis, breaking every consumer that binds
// decoder identity to vocabulary axis. Pin the rejections
// explicitly so the vocabulary axis stays enforced at the
// decoder boundary itself, not just at the outbound projection.
for input in [
"hello", "foo",
// Reader-punctuation vocabulary — belongs to
// `Self::PREFIXES` / `Self::FromStr`, MUST reject here.
"'", "`", ",", ",@",
// SexpShape labels for non-quote-family shapes — no
// iac-forge tag projection at these variants, MUST reject.
"symbol", "list", "nil",
] {
assert_eq!(
QuoteForm::from_iac_forge_tag(input),
None,
"QuoteForm::from_iac_forge_tag({input:?}) accepted a \
non-canonical iac-forge tag input — the decoder must \
reject every string outside the four-arm canonical CL \
tag image",
);
}
}
#[test]
fn quote_form_from_iac_forge_tag_composes_through_iac_forge_tags_array() {
// COMPOSITION-LAW CONTRACT: sweeping the family-wide
// `Self::IAC_FORGE_TAGS` array through `from_iac_forge_tag`
// yields the parallel `Self::ALL` array element-wise —
// `from_iac_forge_tag(Self::IAC_FORGE_TAGS[i]) ==
// Some(Self::ALL[i])` for every `i in 0..4`. The composition
// binds the two family-wide forced-arity arrays through the
// typed inverse decoder at ONE typed sweep on the algebra,
// matching the alignment law
// `quote_form_iac_forge_tags_align_with_all_by_index` on the
// outbound projection sibling.
//
// Enforces the (typed variant, canonical tag) forward-and-
// back closure at the array level: a regression that drifts
// ONE array's contents against the other (a future refactor
// that reorders `Self::IAC_FORGE_TAGS` without reordering
// `Self::ALL`, a rename that breaks the alignment) fails-
// loudly here through the composition sweep before any
// downstream `zip(ALL, IAC_FORGE_TAGS)` consumer with an
// inbound decoder in hand surfaces the misalignment.
for (i, &tag) in QuoteForm::IAC_FORGE_TAGS.iter().enumerate() {
let decoded = QuoteForm::from_iac_forge_tag(tag);
let expected = QuoteForm::ALL[i];
assert_eq!(
decoded,
Some(expected),
"QuoteForm::from_iac_forge_tag(IAC_FORGE_TAGS[{i}] = {tag:?}) \
decoded to {decoded:?}, expected Some({expected:?}) \
(the composition of IAC_FORGE_TAGS with from_iac_forge_tag \
must yield ALL element-wise)",
);
}
}
#[test]
fn quote_form_from_iac_forge_tag_is_injective_on_canonical_domain() {
// INJECTIVITY CONTRACT: distinct canonical CL tags in
// `Self::IAC_FORGE_TAGS` decode to distinct typed variants
// through `from_iac_forge_tag` — the inverse decoder is
// injective on the closed four-arm canonical-tag domain.
// Sibling posture to the outbound
// `quote_form_iac_forge_tags_pairwise_distinct` on the same
// closed set: that pin asserts the four canonical-tag literals
// are pairwise distinct; THIS pin asserts the DECODED variants
// are also pairwise distinct — the pair together enforces
// BOTH sides of the two-way injectivity contract that the
// (typed variant, canonical tag) bijection carries on the
// closed set.
//
// A regression that decodes two distinct canonical tags to
// the same typed variant (a future refactor that collapses
// `Quasiquote` and `Quote` decode arms silently, an off-by-
// one in the linear sweep that returns the wrong variant for
// ONE tag) fails-loudly here at the decoded-set cardinality
// check before any downstream consumer surfaces the decoded-
// side collapse.
let decoded: Vec<QuoteForm> = QuoteForm::IAC_FORGE_TAGS
.iter()
.filter_map(|tag| QuoteForm::from_iac_forge_tag(tag))
.collect();
assert_eq!(
decoded.len(),
QuoteForm::ALL.len(),
"QuoteForm::from_iac_forge_tag failed to decode one or more \
canonical tags — the composition of IAC_FORGE_TAGS with \
from_iac_forge_tag lost {} arms (expected {} — the closed \
set's cardinality)",
QuoteForm::ALL.len() - decoded.len(),
QuoteForm::ALL.len(),
);
for i in 0..decoded.len() {
for j in (i + 1)..decoded.len() {
assert_ne!(
decoded[i], decoded[j],
"QuoteForm::from_iac_forge_tag is not injective on the \
canonical-tag domain — decoded[{i}] ({:?}) and \
decoded[{j}] ({:?}) collide",
decoded[i], decoded[j],
);
}
}
}
#[test]
fn quote_form_sexp_shape_pins_canonical_shape_identity_for_every_variant() {
// CLOSED-SET SHAPE-PROJECTION CONTRACT: each `QuoteForm` variant
// projects to its matching `SexpShape` variant — load-bearing for
// the (Sexp variant, SexpShape variant) pairing the substrate's
// outer-shape projection `domain::sexp_shape` routes through.
// Sibling-arm sweep so the four pairings stay load-bearing under
// reordering refactors. A regression that drifts ONE arm (e.g.
// routes `QuoteForm::Quote` to `SexpShape::Quasiquote`) surfaces
// here immediately rather than as a silent operator-facing
// diagnostic drift at every `LispError::TypeMismatch.got` slot
// for a quote-family witness.
use crate::error::SexpShape;
assert_eq!(QuoteForm::Quote.sexp_shape(), SexpShape::Quote);
assert_eq!(QuoteForm::Quasiquote.sexp_shape(), SexpShape::Quasiquote);
assert_eq!(QuoteForm::Unquote.sexp_shape(), SexpShape::Unquote);
assert_eq!(
QuoteForm::UnquoteSplice.sexp_shape(),
SexpShape::UnquoteSplice
);
}
#[test]
fn quote_form_sexp_shape_composes_with_label_for_canonical_short_diagnostic_string() {
// COMPOSITION-LAW CONTRACT: `qf.sexp_shape().label()` is the
// canonical short diagnostic string for the quote-family marker
// — `"quote"`, `"quasiquote"`, `"unquote"`, `"unquote-splice"`.
// The composition law binds the substrate's typed marker
// (`QuoteForm`) to its diagnostic surface (`SexpShape::label`)
// through ONE algebra so a future change to either projection's
// label (e.g. a substrate-wide rename of `"unquote-splice"` to
// `"splice"`) rides through the typed composition rather than
// requiring an inline match at every diagnostic-construction
// site that previously hand-paired the marker with its label.
// Pin the short labels here — DISTINCT from the iac-forge tag's
// `"unquote-splicing"` (load-bearing for the boundary distinction
// already pinned by
// `quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice`).
assert_eq!(QuoteForm::Quote.sexp_shape().label(), "quote");
assert_eq!(QuoteForm::Quasiquote.sexp_shape().label(), "quasiquote");
assert_eq!(QuoteForm::Unquote.sexp_shape().label(), "unquote");
assert_eq!(
QuoteForm::UnquoteSplice.sexp_shape().label(),
"unquote-splice"
);
}
#[test]
fn quote_form_label_projects_each_variant_to_canonical_diagnostic_label() {
// PER-ARM CONTRACT: pin the outer-`QuoteForm` `Self::label`
// projection produces the FOUR canonical short diagnostic labels
// byte-for-byte across every reachable quote-family variant.
// Pre-lift the outer-`QuoteForm` diagnostic-label projection had
// no typed primitive on the marker algebra — a consumer with a
// `QuoteForm` in hand wanting the canonical short label had to
// spell the two-step composition `qf.sexp_shape().label()` at
// every callsite (a shape pinned as a load-bearing composition
// law by `quote_form_sexp_shape_composes_with_label_for_canonical_short_diagnostic_string`
// one arm above), OR go through `qf.wrap(inner).type_name()`
// which wraps and projects for no runtime purpose. Post-lift the
// FOUR arms bind at ONE typed projection on the outer-`QuoteForm`
// algebra that routes through `SexpShape::label` — the
// (QuoteForm variant, label string) pairing binds at ONE typed
// algebra composition spanning THREE typed layers (`QuoteForm`
// → `SexpShape` → `&'static str`).
//
// Sibling-shape pin to
// `atom_label_projects_each_variant_to_canonical_diagnostic_label`
// one algebra layer down (outer-`Atom` label pin) and
// `sexp_type_name_covers_every_variant` one algebra layer up
// (outer-`Sexp` type_name pin). A regression that drifts ONE
// arm's mapping (e.g. renaming `"unquote-splice"` to `"splice"`
// inline here, dropping the `Unquote → "unquote"` boundary
// rename) fails-loudly at THIS test AND the sibling
// `SexpShape::label` per-arm pin.
assert_eq!(QuoteForm::Quote.label(), "quote");
assert_eq!(QuoteForm::Quasiquote.label(), "quasiquote");
assert_eq!(QuoteForm::Unquote.label(), "unquote");
assert_eq!(QuoteForm::UnquoteSplice.label(), "unquote-splice");
}
#[test]
fn quote_form_label_composes_through_sexp_shape_label_for_every_variant() {
// COMPOSITION-LAW CONTRACT: `qf.label() == qf.sexp_shape().label()`
// for every reachable quote-family marker — the outer-`QuoteForm`
// label projection is structurally derived through `Self::sexp_shape`
// + `SexpShape::label` rather than through a parallel four-arm
// inline match on the outer-`QuoteForm` algebra. Pin the
// composition law so a future refactor that re-inlines the four
// quote-family literals here (and gains its own drift surface
// separate from the `SexpShape::label` canonical site) surfaces
// immediately. The pointer-equality check pins the composition
// produces the SAME `&'static str` (not just a byte-equal copy)
// for every variant — proof the routing hits ONE static literal
// site (`SexpShape::label` via `QuoteForm::sexp_shape().label()`)
// rather than a parallel inline table on the outer-`QuoteForm`
// algebra.
//
// Sibling-shape pin to
// `atom_label_composes_through_kind_label_for_every_variant` on
// the outer-`Atom` value / `AtomKind` marker pair and
// `sexp_type_name_method_composes_through_shape_label_for_every_outer_shape`
// on the outer-`Sexp` value / `SexpShape` marker pair. The three
// routing pins jointly enforce the (outer-value, canonical label)
// pairing stays a full three-layer typed composition on every
// typed-value algebra rather than degrading to a per-layer inline
// literal table.
for qf in QuoteForm::ALL {
let via_label = qf.label();
let via_composition = qf.sexp_shape().label();
assert_eq!(
via_label, via_composition,
"QuoteForm::label() must route through self.sexp_shape().label() \
for {qf:?} — drift here means the lift was reverted to inline arms",
);
assert!(
std::ptr::eq(via_label.as_ptr(), via_composition.as_ptr()),
"QuoteForm::label() must return the SAME `&'static str` as \
self.sexp_shape().label() for {qf:?} — pointer drift means \
the lift composes through a parallel literal table rather \
than routing into the canonical SexpShape::label site",
);
}
}
#[test]
fn quote_form_label_agrees_with_sexp_type_name_at_every_quote_form_arm() {
// CROSS-ALGEBRA AGREEMENT CONTRACT: for every quote-family marker
// `qf` and every inner body `inner`, `qf.label() ==
// qf.wrap(inner.clone()).type_name()`. The agreement is a TYPED
// CONSEQUENCE of the two typed compositions —
// `qf.wrap(inner).type_name()` routes through `Sexp::shape()`'s
// quote-family arms which compose with `SexpShape::label`
// byte-for-byte with `qf.sexp_shape().label()` (which itself IS
// the body of `qf.label()`). A regression that drifts either side
// of the cross-algebra bridge (an outer-`QuoteForm` label
// re-inlined onto a different literal, an outer-`Sexp` quote-arm
// re-routed through a stale shape projection, a
// `QuoteForm::sexp_shape` arm that swaps two markers) fails-
// loudly here rather than as a silent operator-facing diagnostic
// drift at every consumer that pattern-matches on the outer-
// `Sexp` label vs the outer-`QuoteForm` label independently.
//
// Sibling posture to
// `atom_label_agrees_with_sexp_type_name_at_every_atom_arm` on
// the atomic-payload carving — that pin binds the outer-value-
// level vocabulary containment (`Atom::label ==
// Sexp::Atom(_).type_name()`), this pin binds the same
// containment on the quote-family carving (`QuoteForm::label ==
// QuoteForm::wrap(_).type_name()`) so the THREE-layer typed
// composition on the outer-`QuoteForm` algebra and the FOUR-
// layer typed composition on the outer-`Sexp` algebra agree at
// their common quote-family arms.
let inner = Sexp::symbol("x");
for qf in QuoteForm::ALL {
let via_quote_form = qf.label();
let via_sexp = qf.wrap(inner.clone()).type_name();
assert_eq!(
via_quote_form, via_sexp,
"QuoteForm::label() must agree with QuoteForm::wrap(_).type_name() \
for {qf:?} — cross-algebra label drift at the quote-family arms \
would fracture the typed diagnostic vocabulary between the \
outer-QuoteForm and outer-Sexp algebras",
);
assert!(
std::ptr::eq(via_quote_form.as_ptr(), via_sexp.as_ptr()),
"QuoteForm::label() must return the SAME `&'static str` as \
QuoteForm::wrap(_).type_name() for {qf:?} — pointer drift means \
one algebra layer re-inlined the literal rather than routing \
into the canonical `SexpShape::label` site",
);
}
}
#[test]
fn quote_form_label_diverges_from_iac_forge_tag_for_unquote_splice() {
// BOUNDARY-DISTINCT CONTRACT: at the `UnquoteSplice` arm,
// `qf.label() == "unquote-splice"` (the substrate's diagnostic
// label idiom) while `qf.iac_forge_tag() == "unquote-splicing"`
// (the Common-Lisp canonical form, load-bearing for canonical-
// form round-trip with the iac-forge ecosystem). The two
// projections key the SAME closed-set on TWO distinct boundaries
// — pinning the divergence on the NEW typed peer documents the
// intent: a future "consolidation" PR that homogenizes `label`
// and `iac_forge_tag` at the `UnquoteSplice` arm would silently
// break either the iac-forge canonical-form round-trip OR the
// operator-facing diagnostic surface. Sibling-arm posture to
// `quote_form_iac_forge_tag_diverges_from_sexp_shape_label_for_unquote_splice`
// which pinned the divergence at the `qf.sexp_shape().label()`
// composition; this pin lifts the divergence contract onto the
// NEW `QuoteForm::label` typed peer. The three other variants
// (Quote, Quasiquote, Unquote) DO match across both projections
// — pin that path-uniformity too so a regression that drifts one
// of the three matched arms surfaces immediately.
assert_eq!(
QuoteForm::Quote.iac_forge_tag(),
QuoteForm::Quote.label(),
"quote tag/label agreement",
);
assert_eq!(
QuoteForm::Quasiquote.iac_forge_tag(),
QuoteForm::Quasiquote.label(),
"quasiquote tag/label agreement",
);
assert_eq!(
QuoteForm::Unquote.iac_forge_tag(),
QuoteForm::Unquote.label(),
"unquote tag/label agreement",
);
// The intentional divergence — load-bearing for the iac-forge
// canonical form vs the substrate's diagnostic label.
assert_eq!(QuoteForm::UnquoteSplice.iac_forge_tag(), "unquote-splicing");
assert_eq!(QuoteForm::UnquoteSplice.label(), "unquote-splice");
assert_ne!(
QuoteForm::UnquoteSplice.iac_forge_tag(),
QuoteForm::UnquoteSplice.label(),
"the two projections must disagree at UnquoteSplice — the CL canonical \
form requires '-splicing' while the substrate's diagnostic label uses \
the shorter '-splice'; consolidating them would break either side",
);
}
#[test]
fn quote_form_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte() {
// ALIAS CONTRACT: pin every one of the four per-role
// `pub const QuoteForm::*_LABEL` aliases equals the corresponding
// `pub const SexpShape::*_LABEL` byte-for-byte — so the QuoteForm
// ⊂ SexpShape marker-vocabulary containment routes through the
// typed `pub const QuoteForm::V_LABEL: &'static str =
// SexpShape::V_LABEL` alias chain rather than through two
// independent literal-discipline sites. A regression that renames
// the SexpShape side without updating the QuoteForm alias
// pointing at it fails-loudly here with the exact axis identified
// (QUOTE / QUASIQUOTE / UNQUOTE / UNQUOTE_SPLICE); a regression
// that re-inlines the QuoteForm constant to a fresh literal still
// passes this pin but loses the alias-chain typing (which is what
// `quote_form_label_arms_route_through_per_role_labels_for_every_variant`
// + `quote_form_labels_align_with_all_by_index` catch in
// combination).
//
// Sibling-shape pin to
// `atom_kind_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte`
// on the peer 6-of-12 atomic-payload carving and
// `structural_kind_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte`
// on the peer 2-of-12 structural-residual carving — this pin
// closes the fourth and final SexpShape sub-carving's alias-chain
// contract at the exact same shape.
assert_eq!(QuoteForm::QUOTE_LABEL, SexpShape::QUOTE_LABEL);
assert_eq!(QuoteForm::QUASIQUOTE_LABEL, SexpShape::QUASIQUOTE_LABEL);
assert_eq!(QuoteForm::UNQUOTE_LABEL, SexpShape::UNQUOTE_LABEL);
assert_eq!(
QuoteForm::UNQUOTE_SPLICE_LABEL,
SexpShape::UNQUOTE_SPLICE_LABEL,
);
}
#[test]
fn quote_form_label_arms_route_through_per_role_labels_for_every_variant() {
// PATH-UNIFORMITY: `QuoteForm::V.label()` MUST equal the per-role
// `pub const QuoteForm::V_LABEL` for every `v: QuoteForm`. Pre-
// lift the four quote-family marker labels were reachable through
// `QuoteForm::label` (the composition `self.sexp_shape().label()`
// — routing into `SexpShape::*_LABEL`) OR through direct
// `SexpShape::*_LABEL` reach-across; post-lift each variant's
// canonical bytes are reachable through the per-role
// `QuoteForm::*_LABEL` alias too. Pin the byte-equality between
// the runtime projection and the compile-time alias so a
// regression that renames the alias without updating the arm (or
// vice versa) fails-loudly at the exact axis.
//
// Sibling-shape pin to
// `atom_kind_label_arms_route_through_per_role_labels_for_every_variant`
// and
// `structural_kind_label_arms_route_through_per_role_labels_for_every_variant`
// — those pin the peer 6-of-12 and 2-of-12 sub-carvings; this pin
// binds the QuoteForm 4-of-12 subset algebra's per-role aliases
// against `QuoteForm::label`'s composition-routed arms so the
// four quote-family marker labels project through ONE aliased
// typed source of truth per role rather than through per-consumer
// inline literals.
assert_eq!(QuoteForm::Quote.label(), QuoteForm::QUOTE_LABEL);
assert_eq!(QuoteForm::Quasiquote.label(), QuoteForm::QUASIQUOTE_LABEL);
assert_eq!(QuoteForm::Unquote.label(), QuoteForm::UNQUOTE_LABEL);
assert_eq!(
QuoteForm::UnquoteSplice.label(),
QuoteForm::UNQUOTE_SPLICE_LABEL,
);
}
#[test]
fn quote_form_labels_has_expected_cardinality() {
// Cardinality pin: `LABELS.len() == 4` matches `ALL.len()` so a
// refactor that loosens the type to `&'static [&'static str]`
// fails HERE (the `[_; 4]` slot cannot be sliced silently), and
// a variant added to `ALL` without a matching `LABELS` row fails
// the pair-arity gate at the array literal itself before this
// test even runs. The pin doubles as an operator-visible mark of
// the family's cardinality across the substrate — four quote-
// family markers, matching the four-arm carving of the parent
// `SexpShape::LABELS` (the quote-family subset of the twelve
// canonical outer-shape labels).
assert_eq!(QuoteForm::LABELS.len(), 4);
assert_eq!(QuoteForm::LABELS.len(), QuoteForm::ALL.len());
}
#[test]
fn quote_form_labels_align_with_all_by_index() {
// ALIGNMENT PIN: sweep `LABELS[i] == ALL[i].label()` so any
// `zip(ALL, LABELS)` consumer reads a coherent (variant, label)
// pair off ONE forced-arity array pair. The declaration-order
// pin makes a family-wide consumer that walks the ALL / LABELS
// pair in lockstep (an LSP completion bar keyed on
// `QuoteForm::LABELS`, a Sekiban metric emitter labeling
// `tatara_lisp_quote_family_label_total{label}` by the per-index
// label) read one canonical (variant, bytes) pair per slot
// rather than routing through per-consumer paired-iteration. A
// regression that reorders LABELS without also reordering ALL
// (or vice versa) fails-loudly at the exact index that drifted.
assert_eq!(QuoteForm::LABELS.len(), QuoteForm::ALL.len());
for (i, qf) in QuoteForm::ALL.iter().enumerate() {
assert_eq!(
QuoteForm::LABELS[i],
qf.label(),
"QuoteForm::LABELS[{i}] `{lbl}` drifted from \
QuoteForm::ALL[{i}].label() `{via_variant}` — the \
canonical ALL ordering and the LABELS ordering must \
match element-wise",
lbl = QuoteForm::LABELS[i],
via_variant = qf.label(),
);
}
}
#[test]
fn quote_form_labels_pairwise_distinct() {
// 4x4 pairwise sweep so a collision between any two labels
// (which would silently degrade two distinct quote-family
// markers to the SAME diagnostic bytes and violate the closed-
// set FromStr round-trip through `SexpShape::from_str`) fails-
// loudly at the exact pair. Distinctness is already enforced
// structurally at the parent superset by
// `sexp_shape_labels_pairwise_distinct` (the twelve-variant
// sweep), but this pin is a secondary guard focused on the per-
// role `pub const` surface of the QuoteForm 4-of-12 subset
// directly rather than the runtime projection through
// `SexpShape::label`.
for (i, a) in QuoteForm::LABELS.iter().enumerate() {
for (j, b) in QuoteForm::LABELS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"QuoteForm::LABELS[{i}] ({a:?}) collides with \
QuoteForm::LABELS[{j}] ({b:?}) — two distinct \
quote-family markers cannot share diagnostic bytes",
);
}
}
}
#[test]
fn quote_form_labels_match_sexp_shape_labels_element_wise_via_alias_chain() {
// CROSS-AXIS PIN: `QuoteForm::LABELS[i] ==
// QuoteForm::ALL[i].sexp_shape().label()` for every index. Closes
// the alias-chain identity at the family-wide array level:
// LABELS is NOT a fresh literal table but the projection of ALL
// through the composition, materialized once at declaration time
// through the four per-role aliases. A regression that re-inlines
// LABELS to fresh literals (or that re-inlines each per-role
// constant off the aliased `SexpShape::*_LABEL` source of truth)
// still passes the pairwise-distinct + cardinality + alignment
// pins but drifts the alias chain — this pin catches that drift.
//
// Sibling-shape pin to
// `atom_kind_labels_match_sexp_shape_labels_element_wise_via_alias_chain`
// and
// `structural_kind_labels_match_sexp_shape_labels_element_wise_via_alias_chain`
// — those pin the peer 6-of-12 and 2-of-12 sub-carvings' alias
// chains through their `SexpShape` parents; this pin closes the
// fourth and final SexpShape sub-carving's alias-chain identity
// at the same shape.
assert_eq!(QuoteForm::LABELS.len(), QuoteForm::ALL.len());
for (i, qf) in QuoteForm::ALL.iter().enumerate() {
let via_composition = qf.sexp_shape().label();
assert_eq!(
QuoteForm::LABELS[i],
via_composition,
"QuoteForm::LABELS[{i}] `{lbl}` drifted from \
QuoteForm::ALL[{i}].sexp_shape().label() `{via}` — \
the alias-chain composition law `LABELS[i] == \
ALL[i].sexp_shape().label()` binds the family-wide \
array to the composition through sexp_shape + \
SexpShape::label; a drift here means the per-role \
aliases were re-inlined off their SexpShape source of \
truth",
lbl = QuoteForm::LABELS[i],
via = via_composition,
);
}
}
#[test]
fn quote_form_sexp_shape_paired_with_as_quote_form_preserves_pre_lift_pairing_for_every_sexp() {
// PATH-UNIFORMITY CONTRACT: the (Sexp variant, SexpShape variant)
// pairing the pre-lift `sexp_shape` arms encoded inline is now
// structurally derived via
// `s.as_quote_form().map(|(qf, _)| qf.sexp_shape())` for every
// quote-family `Sexp` shape. Pin the derivation against the
// pre-lift pairing across all four quote-family wrapper variants
// so a regression that drifts ONE side of the typed algebra
// (e.g. a `QuoteForm::Quote → SexpShape::Quasiquote` typo, or a
// `Sexp::as_quote_form` arm that swaps two markers) surfaces
// immediately. Non-quote-family shapes project to `None` from
// `as_quote_form`, which the assertion arm skips — the typed
// closed-set partition is load-bearing for the early-return
// shape of the lifted `domain::sexp_shape`.
use crate::error::SexpShape;
let cases: &[(&str, Sexp, SexpShape)] = &[
(
"quote",
Sexp::Quote(Box::new(Sexp::symbol("x"))),
SexpShape::Quote,
),
(
"quasiquote",
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))),
SexpShape::Quasiquote,
),
(
"unquote",
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
SexpShape::Unquote,
),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
SexpShape::UnquoteSplice,
),
];
for (label, sexp, expected_shape) in cases {
let (qf, _) = sexp
.as_quote_form()
.unwrap_or_else(|| panic!("{label} must project through as_quote_form"));
assert_eq!(
qf.sexp_shape(),
*expected_shape,
"{label} drifted from typed (QuoteForm, SexpShape) pairing"
);
}
}
#[test]
fn as_unquote_derives_from_as_quote_form_composed_with_subset_gate() {
// Path-uniformity: `Sexp::as_unquote` is now derived from
// `as_quote_form().and_then(|(qf, inner)| qf.as_unquote_form()
// .map(|uf| (uf, inner)))`. Pin that the derived semantic
// agrees with the pre-lift arm-based one across the closed
// Sexp variant set — every shape's projection through
// `as_unquote` must equal the manual composition through
// `as_quote_form` + `QuoteForm::as_unquote_form`. A regression
// that drifts ONE projection's posture from the composition
// becomes a typed test failure.
let shapes: Vec<(&str, Sexp)> = vec![
("nil", Sexp::Nil),
("symbol", Sexp::symbol("x")),
("keyword", Sexp::keyword("k")),
("string", Sexp::string("s")),
("int", Sexp::int(7)),
("float", Sexp::float(2.5)),
("bool", Sexp::boolean(true)),
("empty list", Sexp::List(vec![])),
("non-empty list", Sexp::List(vec![Sexp::symbol("op")])),
("quote", Sexp::Quote(Box::new(Sexp::symbol("x")))),
("quasiquote", Sexp::Quasiquote(Box::new(Sexp::symbol("x")))),
("unquote", Sexp::Unquote(Box::new(Sexp::symbol("x")))),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
),
];
for (label, sexp) in &shapes {
let via_direct = sexp.as_unquote();
let via_composed = sexp
.as_quote_form()
.and_then(|(qf, inner)| qf.as_unquote_form().map(|uf| (uf, inner)));
assert_eq!(
via_direct, via_composed,
"as_unquote drifted from composed as_quote_form+as_unquote_form at {label}"
);
}
}
#[test]
fn hash_for_sexp_structural_arms_route_through_structural_kind_hash_discriminator() {
// CACHE-KEY CONTRACT (Hash side, structural axis): pin that
// the lifted `Hash for Sexp` impl produces byte-identical
// hashes for the two structural-residual arms (`Sexp::Nil`,
// `Sexp::List(_)`) as the pre-lift implementation, routing
// through `StructuralKind::hash_discriminator` so the
// (Sexp variant, cache-key byte) pairing is structurally
// bound to the algebra rather than threaded through inline
// `0u8` / `2u8` literals. We compute the expected hash via a
// SECOND hasher that manually drives the pre-lift `<discr>
// .hash(h); <rest>.hash(h)` sequence, then compare. A
// regression that drifts the discriminator (e.g. renumbers
// `StructuralKind::List` to `1u8` and collides with the
// atomic-carve outer marker byte) OR re-orders the (discr,
// rest) sequence surfaces here as a hash-value mismatch.
// Sibling arm-sweep to
// `hash_for_sexp_preserves_legacy_quote_family_discriminator_bytes`
// on the quote-family axis (four wrapper variants) — the
// three closed-set carvings' hash arms all route through
// ONE typed method per carving, and this pin binds the
// structural-residual arm's post-lift shape against the
// pre-lift byte-stream.
use crate::error::StructuralKind;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
// (label, sexp, expected-first-discr-byte, extra-hash-sequence
// closure that drives the residual hash body after the
// discriminator byte)
#[allow(clippy::type_complexity)]
let cases: [(&str, Sexp, u8, Box<dyn Fn(&mut DefaultHasher)>); 2] = [
("nil", Sexp::Nil, 0u8, Box::new(|_h: &mut DefaultHasher| {})),
(
"list",
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(1)]),
2u8,
Box::new(|h: &mut DefaultHasher| {
let items = vec![Sexp::symbol("a"), Sexp::int(1)];
items.len().hash(h);
for i in &items {
i.hash(h);
}
}),
),
];
for (label, sexp, expected_discr, extra) in &cases {
let mut via_impl = DefaultHasher::new();
sexp.hash(&mut via_impl);
let mut via_legacy = DefaultHasher::new();
expected_discr.hash(&mut via_legacy);
extra(&mut via_legacy);
assert_eq!(
via_impl.finish(),
via_legacy.finish(),
"Hash for Sexp drifted from legacy (discr={expected_discr}, rest) sequence at {label}",
);
}
// Composition pin: pointer-independent structural equality —
// the discriminator byte value MUST agree between the typed
// projection and the pre-lift literal, so a regression that
// re-inlines the two arm literals as a parallel match-table
// (`Sexp::Nil => 0u8`, `Sexp::List(_) => 2u8`) still passes
// the hash-value sweep above but drifts if the future
// `StructuralKind::hash_discriminator` is re-numbered — this
// pin binds the composition IDENTITY (not just the value
// equality) between the outer `Hash for Sexp` body and the
// typed algebra.
assert_eq!(StructuralKind::Nil.hash_discriminator(), 0u8);
assert_eq!(StructuralKind::List.hash_discriminator(), 2u8);
}
#[test]
fn hash_for_sexp_preserves_legacy_quote_family_discriminator_bytes() {
// CACHE-KEY CONTRACT (Hash side): pin that the lifted
// `Hash for Sexp` impl produces byte-identical hashes for the
// four quote-family variants as the pre-lift implementation.
// We compute the expected hash via a SECOND hasher that
// manually drives the pre-lift `<discr>.hash(h); inner.hash(h)`
// sequence, then compare. A regression that drifts the
// discriminator OR re-orders the (discr, inner) sequence
// surfaces here as a hash-value mismatch.
use std::collections::hash_map::DefaultHasher;
let inner = Sexp::symbol("payload");
for (label, sexp, expected_discr) in [
("quote", Sexp::Quote(Box::new(inner.clone())), 3u8),
("quasiquote", Sexp::Quasiquote(Box::new(inner.clone())), 4u8),
("unquote", Sexp::Unquote(Box::new(inner.clone())), 5u8),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(inner.clone())),
6u8,
),
] {
let mut via_impl = DefaultHasher::new();
sexp.hash(&mut via_impl);
let mut via_legacy = DefaultHasher::new();
expected_discr.hash(&mut via_legacy);
inner.hash(&mut via_legacy);
assert_eq!(
via_impl.finish(),
via_legacy.finish(),
"Hash for Sexp drifted from legacy (discr={expected_discr}, inner) sequence at {label}"
);
}
}
#[test]
fn sexp_hash_discriminator_pins_legacy_outer_cache_key_bytes() {
// CACHE-KEY CONTRACT: pre-lift `Hash for Sexp` used the literal
// byte values 0/1/2 for Nil/Atom/List AND delegated 3/4/5/6 for
// Quote/Quasiquote/Unquote/UnquoteSplice through
// `QuoteForm::hash_discriminator`. The macro-expansion cache
// (`Expander::cache`) keys on Hash; ANY change to a discriminator
// byte silently invalidates every cached expansion across the
// substrate. Pin the seven legacy values explicitly so a
// regression that re-numbers them surfaces immediately — the
// outer-`Sexp` algebra MUST preserve the prior byte mapping bit-
// for-bit. Sibling posture to
// `atom_kind_hash_discriminator_pins_legacy_atom_cache_key_bytes`
// and `quote_form_hash_discriminator_pins_legacy_cache_key_bytes`
// on the two sub-carvings.
assert_eq!(Sexp::Nil.hash_discriminator(), 0);
assert_eq!(Sexp::symbol("x").hash_discriminator(), 1);
assert_eq!(Sexp::keyword("k").hash_discriminator(), 1);
assert_eq!(Sexp::string("s").hash_discriminator(), 1);
assert_eq!(Sexp::int(7).hash_discriminator(), 1);
assert_eq!(Sexp::float(2.5).hash_discriminator(), 1);
assert_eq!(Sexp::boolean(true).hash_discriminator(), 1);
assert_eq!(Sexp::List(vec![]).hash_discriminator(), 2);
assert_eq!(Sexp::Quote(Box::new(Sexp::Nil)).hash_discriminator(), 3);
assert_eq!(
Sexp::Quasiquote(Box::new(Sexp::Nil)).hash_discriminator(),
4
);
assert_eq!(Sexp::Unquote(Box::new(Sexp::Nil)).hash_discriminator(), 5);
assert_eq!(
Sexp::UnquoteSplice(Box::new(Sexp::Nil)).hash_discriminator(),
6
);
}
#[test]
fn sexp_hash_discriminator_bytes_partition_zero_through_six_injectively() {
// Closed-set injectivity across the seven outer-`Sexp` variants:
// the seven discriminator bytes MUST partition `{0, 1, 2, 3, 4,
// 5, 6}` injectively so two distinct outer variants never
// conflate their outer cache-key byte — a violation here means
// the cache could conflate e.g. `Sexp::List(vec![])` and
// `Sexp::Quote(Box::new(Sexp::Nil))` at the outer discriminator
// slot. Uses ONE seed per outer-variant sweep. Sibling pin to
// `atom_kind_hash_discriminator_bytes_are_pairwise_disjoint` (six-
// arm partition of `{0..=5}` nested inside the Atom outer byte
// `1`) and `quote_form_hash_discriminator_bytes_are_pairwise_
// disjoint` (four-arm partition of `{3..=6}` surfaced through
// this outer method's quote-family arms). Together the three
// partitions jointly cover the outer-Sexp discriminator space
// `{0..=6}` — the joint partition contract is pinned by
// `sexp_hash_discriminator_partitions_the_full_outer_discriminator_space_zero_through_six`
// below.
let bytes: Vec<u8> = [
Sexp::Nil,
Sexp::symbol("x"),
Sexp::List(vec![]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
]
.iter()
.map(Sexp::hash_discriminator)
.collect();
let mut sorted = bytes.clone();
sorted.sort_unstable();
let mut deduped = sorted.clone();
deduped.dedup();
assert_eq!(
sorted, deduped,
"Sexp hash discriminator bytes must be pairwise disjoint across the seven outer variants"
);
assert_eq!(sorted, vec![0, 1, 2, 3, 4, 5, 6]);
}
#[test]
fn sexp_hash_discriminator_partitions_the_full_outer_discriminator_space_zero_through_six() {
// JOINT PARTITION CONTRACT: the outer-`Sexp` discriminator byte
// space `{0..=6}` is jointly covered by the three carvings' typed
// discriminator methods — pinning the joint contract makes the
// prefix-uniqueness invariant a compile-time-verified theorem
// rather than a per-carving isolated pin.
//
// Sexp-outer: `{0, 1, 2, 3, 4, 5, 6}` via `Sexp::hash_discriminator`
// (the outer arm-partition method; the entire outer space).
// AtomKind: `{0, 1, 2, 3, 4, 5}` via `AtomKind::hash_discriminator`
// (nested inside the Atom outer byte `1`; NOT part of the outer
// partition, but pinned here to document the sub-carving space).
// QuoteForm: `{3, 4, 5, 6}` via `QuoteForm::hash_discriminator`
// (surfaced through the four quote-family arms of the outer
// method; MUST equal the outer sweep's `{3..=6}` slice).
//
// A regression that drifts the outer method's quote-family arms
// from the delegated `QuoteForm::hash_discriminator` bytes (e.g.
// routes `Sexp::Quote(_)` to `7u8` inline) fails-loudly here.
// Sibling posture to
// `structural_kind_hash_discriminator_disjoint_from_atom_outer_carve_byte_and_quote_form_hash_discriminator_partition`
// on the sub-carving axis — this pin binds the OUTER joint
// partition; that pin would bind a hypothetical structural sub-
// carving's disjointness.
let outer_seeds: Vec<Sexp> = vec![
Sexp::Nil,
Sexp::symbol("x"),
Sexp::List(vec![]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
let outer_bytes: std::collections::BTreeSet<u8> =
outer_seeds.iter().map(Sexp::hash_discriminator).collect();
let expected: std::collections::BTreeSet<u8> = (0u8..=6u8).collect();
assert_eq!(
outer_bytes, expected,
"Sexp::hash_discriminator must cover exactly the outer discriminator space {{0..=6}}"
);
let quote_bytes: std::collections::BTreeSet<u8> = QuoteForm::ALL
.iter()
.map(|qf| qf.hash_discriminator())
.collect();
let quote_slice: std::collections::BTreeSet<u8> = (3u8..=6u8).collect();
assert_eq!(
quote_bytes, quote_slice,
"QuoteForm::hash_discriminator must cover {{3..=6}} — the quote-family slice of the outer Sexp partition"
);
assert!(
quote_bytes.is_subset(&outer_bytes),
"QuoteForm::hash_discriminator bytes must be a subset of Sexp::hash_discriminator's outer partition"
);
}
#[test]
fn sexp_hash_discriminator_atom_arm_collapses_over_every_atom_kind() {
// OUTER-CARVING CONTRACT (atomic arm): every `AtomKind` variant
// projects through `Sexp::Atom` to the SAME outer discriminator
// byte `1u8` — the atomic outer arm is a single-byte marker on
// the outer partition, with the per-atom-kind inner byte
// (`AtomKind::hash_discriminator`'s `{0..=5}`) nested INSIDE
// `Atom::hash` — NOT surfaced through this method. Pin the six-
// way collapse so a regression that drifts ONE atom kind's outer
// routing (e.g. routes `Sexp::Atom(Atom::Int(_))` to `7u8`
// inline) surfaces here immediately. Sibling posture to
// `sexp_hash_discriminator_quote_arm_delegates_to_quote_form_
// hash_discriminator` on the quote-family arm — that arm
// DELEGATES to `QuoteForm::hash_discriminator` for `{3..=6}`;
// this arm COLLAPSES to a single outer byte `1`.
for (kind, sexp) in [
(AtomKind::Symbol, Sexp::symbol("s")),
(AtomKind::Keyword, Sexp::keyword("k")),
(AtomKind::Str, Sexp::string("t")),
(AtomKind::Int, Sexp::int(7)),
(AtomKind::Float, Sexp::float(2.5)),
(AtomKind::Bool, Sexp::boolean(true)),
] {
assert_eq!(
sexp.hash_discriminator(),
1,
"Sexp::Atom({kind:?}) must collapse to outer byte 1"
);
}
}
#[test]
fn sexp_hash_discriminator_quote_arm_delegates_to_quote_form_hash_discriminator() {
// OUTER-CARVING CONTRACT (quote-family arm): every `QuoteForm`
// variant projects through `QuoteForm::wrap` to a `Sexp::Quote_*`
// whose `hash_discriminator` equals `qf.hash_discriminator()` —
// the four quote-family arms DELEGATE to the sub-algebra's
// discriminator method rather than inline four literals. Pin
// the delegation-identity across the closed set so a regression
// that inlines a byte at ONE arm (e.g. routes
// `Sexp::UnquoteSplice(_)` to `6u8` inline instead of through
// `QuoteForm::UnquoteSplice.hash_discriminator()`) fails-loudly
// here — it would type-check but silently drift if the sub-
// algebra's byte is renumbered.
for qf in QuoteForm::ALL {
let sexp = qf.wrap(Sexp::Nil);
assert_eq!(
sexp.hash_discriminator(),
qf.hash_discriminator(),
"Sexp {qf:?}-arm must delegate to QuoteForm::hash_discriminator"
);
}
}
#[test]
fn hash_for_sexp_routes_outer_discriminator_through_sexp_hash_discriminator() {
// ROUTING-LAW CONTRACT: pin the outer-`Sexp` routing IDENTITY —
// for every reachable outer-variant shape, `Hash for Sexp`
// produces byte-identical output to a hand-driven
// `<sexp.hash_discriminator()>.hash(h); <inner-payload-hash>`
// sequence. Binds the composition IDENTITY (not just value
// equality) between the outer Hash body and the typed algebra
// method — a regression that re-inlines the three literals
// (`0u8` / `1u8` / `2u8`) at the outer arms still drifts
// detectably if the future `Sexp::hash_discriminator` is
// re-numbered. Sibling posture to
// `hash_for_sexp_preserves_legacy_quote_family_discriminator_bytes`
// — that pin binds the quote-family arms against the pre-lift
// literal bytes; this pin binds ALL SEVEN outer arms against the
// post-lift typed method.
use std::collections::hash_map::DefaultHasher;
let payload = Sexp::symbol("payload");
let seeds: Vec<(&str, Sexp)> = vec![
("nil", Sexp::Nil),
("atom-symbol", Sexp::symbol("s")),
("atom-int", Sexp::int(7)),
("atom-float", Sexp::float(2.5)),
("atom-bool", Sexp::boolean(true)),
("empty list", Sexp::List(vec![])),
(
"non-empty list",
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
),
("quote", Sexp::Quote(Box::new(payload.clone()))),
("quasiquote", Sexp::Quasiquote(Box::new(payload.clone()))),
("unquote", Sexp::Unquote(Box::new(payload.clone()))),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(payload.clone())),
),
];
for (label, sexp) in seeds {
let mut via_impl = DefaultHasher::new();
sexp.hash(&mut via_impl);
let mut via_lifted = DefaultHasher::new();
sexp.hash_discriminator().hash(&mut via_lifted);
match &sexp {
Sexp::Nil => {}
Sexp::Atom(a) => a.hash(&mut via_lifted),
Sexp::List(items) => {
items.len().hash(&mut via_lifted);
for i in items {
i.hash(&mut via_lifted);
}
}
Sexp::Quote(_)
| Sexp::Quasiquote(_)
| Sexp::Unquote(_)
| Sexp::UnquoteSplice(_) => {
let (_, inner) = sexp.expect_quote_form();
inner.hash(&mut via_lifted);
}
}
assert_eq!(
via_impl.finish(),
via_lifted.finish(),
"Hash for Sexp drifted from routed-through-hash_discriminator sequence at {label}"
);
}
}
#[test]
fn sexp_hash_discriminator_routes_through_shape_hash_discriminator_via_composition() {
// COMPOSITION-IDENTITY CONTRACT (five-layer post-lift): pin the
// outer-`Sexp` cache-key routing IDENTITY through the new shape-
// level algebra layer — for every reachable outer-variant shape,
// `Sexp::hash_discriminator` MUST agree byte-for-byte with
// `self.shape().hash_discriminator()`. Post-lift the outer
// method's body is EXACTLY `self.shape().hash_discriminator()`,
// and this pin binds the routing identity across every reachable
// shape so a regression that re-inlines the seven arm literals
// (e.g. reverts to an inline match returning `0u8`/`1u8`/`2u8`
// and the four quote-family sub-carving delegations) still
// drifts detectably if the future `SexpShape::hash_discriminator`
// is re-numbered — the composition identity is what closes the
// outer-`Sexp` cache-key algebra at five typed layers (outer →
// shape → three sub-carvings). Sibling posture to
// `hash_for_sexp_routes_outer_discriminator_through_sexp_hash_discriminator`
// — that pin binds the `Hash for Sexp` body against the outer
// method; this pin binds the outer method against the shape-
// level method.
let payload = Sexp::symbol("payload");
let seeds: Vec<(&str, Sexp)> = vec![
("nil", Sexp::Nil),
("atom-symbol", Sexp::symbol("s")),
("atom-keyword", Sexp::keyword("k")),
("atom-string", Sexp::string("t")),
("atom-int", Sexp::int(7)),
("atom-float", Sexp::float(2.5)),
("atom-bool", Sexp::boolean(true)),
("empty list", Sexp::List(vec![])),
(
"non-empty list",
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
),
("quote", Sexp::Quote(Box::new(payload.clone()))),
("quasiquote", Sexp::Quasiquote(Box::new(payload.clone()))),
("unquote", Sexp::Unquote(Box::new(payload.clone()))),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(payload.clone())),
),
];
for (label, sexp) in seeds {
let outer = sexp.hash_discriminator();
let via_shape = sexp.shape().hash_discriminator();
assert_eq!(
outer, via_shape,
"Sexp::hash_discriminator at {label} drifted from self.shape().hash_discriminator() — the five-layer typed cache-key composition is broken",
);
}
}
#[test]
fn sexp_iac_forge_tag_routes_through_shape_iac_forge_tag_via_composition() {
// COMPOSITION-IDENTITY CONTRACT (outer-value peer): pin the
// outer-`Sexp` cross-crate canonical-form tag routing IDENTITY
// through the pre-existing shape-level projection — for every
// reachable outer-variant shape, `Sexp::iac_forge_tag` MUST agree
// arm-for-arm with `self.shape().iac_forge_tag()`. Post-lift the
// outer method's body is EXACTLY `self.shape().iac_forge_tag()`,
// and this pin binds the routing identity across every reachable
// shape so a regression that re-inlines a parallel four-arm
// match on the outer `Self::Quote | Self::Quasiquote | ...` set
// returning literal tag strings inline still drifts detectably
// if the shape-level projection's tag composition is re-numbered
// — the composition identity is what closes the outer-`Sexp`
// cross-crate canonical-form tag surface at four typed layers
// (outer → shape → carving → sub-carving-tag). Sibling posture
// to `sexp_hash_discriminator_routes_through_shape_hash_discriminator_via_composition`
// — that pin binds the outer method against the shape-level
// method on the cache-key byte axis; this pin binds the outer
// method against the shape-level method on the cross-crate
// canonical-form tag axis.
let payload = Sexp::symbol("payload");
let seeds: Vec<(&str, Sexp)> = vec![
("nil", Sexp::Nil),
("atom-symbol", Sexp::symbol("s")),
("atom-keyword", Sexp::keyword("k")),
("atom-string", Sexp::string("t")),
("atom-int", Sexp::int(7)),
("atom-float", Sexp::float(2.5)),
("atom-bool", Sexp::boolean(true)),
("empty list", Sexp::List(vec![])),
(
"non-empty list",
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
),
("quote", Sexp::Quote(Box::new(payload.clone()))),
("quasiquote", Sexp::Quasiquote(Box::new(payload.clone()))),
("unquote", Sexp::Unquote(Box::new(payload.clone()))),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(payload.clone())),
),
];
for (label, sexp) in seeds {
let outer = sexp.iac_forge_tag();
let via_shape = sexp.shape().iac_forge_tag();
assert_eq!(
outer, via_shape,
"Sexp::iac_forge_tag at {label} drifted from self.shape().iac_forge_tag() — the four-layer typed cross-crate canonical-form tag composition is broken",
);
}
}
#[test]
fn sexp_iac_forge_tag_pins_canonical_cl_tags_for_every_quote_family_arm() {
// CANONICAL-TAG CONTRACT (outer-value peer): the outer-value
// `Sexp::iac_forge_tag` MUST project each of the four homoiconic
// prefix-wrapper arms to the SAME canonical Common-Lisp tag
// string `crate::error::SexpShape::iac_forge_tag` projects at the
// shape-level (and `crate::ast::QuoteForm::iac_forge_tag` at the
// sub-carving level) — `Sexp::Quote → Some("quote")`,
// `Sexp::Quasiquote → Some("quasiquote")`, `Sexp::Unquote →
// Some("unquote")`, `Sexp::UnquoteSplice → Some("unquote-
// splicing")`. A regression that inlines a byte-drifted spelling
// here (e.g. `Sexp::UnquoteSplice → Some("unquote-splice")`
// conflating the substrate's shorter diagnostic label with the
// CL canonical form) silently breaks every cross-crate iac-forge
// consumer keyed on `(unquote-splicing ...)`. Sibling posture to
// `sexp_shape_iac_forge_tag_pins_canonical_cl_tags_for_every_quote_family_arm`
// one algebra level down — that pin binds the shape-level
// projection's canonical tag surface; this pin binds the outer-
// value projection's canonical tag surface across the closed
// four-arm quote-family sweep on the outer `Sexp` algebra.
let inner = Sexp::symbol("payload");
assert_eq!(
Sexp::Quote(Box::new(inner.clone())).iac_forge_tag(),
Some("quote"),
);
assert_eq!(
Sexp::Quasiquote(Box::new(inner.clone())).iac_forge_tag(),
Some("quasiquote"),
);
assert_eq!(
Sexp::Unquote(Box::new(inner.clone())).iac_forge_tag(),
Some("unquote"),
);
assert_eq!(
Sexp::UnquoteSplice(Box::new(inner)).iac_forge_tag(),
Some("unquote-splicing"),
);
}
#[test]
fn sexp_iac_forge_tag_returns_none_on_every_non_quote_family_variant() {
// PARTIAL-PROJECTION KERNEL CONTRACT (outer-value peer): every
// `Sexp` variant OUTSIDE the four-arm quote-family carving MUST
// project through `Sexp::iac_forge_tag` to `None` — the three-
// arm outer kernel `{Nil, Atom, List}` (which corresponds to the
// eight-shape kernel at the shape-level projection through the
// six-atomic-arms → outer `Atom` collapse of `Self::shape`). Pin
// representative seeds for each kernel arm — `Nil`, one atom per
// `AtomKind`, one empty + one non-empty list — so a regression
// that surfaces a bogus tag for a non-quote-family arm (e.g.
// `Sexp::List → Some("list")` conflating the outer-shape
// diagnostic label with the quote-family canonical form) fails-
// loudly here. Sibling posture to
// `sexp_shape_iac_forge_tag_returns_none_on_every_non_quote_family_shape`
// one algebra level down — that pin binds the shape-level
// projection's kernel; this pin binds the outer-value
// projection's kernel on the three-arm outer partition.
assert_eq!(Sexp::Nil.iac_forge_tag(), None);
assert_eq!(Sexp::symbol("s").iac_forge_tag(), None);
assert_eq!(Sexp::keyword("k").iac_forge_tag(), None);
assert_eq!(Sexp::string("t").iac_forge_tag(), None);
assert_eq!(Sexp::int(7).iac_forge_tag(), None);
assert_eq!(Sexp::float(2.5).iac_forge_tag(), None);
assert_eq!(Sexp::boolean(true).iac_forge_tag(), None);
assert_eq!(Sexp::List(vec![]).iac_forge_tag(), None);
assert_eq!(
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]).iac_forge_tag(),
None,
);
}
#[test]
fn sexp_iac_forge_tag_partitions_quote_family_and_kernel_disjointly() {
// IMAGE-PARTITION CONTRACT (outer-value peer): sweeping a
// representative seed per outer `Sexp` variant through
// `Sexp::iac_forge_tag` MUST partition into EXACTLY the four-arm
// quote-family image (four distinct canonical CL tag strings —
// the pre-image of `Some(_)`) AND the outer three-arm non-quote-
// family kernel (all `None` — `Nil` + one atom per `AtomKind` +
// one list). The image's `is_some()` count MUST be four
// (surjective onto the four-tag closed set), the kernel's
// `is_none()` count MUST cover every non-quote-family seed, and
// the total sweep sums to the thirteen-seed representative sweep
// covering all seven outer variants (six `Atom` payloads +
// `Nil` + one `List` + four quote-family arms). A regression that
// leaks a bogus `Some(_)` from a non-quote-family arm or drops a
// `Some(_)` from a quote-family arm fails-loudly here on the
// partition-cardinality axis before any downstream iac-forge
// consumer would surface the drift. Sibling posture to
// `sexp_shape_iac_forge_tag_partitions_quote_family_and_kernel_disjointly`
// one algebra level down — that pin binds the shape-level
// image-partition on the twelve-shape closed sweep; this pin
// binds the outer-value image-partition on the representative
// outer-variant sweep.
let payload = Sexp::symbol("payload");
let seeds: Vec<Sexp> = vec![
Sexp::Nil,
Sexp::symbol("s"),
Sexp::keyword("k"),
Sexp::string("t"),
Sexp::int(7),
Sexp::float(2.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
Sexp::Quote(Box::new(payload.clone())),
Sexp::Quasiquote(Box::new(payload.clone())),
Sexp::Unquote(Box::new(payload.clone())),
Sexp::UnquoteSplice(Box::new(payload.clone())),
];
let tag_image: std::collections::BTreeSet<&'static str> =
seeds.iter().filter_map(Sexp::iac_forge_tag).collect();
let expected_tag_image: std::collections::BTreeSet<&'static str> =
["quote", "quasiquote", "unquote", "unquote-splicing"]
.into_iter()
.collect();
assert_eq!(
tag_image, expected_tag_image,
"Sexp::iac_forge_tag image must exactly cover the four canonical CL quote-family tags",
);
let some_count = seeds
.iter()
.filter(|sexp| sexp.iac_forge_tag().is_some())
.count();
assert_eq!(
some_count, 4,
"Sexp::iac_forge_tag must return `Some(_)` on exactly the four-arm quote-family carving",
);
let none_count = seeds
.iter()
.filter(|sexp| sexp.iac_forge_tag().is_none())
.count();
assert_eq!(
none_count,
seeds.len() - 4,
"Sexp::iac_forge_tag must return `None` on every seed outside the four-arm quote-family carving",
);
assert_eq!(
some_count + none_count,
seeds.len(),
"Sexp::iac_forge_tag's image + kernel must partition the representative outer-variant sweep exactly",
);
}
#[test]
fn sexp_prefix_routes_through_shape_prefix_via_composition() {
// COMPOSITION-IDENTITY CONTRACT (outer-value peer): pin the
// outer-`Sexp` reader-punctuation surface routing IDENTITY
// through the pre-existing shape-level projection — for every
// reachable outer-variant shape, `Sexp::prefix` MUST agree arm-
// for-arm with `self.shape().prefix()`. Post-lift the outer
// method's body is EXACTLY `self.shape().prefix()`, and this
// pin binds the routing identity across every reachable shape so
// a regression that re-inlines a parallel four-arm match on the
// outer `Self::Quote | Self::Quasiquote | ...` set returning
// literal reader-punctuation strings inline still drifts
// detectably if the shape-level projection's prefix composition
// is re-numbered — the composition identity is what closes the
// outer-`Sexp` reader-punctuation surface at four typed layers
// (outer → shape → carving → sub-carving-prefix). Sibling
// posture to
// `sexp_iac_forge_tag_routes_through_shape_iac_forge_tag_via_composition`
// one vocabulary axis over — that pin binds the outer method
// against the shape-level method on the cross-crate canonical-
// form tag axis; this pin binds the outer method against the
// shape-level method on the reader-punctuation axis.
let payload = Sexp::symbol("payload");
let seeds: Vec<(&str, Sexp)> = vec![
("nil", Sexp::Nil),
("atom-symbol", Sexp::symbol("s")),
("atom-keyword", Sexp::keyword("k")),
("atom-string", Sexp::string("t")),
("atom-int", Sexp::int(7)),
("atom-float", Sexp::float(2.5)),
("atom-bool", Sexp::boolean(true)),
("empty list", Sexp::List(vec![])),
(
"non-empty list",
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
),
("quote", Sexp::Quote(Box::new(payload.clone()))),
("quasiquote", Sexp::Quasiquote(Box::new(payload.clone()))),
("unquote", Sexp::Unquote(Box::new(payload.clone()))),
(
"unquote-splice",
Sexp::UnquoteSplice(Box::new(payload.clone())),
),
];
for (label, sexp) in seeds {
let outer = sexp.prefix();
let via_shape = sexp.shape().prefix();
assert_eq!(
outer, via_shape,
"Sexp::prefix at {label} drifted from self.shape().prefix() — the four-layer typed reader-punctuation composition is broken",
);
}
}
#[test]
fn sexp_prefix_pins_canonical_reader_prefixes_for_every_quote_family_arm() {
// CANONICAL-PREFIX CONTRACT (outer-value peer): the outer-value
// `Sexp::prefix` MUST project each of the four homoiconic
// prefix-wrapper arms to the SAME canonical reader-punctuation
// string `crate::error::SexpShape::prefix` projects at the
// shape-level (and `crate::ast::QuoteForm::prefix` at the sub-
// carving level) — `Sexp::Quote → Some("'")`,
// `Sexp::Quasiquote → Some("`")`, `Sexp::Unquote → Some(",")`,
// `Sexp::UnquoteSplice → Some(",@")`. A regression that inlines
// a byte-drifted spelling here (e.g. `Sexp::UnquoteSplice →
// Some(", @")` inserting a spurious space, or `Sexp::Quote →
// Some("`")` swapping arms between Quote and Quasiquote)
// silently breaks the `Display for Sexp` round-trip against the
// reader's prefix dispatch. Sibling posture to
// `sexp_shape_prefix_pins_canonical_reader_prefixes_for_every_quote_family_arm`
// one algebra level down — that pin binds the shape-level
// projection's canonical reader-punctuation surface; this pin
// binds the outer-value projection's canonical reader-
// punctuation surface across the closed four-arm quote-family
// sweep on the outer `Sexp` algebra.
let inner = Sexp::symbol("payload");
assert_eq!(Sexp::Quote(Box::new(inner.clone())).prefix(), Some("'"),);
assert_eq!(
Sexp::Quasiquote(Box::new(inner.clone())).prefix(),
Some("`"),
);
assert_eq!(Sexp::Unquote(Box::new(inner.clone())).prefix(), Some(","),);
assert_eq!(Sexp::UnquoteSplice(Box::new(inner)).prefix(), Some(",@"),);
}
#[test]
fn sexp_prefix_returns_none_on_every_non_quote_family_variant() {
// PARTIAL-PROJECTION KERNEL CONTRACT (outer-value peer): every
// `Sexp` variant OUTSIDE the four-arm quote-family carving MUST
// project through `Sexp::prefix` to `None` — the three-arm
// outer kernel `{Nil, Atom, List}` (which corresponds to the
// eight-shape kernel at the shape-level projection through the
// six-atomic-arms → outer `Atom` collapse of `Self::shape`).
// Pin representative seeds for each kernel arm — `Nil`, one
// atom per `AtomKind`, one empty + one non-empty list — so a
// regression that surfaces a bogus prefix for a non-quote-
// family arm (e.g. `Sexp::List → Some("(")` conflating the
// outer-shape structural delimiter with the quote-family
// reader-punctuation) fails-loudly here. Sibling posture to
// `sexp_shape_prefix_returns_none_on_every_non_quote_family_shape`
// one algebra level down — that pin binds the shape-level
// projection's kernel; this pin binds the outer-value
// projection's kernel on the three-arm outer partition.
assert_eq!(Sexp::Nil.prefix(), None);
assert_eq!(Sexp::symbol("s").prefix(), None);
assert_eq!(Sexp::keyword("k").prefix(), None);
assert_eq!(Sexp::string("t").prefix(), None);
assert_eq!(Sexp::int(7).prefix(), None);
assert_eq!(Sexp::float(2.5).prefix(), None);
assert_eq!(Sexp::boolean(true).prefix(), None);
assert_eq!(Sexp::List(vec![]).prefix(), None);
assert_eq!(
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]).prefix(),
None,
);
}
#[test]
fn sexp_prefix_partitions_quote_family_and_kernel_disjointly() {
// IMAGE-PARTITION CONTRACT (outer-value peer): sweeping a
// representative seed per outer `Sexp` variant through
// `Sexp::prefix` MUST partition into EXACTLY the four-arm
// quote-family image (four distinct canonical reader-punctuation
// strings — the pre-image of `Some(_)`) AND the outer three-arm
// non-quote-family kernel (all `None` — `Nil` + one atom per
// `AtomKind` + one list). The image's `is_some()` count MUST be
// four (surjective onto the four-prefix closed set), the
// kernel's `is_none()` count MUST cover every non-quote-family
// seed, and the total sweep sums to the thirteen-seed
// representative sweep covering all seven outer variants (six
// `Atom` payloads + `Nil` + one `List` + four quote-family
// arms). A regression that leaks a bogus `Some(_)` from a non-
// quote-family arm or drops a `Some(_)` from a quote-family arm
// fails-loudly here on the partition-cardinality axis before
// any downstream reader-round-trip or Display consumer would
// surface the drift. Sibling posture to
// `sexp_shape_prefix_partitions_quote_family_and_kernel_disjointly`
// one algebra level down — that pin binds the shape-level
// image-partition on the twelve-shape closed sweep; this pin
// binds the outer-value image-partition on the representative
// outer-variant sweep.
let payload = Sexp::symbol("payload");
let seeds: Vec<Sexp> = vec![
Sexp::Nil,
Sexp::symbol("s"),
Sexp::keyword("k"),
Sexp::string("t"),
Sexp::int(7),
Sexp::float(2.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
Sexp::Quote(Box::new(payload.clone())),
Sexp::Quasiquote(Box::new(payload.clone())),
Sexp::Unquote(Box::new(payload.clone())),
Sexp::UnquoteSplice(Box::new(payload.clone())),
];
let prefix_image: std::collections::BTreeSet<&'static str> =
seeds.iter().filter_map(Sexp::prefix).collect();
let expected_prefix_image: std::collections::BTreeSet<&'static str> =
["'", "`", ",", ",@"].into_iter().collect();
assert_eq!(
prefix_image, expected_prefix_image,
"Sexp::prefix image must exactly cover the four canonical reader-punctuation quote-family prefixes",
);
let some_count = seeds.iter().filter(|sexp| sexp.prefix().is_some()).count();
assert_eq!(
some_count, 4,
"Sexp::prefix must return `Some(_)` on exactly the four-arm quote-family carving",
);
let none_count = seeds.iter().filter(|sexp| sexp.prefix().is_none()).count();
assert_eq!(
none_count,
seeds.len() - 4,
"Sexp::prefix must return `None` on every seed outside the four-arm quote-family carving",
);
assert_eq!(
some_count + none_count,
seeds.len(),
"Sexp::prefix's image + kernel must partition the representative outer-variant sweep exactly",
);
}
#[test]
fn display_for_sexp_renders_each_quote_family_variant_with_canonical_prefix() {
// Pin the post-lift Display rendering: every wrapper variant
// renders as `<prefix><inner>` with the prefix sourced from
// `QuoteForm::prefix`. A regression that drifts the prefix
// arm-routing (e.g. routes Quote through `` ` `` instead of
// `'`) fails loudly here. The literal `inner` rendering is
// the symbol `foo` so the prefix is the only diff between
// arms — pin path-uniformity across the closed set.
let inner = Sexp::symbol("foo");
assert_eq!(Sexp::Quote(Box::new(inner.clone())).to_string(), "'foo");
assert_eq!(
Sexp::Quasiquote(Box::new(inner.clone())).to_string(),
"`foo"
);
assert_eq!(Sexp::Unquote(Box::new(inner.clone())).to_string(), ",foo");
assert_eq!(Sexp::UnquoteSplice(Box::new(inner)).to_string(), ",@foo");
}
#[test]
fn display_for_sexp_round_trips_each_quote_family_variant_through_reader() {
// ROUND-TRIP CONTRACT: every wrapper variant's Display →
// reader path produces the matching `Sexp::*` variant. The
// reader's prefix-dispatch (in `reader::parse`) consumes the
// canonical `'` / `` ` `` / `,` / `,@` tokens and produces
// the corresponding wrapper; the Display impl emits the same
// tokens via `QuoteForm::prefix`. Pin the round-trip
// end-to-end so a regression that drifts the prefix on
// either side (Display or reader) fails loudly here. Sibling
// posture to `fmt_float_round_trips_integral_float_through
// _reader_as_float` — the Float round-trip pin at the
// Display→read boundary; this test pins the four
// quote-family round-trips at the same boundary.
let inner_body = Sexp::symbol("payload");
let quote = Sexp::Quote(Box::new(inner_body.clone()));
let forms = crate::reader::read("e.to_string()).expect("quote must round-trip");
assert_eq!(forms.len(), 1);
assert_eq!(forms[0], quote);
let quasiquote = Sexp::Quasiquote(Box::new(inner_body.clone()));
let forms =
crate::reader::read(&quasiquote.to_string()).expect("quasiquote must round-trip");
assert_eq!(forms.len(), 1);
assert_eq!(forms[0], quasiquote);
let unquote = Sexp::Unquote(Box::new(inner_body.clone()));
let forms = crate::reader::read(&unquote.to_string()).expect("unquote must round-trip");
assert_eq!(forms.len(), 1);
assert_eq!(forms[0], unquote);
let splice = Sexp::UnquoteSplice(Box::new(inner_body));
let forms =
crate::reader::read(&splice.to_string()).expect("unquote-splice must round-trip");
assert_eq!(forms.len(), 1);
assert_eq!(forms[0], splice);
}
#[test]
fn quote_form_wrap_projects_each_typed_marker_into_matching_sexp_wrapper() {
// CLOSED-SET CONSTRUCTOR CONTRACT: pin that `QuoteForm::wrap` is
// the structural inverse of `Sexp::as_quote_form` at the
// marker→wrapper boundary. Every variant of the closed-set
// `QuoteForm` algebra projects to its matching `Sexp::*` wrapper
// applied to the supplied inner — `Quote → Sexp::Quote`,
// `Quasiquote → Sexp::Quasiquote`, `Unquote → Sexp::Unquote`,
// `UnquoteSplice → Sexp::UnquoteSplice`. A regression that swaps
// two arms (e.g. `Self::Quote → Sexp::Quasiquote`) type-checks
// but silently corrupts every consumer that constructs a quote-
// family Sexp through the projection — fails loudly here.
// Sibling-arm sweep so the (marker, constructor) pair stays
// load-bearing under reordering refactors.
let inner = Sexp::symbol("payload");
assert_eq!(
QuoteForm::Quote.wrap(inner.clone()),
Sexp::Quote(Box::new(inner.clone()))
);
assert_eq!(
QuoteForm::Quasiquote.wrap(inner.clone()),
Sexp::Quasiquote(Box::new(inner.clone()))
);
assert_eq!(
QuoteForm::Unquote.wrap(inner.clone()),
Sexp::Unquote(Box::new(inner.clone()))
);
assert_eq!(
QuoteForm::UnquoteSplice.wrap(inner.clone()),
Sexp::UnquoteSplice(Box::new(inner))
);
}
#[test]
fn quote_form_wrap_round_trips_through_as_quote_form_for_every_variant() {
// ROUND-TRIP CONTRACT: pin the structural identity
// `qf.wrap(inner.clone()).as_quote_form() == Some((qf, &inner))`
// for every variant of the closed-set `QuoteForm` algebra. This
// is the canonical law binding the marker→wrapper projection
// (`wrap`) to its wrapper→marker dual (`as_quote_form`) on the
// substrate's `Sexp` algebra. A regression that drifts the
// (marker, constructor) pair on EITHER side — `wrap` routing
// `Quote` to `Sexp::Quasiquote`, OR `as_quote_form` routing
// `Sexp::Quote(_)` to `QuoteForm::Quasiquote` — surfaces as a
// round-trip mismatch here. Sweep all four variants so the
// round-trip stays load-bearing across the closed set. Same
// posture as the `display_for_sexp_round_trips_each_quote_family
// _variant_through_reader` round-trip pin at the Display→read
// boundary; this test pins the round-trip at the marker→Sexp
// projection boundary.
let inner_body = Sexp::symbol("payload");
for qf in [
QuoteForm::Quote,
QuoteForm::Quasiquote,
QuoteForm::Unquote,
QuoteForm::UnquoteSplice,
] {
let wrapped = qf.wrap(inner_body.clone());
let projected = wrapped
.as_quote_form()
.expect("wrap output must project back through as_quote_form");
assert_eq!(
projected.0, qf,
"wrap→as_quote_form drifted at marker for variant {qf:?}"
);
assert_eq!(
projected.1, &inner_body,
"wrap→as_quote_form drifted at inner body for variant {qf:?}"
);
}
}
#[test]
fn quote_form_all_is_unique_and_complete() {
// CLOSED-SET TRUTH-TABLE: pin that `QuoteForm::ALL` carries
// exactly the four reachable quote-family wrappers — no duplicates,
// byte-equal coverage of `{Quote, Quasiquote, Unquote, UnquoteSplice}`.
// The `[Self; 4]` array-literal arity already binds the count at
// compile time; this test pins the *identity* of each slot so a
// future re-ordering refactor (e.g. swapping `Unquote` and
// `UnquoteSplice` positions) that leaves the cardinality intact
// still fails loudly. Sibling discipline to
// `unquote_form_all_is_unique_and_complete` (the 2-of-4 subset
// sibling) and `atom_kind_all_is_unique_and_complete` (the peer
// atomic-payload axis).
//
// The `iter+map+collect+sort_unstable` quadruple this test inlined
// pre-lift now binds at `<QuoteForm as ClosedSet>::sorted_labels()`
// — the canonical-ordered candidate-list projection on the trait.
// Distinctness of the sorted result is covered by
// `assert_closed_set_well_formed::<QuoteForm>()` (the workspace-wide
// testkit), so this test reduces to the per-implementor unique
// payload (the four reader-punctuation literals in lexicographic
// order — the load-bearing per-enum ground truth the substrate-wide
// sort lift does NOT subsume).
assert_eq!(QuoteForm::ALL.len(), 4);
assert_eq!(
<QuoteForm as tatara_closed_set::ClosedSet>::sorted_labels(),
vec!["'", ",", ",@", "`"],
"QuoteForm::ALL must cover every reachable homoiconic prefix-wrapper"
);
}
#[test]
fn quote_form_display_matches_prefix_for_every_variant() {
// DISPLAY-EQUALS-PREFIX CONTRACT: pin that
// `<QuoteForm as fmt::Display>::fmt` projects through
// `QuoteForm::prefix` byte-for-byte for every variant in
// `QuoteForm::ALL`. The Display impl is the canonical rendering
// surface a future diagnostic annotation (`#[error("... {prefix}")]`
// shape) threads through; pinning the equality here means a
// regression that drifts EITHER the Display arm OR the `prefix`
// arm independently surfaces at this test rather than silently
// bifurcating the operator-facing rendered marker. Sibling
// discipline to `unquote_form_display_renders_canonical_marker_
// for_each_variant` (the 2-of-4 subset sibling) and
// `atom_kind_display_matches_label_for_every_variant` (the peer
// atomic-payload axis).
for qf in QuoteForm::ALL {
assert_eq!(
qf.to_string(),
qf.prefix(),
"Display rendering for {qf:?} diverged from prefix() projection"
);
}
}
#[test]
fn quote_form_prefix_round_trips_through_from_str() {
// BIDIRECTIONAL ROUND-TRIP: pin the structural identity
// `qf.prefix().parse() == Ok(qf)` for every variant in
// `QuoteForm::ALL`. This is the canonical law binding the
// marker→string projection (`prefix`) to its string→marker dual
// (`FromStr`). A regression that drifts EITHER side — `prefix`
// routing `Quote` to `` "`" ``, OR `FromStr` decoding `"'"` to
// `Quasiquote` — surfaces as a round-trip mismatch here. Sweep
// all four variants so the round-trip stays load-bearing across
// the closed set. Same posture as the
// `unquote_form_marker_round_trips_through_from_str` sibling on
// the 2-of-4 template-substitution subset axis and
// `atom_kind_label_round_trips_through_from_str` on the peer
// atomic-payload axis.
for qf in QuoteForm::ALL {
let prefix = qf.prefix();
let decoded: QuoteForm = prefix
.parse()
.expect("canonical prefix must decode through FromStr");
assert_eq!(
decoded, qf,
"FromStr ↔ prefix round-trip drifted for variant {qf:?} (prefix {prefix:?})"
);
}
}
#[test]
fn unknown_quote_form_carries_offending_input_verbatim() {
// TYPED PARSE-FAILURE CONTRACT: pin the exact rendered shape of
// `UnknownQuoteForm`'s `#[error(...)]` annotation AND the
// verbatim `.0` field projection — no normalization, no case-
// folding, no whitespace trimming. The error is part of the
// substrate-wide `Unknown*` parse-rejection family
// (`UnknownSexpShape`, `UnknownAtomKind`, `UnknownUnquoteForm`,
// `UnknownRequestorKind`, `UnknownReceiptKind`, `UnknownPhase`,
// `UnknownConditionKind`, `UnknownTeardownPolicy`, …) and the
// joint rendered shape (`"unknown <thing>: {0}"`) is the
// operator-facing diagnostic idiom every member preserves. A
// regression that case-folds, trims, or strips the offending
// input would silently rewrite an operator's literal value at
// the diagnostic boundary — fails loudly here.
let offending = "not-a-quote-prefix";
let err: UnknownQuoteForm = offending
.parse::<QuoteForm>()
.expect_err("non-canonical input must reject through FromStr");
assert_eq!(
err.0, offending,
"offending input was not preserved verbatim"
);
assert_eq!(
err.to_string(),
"unknown quote form: not-a-quote-prefix",
"Display rendering diverged from the substrate-wide Unknown* idiom"
);
}
#[test]
fn quote_form_is_well_formed_closed_set() {
// Structural contract: QuoteForm's four variants are pairwise
// distinct, round-trip through the trait's `label` ↔
// `parse_label`, and reject the empty string — the
// workspace-wide `assert_closed_set_well_formed::<T>()` testkit
// pinned across every `tatara-process` closed-set implementor
// (`AllocationPhase`, `RequestorKind`, `ProcessPhase`,
// `ConditionKind`, `WorkloadKind`, …). The substrate-level
// assertion runs on the auto-derived `impl ClosedSet for
// QuoteForm` emitted by `#[derive(tatara_closed_set::DeriveClosedSet)]`
// — a regression that drifts the derive's `make_unknown`
// delegation, the `via = "prefix"` projection
// (`"'" / "`" / "," / ",@"`), or the variant listing forced
// through `Self::ALL` fails-loudly here in isolation from the
// per-variant truth tables above.
tatara_closed_set::assert_closed_set_well_formed::<QuoteForm>();
}
#[test]
fn quote_form_from_str_rejects_sexp_shape_labels_on_homoiconic_prefix_axis() {
// CROSS-AXIS DISJOINTNESS: pin that `QuoteForm::FromStr` decodes
// the homoiconic punctuation markers `'` / `` ` `` / `,` / `,@`
// but rejects the `SexpShape` structural-identity vocabulary
// (`"quote"` / `"quasiquote"` / `"unquote"` / `"unquote-splice"`)
// AND the `iac_forge_tag` cross-crate canonical-form vocabulary
// (`"quote"` / `"quasiquote"` / `"unquote"` / `"unquote-splicing"`).
// The three closed sets project the SAME four `Sexp::*` quote-
// family constructors on DISTINCT axes — a regression that
// conflated them would let `"quote".parse::<QuoteForm>()` succeed
// (silently bifurcating the diagnostic surface) or
// `"'".parse::<SexpShape>()` succeed (silently colliding the
// punctuation and structural-identity vocabularies). Sibling
// discipline to `unquote_form_from_str_rejects_sexp_shape_labels_
// on_template_marker_axis` (the 2-of-4 subset's matching
// cross-axis pin).
use crate::error::SexpShape;
for shape in [
SexpShape::Quote,
SexpShape::Quasiquote,
SexpShape::Unquote,
SexpShape::UnquoteSplice,
] {
let label = shape.label();
assert!(
label.parse::<QuoteForm>().is_err(),
"SexpShape label {label:?} unexpectedly decoded through QuoteForm::FromStr — cross-axis vocabulary collision"
);
}
for qf in QuoteForm::ALL {
let tag = qf.iac_forge_tag();
assert!(
tag.parse::<QuoteForm>().is_err(),
"iac_forge_tag {tag:?} unexpectedly decoded through QuoteForm::FromStr — cross-axis vocabulary collision"
);
}
}
#[test]
fn quote_form_from_str_extends_unquote_form_from_str_on_the_2_of_4_subset() {
// SUBSET-CONTAINMENT CONTRACT: pin that every successful
// `UnquoteForm::FromStr` input is ALSO a successful
// `QuoteForm::FromStr` input, AND the resulting variants project
// to each other through `QuoteForm::as_unquote_form` (the 2-of-4
// subset gate). This binds the two homoiconic-prefix axes
// (`UnquoteForm`'s 2-of-2 template-substitution subset and
// `QuoteForm`'s full 4-of-4 quote-family) at the FromStr
// boundary: a regression that drifts EITHER FromStr's vocabulary
// from the other (e.g. `UnquoteForm::FromStr` adding a spelling
// `","` rejects in `QuoteForm::FromStr` would surface) fails
// loudly here. Composition law: for every `uf` in
// `UnquoteForm::ALL`, `uf.marker().parse::<QuoteForm>()` is
// `Ok(qf)` where `qf.as_unquote_form() == Some(uf)`.
use crate::error::UnquoteForm;
for uf in UnquoteForm::ALL {
let marker = uf.marker();
let qf: QuoteForm = marker.parse().unwrap_or_else(|_| {
panic!(
"UnquoteForm marker {marker:?} for {uf:?} did not decode through QuoteForm::FromStr — 2-of-4 subset containment violated"
)
});
assert_eq!(
qf.as_unquote_form(),
Some(uf),
"QuoteForm decoded from {marker:?} did not project back to UnquoteForm::{uf:?} via as_unquote_form"
);
}
}
#[test]
fn quote_form_wrap_derives_each_arm_to_its_pre_lift_box_new_form() {
// PATH-UNIFORMITY CONTRACT: pin that `QuoteForm::wrap` is
// observably equivalent to the pre-lift four-arm reader pattern
// `Sexp::<Variant>(Box::new(inner))` across every variant of the
// closed set. The reader's pre-lift parse arms each constructed
// their corresponding wrapper inline; post-lift the parse routes
// through `QuoteForm::wrap`. A regression that drifts the
// projection's allocation posture (e.g. wraps in an extra layer,
// or skips the `Box::new`) fails loudly here. Companion to the
// `wrap` projection test above — that test pins the (marker,
// constructor) pairing; this test pins the structural shape of
// each wrap output bit-for-bit against the pre-lift inline form.
let inner = Sexp::List(vec![Sexp::symbol("inner"), Sexp::int(7)]);
for (qf, expected) in [
(QuoteForm::Quote, Sexp::Quote(Box::new(inner.clone()))),
(
QuoteForm::Quasiquote,
Sexp::Quasiquote(Box::new(inner.clone())),
),
(QuoteForm::Unquote, Sexp::Unquote(Box::new(inner.clone()))),
(
QuoteForm::UnquoteSplice,
Sexp::UnquoteSplice(Box::new(inner.clone())),
),
] {
assert_eq!(
qf.wrap(inner.clone()),
expected,
"wrap drifted from pre-lift Sexp::<Variant>(Box::new(inner)) form for {qf:?}"
);
}
}
#[test]
fn fmt_float_leaves_int_display_unchanged() {
// Path-uniformity sibling: `Atom::Int` Display is unaffected by
// the `fmt_float` introduction — the helper is wired only into
// the `Atom::Float` arm of the Display match. A regression that
// accidentally routes `Atom::Int` through `fmt_float` would
// render `"1.0"` here and break every consumer that authored an
// int kwarg expecting the bare-integer rendering.
assert_eq!(Sexp::int(1).to_string(), "1");
assert_eq!(Sexp::int(0).to_string(), "0");
assert_eq!(Sexp::int(-42).to_string(), "-42");
}
// ── AtomKind + Atom::kind: closed-set atomic-payload projection ─────
//
// `AtomKind` is the closed-set typed discriminator for `Atom`'s six
// payload variants — `Symbol`, `Keyword`, `Str`, `Int`, `Float`,
// `Bool`. It is the atomic-payload peer of `QuoteForm` (the four
// homoiconic prefix wrappers), and the two closed sets together
// carve every non-Nil non-List arm of `SexpShape`'s twelve-variant
// closed set via their typed `sexp_shape` projections. Lifting the
// (Atom variant, byte-discriminator, canonical-label,
// SexpShape variant) quadruple onto ONE typed algebra collapses:
// - `Hash for Atom`'s six byte literals (0/1/2/3/4/5) onto
// `AtomKind::hash_discriminator` via `self.kind()` — ONE arm
// at the discriminator site;
// - `domain::sexp_shape`'s six `Atom::X(_) → SexpShape::X` arms
// onto `a.kind().sexp_shape()` — ONE arm at the projection
// site;
// - any future LSP / REPL / metric-aggregator consumer that
// needs to round-trip a rendered diagnostic label back into
// the typed discriminator onto `AtomKind::FromStr` — ONE
// decode site keyed on `AtomKind::ALL` + `AtomKind::label`.
//
// Tests below pin:
// (a) `Atom::kind` projects every Atom variant to its typed
// discriminator, regardless of inner payload contents;
// (b) `AtomKind::ALL` enumerates every variant EXACTLY ONCE;
// (c) `AtomKind::label` returns the canonical
// lowercase / kebab string for every variant — byte-for-byte
// identical to the corresponding `SexpShape::label`;
// (d) `Display for AtomKind` delegates to `label`;
// (e) `AtomKind::hash_discriminator` returns the same byte
// values the pre-lift `Hash for Atom` arms emitted
// (0/1/2/3/4/5) — pin the cache-key contract so a
// regression that drifts a discriminator silently
// invalidates every cached macro expansion fails loudly
// here;
// (f) `AtomKind::sexp_shape` projects every variant to the
// matching `SexpShape` — the typed pairing the
// `domain::sexp_shape` collapse relies on;
// (g) `AtomKind::FromStr` round-trips every variant through its
// label; rejects non-canonical capitalizations, empty input,
// and the non-atom `SexpShape` labels (`"nil"`, `"list"`,
// `"quote"`, `"quasiquote"`, `"unquote"`, `"unquote-splice"`);
// (h) `UnknownAtomKind` carries the offending input verbatim and
// renders the `#[error(...)]` annotation byte-exactly;
// (i) `Hash for Atom` produces byte-identical hashes for every
// atomic variant as the pre-lift implementation — pin the
// cache-key contract end-to-end so the post-lift routing
// through `AtomKind::hash_discriminator` cannot drift the
// cache;
// (j) the cross-projection composition law
// `crate::domain::sexp_shape(&Sexp::Atom(a)) ==
// a.kind().sexp_shape()` holds for every atomic kind.
#[test]
fn atom_kind_projects_each_atom_variant_to_typed_marker() {
// The structural identity `Atom::kind` establishes:
// `Symbol(_) → AtomKind::Symbol`, `Keyword(_) →
// AtomKind::Keyword`, etc. Pin every arm with a representative
// payload + an empty / boundary payload so a regression that
// matches on the payload rather than the variant identity
// (e.g. a typo that routes `Str("")` to a different marker
// than `Str("nonempty")`) surfaces immediately.
assert_eq!(Atom::Symbol("foo".into()).kind(), AtomKind::Symbol);
assert_eq!(Atom::Symbol(String::new()).kind(), AtomKind::Symbol);
assert_eq!(Atom::Keyword("k".into()).kind(), AtomKind::Keyword);
assert_eq!(Atom::Str("s".into()).kind(), AtomKind::Str);
assert_eq!(Atom::Str(String::new()).kind(), AtomKind::Str);
assert_eq!(Atom::Int(0).kind(), AtomKind::Int);
assert_eq!(Atom::Int(i64::MIN).kind(), AtomKind::Int);
assert_eq!(Atom::Int(i64::MAX).kind(), AtomKind::Int);
assert_eq!(Atom::Float(0.0).kind(), AtomKind::Float);
assert_eq!(Atom::Float(f64::NAN).kind(), AtomKind::Float);
assert_eq!(Atom::Float(f64::INFINITY).kind(), AtomKind::Float);
assert_eq!(Atom::Bool(true).kind(), AtomKind::Bool);
assert_eq!(Atom::Bool(false).kind(), AtomKind::Bool);
}
#[test]
fn atom_kind_all_is_unique_and_complete() {
// Closed-set posture: `ALL` enumerates every reachable variant
// EXACTLY ONCE — no duplicates, no omissions. The `[Self; 6]`
// array literal in the declaration forces the arity at compile
// time; this test catches the orthogonal failure modes — a
// future variant added at the type without being added to ALL
// (silently dropped from every consumer's sweep), or a typo
// that duplicates an entry (silently double-counted). Same
// truth-table pinning every sibling closed-set lift in the
// workspace uses (`SexpShape::ALL`, `RequestorKind::ALL`,
// `ReceiptKind::ALL`, `ConditionKind::ALL`, `ProcessPhase::ALL`,
// `ChannelKind::ALL`, …).
//
// The `iter+map+collect+sort_unstable` quadruple this test inlined
// pre-lift now binds at `<AtomKind as ClosedSet>::sorted_labels()`
// — the canonical-ordered candidate-list projection on the trait.
// Distinctness of the sorted result is covered by
// `assert_closed_set_well_formed::<AtomKind>()`, so this test
// reduces to the per-implementor unique payload (the six diagnostic
// labels in lexicographic order).
assert_eq!(AtomKind::ALL.len(), 6);
assert_eq!(
<AtomKind as tatara_closed_set::ClosedSet>::sorted_labels(),
vec!["bool", "float", "int", "keyword", "string", "symbol"],
"AtomKind::ALL must cover every reachable Atom payload kind"
);
}
#[test]
fn atom_kind_label_renders_canonical_string_for_every_variant() {
// Pin every variant's canonical `&'static str` projection — a
// regression that drifts any label (typo `"sym"` for
// `"symbol"`, swap of `"int"` ↔ `"float"`, capitalization
// drift `"String"` for `"string"`, or the `Str → "string"`
// boundary rename being reversed to a literal `"str"`) fails-
// loudly here. The six labels are byte-for-byte identical to
// the corresponding `SexpShape::label` arms so the typed
// diagnostic vocabulary stays unified across the AtomKind ⊂
// SexpShape containment.
assert_eq!(AtomKind::Symbol.label(), "symbol");
assert_eq!(AtomKind::Keyword.label(), "keyword");
assert_eq!(AtomKind::Str.label(), "string");
assert_eq!(AtomKind::Int.label(), "int");
assert_eq!(AtomKind::Float.label(), "float");
assert_eq!(AtomKind::Bool.label(), "bool");
}
#[test]
fn atom_kind_label_agrees_with_sexp_shape_label_for_every_atom_arm() {
// CROSS-PROJECTION VOCABULARY CONTRACT: each `AtomKind`
// variant's `label()` is byte-for-byte identical to the
// corresponding `SexpShape` variant's `label()` (after the
// `Str → String` typed-variant rename which is intentional
// — the wire vocabulary is `"string"` on both axes). Pin the
// six-way agreement so a future label rename on EITHER side
// (a SexpShape `"string"` → `"str"` drift, or an AtomKind
// `"int"` → `"i64"` drift) fails-loudly here, NOT silently
// at every cross-axis consumer. The pairing is load-bearing
// for the typed-projection composition
// `AtomKind::sexp_shape().label() == AtomKind::label()`.
//
// Post-lift this contract is structurally true by composition
// (`AtomKind::label`'s body IS `self.sexp_shape().label()`),
// so the cross-axis sweep is a tautology — the regression
// surface lives at `SexpShape::label`'s atomic arms now,
// pinned by `atom_kind_label_renders_canonical_string_for_every_variant`
// (which keys the same six literals through the composition).
// The sweep stays in place as a structural invariant pin in
// case a future implementor reverses the lift and re-inlines
// the per-variant arms here — drift between the two sites
// would re-emerge and this test catches it.
for kind in AtomKind::ALL {
assert_eq!(
kind.label(),
kind.sexp_shape().label(),
"label vocabulary drift between AtomKind::{kind:?} \
and its SexpShape projection",
);
}
}
#[test]
fn atom_kind_label_routes_through_sexp_shape_label_via_sexp_shape_projection() {
// ROUTING-PIN CONTRACT: post-lift `AtomKind::label`'s body
// composes `Self::sexp_shape()` with `SexpShape::label()`
// verbatim — no inline per-arm literal table. The composition
// law `AtomKind::label(k) == AtomKind::sexp_shape(k).label()`
// is structurally true for every `k: AtomKind`; pinning the
// routing means a regression that re-inlines the six atomic-
// arm literals here surfaces as a drift between the inline
// copy and the `SexpShape::label` canonical site rather than
// surviving silently.
//
// Six representative cases — one per variant — walked through
// the composition manually and through the direct projection,
// then byte-compared. A drift in EITHER half of the composition
// (a typo in `Self::sexp_shape`'s match arms swapping
// `Self::Int → SexpShape::Float`, OR a typo in `SexpShape::label`
// dropping the `Int → "int"` arm) fails this assertion AND every
// sibling per-arm assertion in
// `atom_kind_label_renders_canonical_string_for_every_variant`
// — but THIS test names the routing axis explicitly so a
// regression to inline-literal-arms shows up as a failure of
// the routing pin alongside the per-arm pin.
//
// Sibling-lift posture to the prior-run routing pins:
// `sexp_to_json_object_arm_routes_through_is_kwargs_list_method`
// (commit 4a11f5b) pins `Sexp::to_json`'s kwargs gate through
// the lifted predicate. This pin extends the same posture to
// `AtomKind::label`'s structural routing through the
// `Self::sexp_shape() ∘ SexpShape::label` composition.
//
// Theory anchor: THEORY.md §V.1 — knowable platform; the
// label-projection routing is a NAMED structural contract
// pinned alongside the per-arm vocabulary contract, so
// operators reading the test surface see BOTH the load-bearing
// identity AND the load-bearing composition. THEORY.md §VI.1
// — generation over composition; the label projection emerges
// from the typed pairing rather than per-arm literal discipline,
// and the routing pin enforces the lift stays in effect.
for kind in AtomKind::ALL {
let via_label = kind.label();
let via_composition = kind.sexp_shape().label();
assert_eq!(
via_label, via_composition,
"AtomKind::{kind:?}::label() must route through \
Self::sexp_shape().label() — drift here means the \
lift was reverted to inline arms",
);
// The pointer-equality check pins the composition produces
// the SAME `&'static str` (not just a byte-equal copy) for
// every variant — proof the routing hits ONE static literal
// site (`SexpShape::label`) rather than a parallel inline
// table.
assert!(
std::ptr::eq(via_label.as_ptr(), via_composition.as_ptr()),
"AtomKind::{kind:?}::label() must return the SAME \
`&'static str` as Self::sexp_shape().label() — \
pointer drift means the lift composes through a \
parallel literal table rather than routing into the \
canonical SexpShape::label site",
);
}
}
#[test]
fn atom_kind_display_matches_label_for_every_variant() {
// Pin Display-equals-label: any future
// `#[error("... got {got}")]` annotation that threads through
// this projection projects through Display, and Display
// delegates to `label()`. A regression that introduces a
// Display impl that deviates from `label()` (e.g. capitalizing
// one variant) would drift any future diagnostic surface;
// this test pins the contract. Sibling posture to
// `sexp_shape_display_matches_label_for_every_variant` in
// `error.rs`.
assert_eq!(format!("{}", AtomKind::Symbol), "symbol");
assert_eq!(format!("{}", AtomKind::Keyword), "keyword");
assert_eq!(format!("{}", AtomKind::Str), "string");
assert_eq!(format!("{}", AtomKind::Int), "int");
assert_eq!(format!("{}", AtomKind::Float), "float");
assert_eq!(format!("{}", AtomKind::Bool), "bool");
}
#[test]
fn atom_kind_hash_discriminator_pins_legacy_atom_cache_key_bytes() {
// CACHE-KEY CONTRACT: pre-lift `Hash for Atom` used the literal
// byte values 0/1/2/3/4/5 for Symbol/Keyword/Str/Int/Float/Bool
// as the per-variant discriminator. The macro-expansion cache
// (`Expander::cache`) keys on Hash; ANY change to a
// discriminator byte silently invalidates every cached
// expansion across the substrate. Pin the six legacy values
// explicitly so a regression that re-numbers them surfaces
// immediately — the `AtomKind` algebra MUST preserve the prior
// byte mapping bit-for-bit. Sibling posture to
// `quote_form_hash_discriminator_pins_legacy_cache_key_bytes`
// on the quote-family axis.
assert_eq!(AtomKind::Symbol.hash_discriminator(), 0);
assert_eq!(AtomKind::Keyword.hash_discriminator(), 1);
assert_eq!(AtomKind::Str.hash_discriminator(), 2);
assert_eq!(AtomKind::Int.hash_discriminator(), 3);
assert_eq!(AtomKind::Float.hash_discriminator(), 4);
assert_eq!(AtomKind::Bool.hash_discriminator(), 5);
}
#[test]
fn atom_kind_hash_discriminator_bytes_are_pairwise_disjoint() {
// Closed-set injectivity: the six discriminator bytes must
// partition `{0, 1, 2, 3, 4, 5}` injectively so two distinct
// `Atom` variants never produce the SAME hash discriminator —
// a violation here means the cache could conflate two atomic
// kinds with identical payloads (`Symbol("x")` and `Str("x")`
// would silently share a cache slot). Sibling pin to
// `atom_kind_all_is_unique_and_complete` on the label axis.
let bytes: Vec<u8> = AtomKind::ALL
.iter()
.map(|k| k.hash_discriminator())
.collect();
let mut sorted = bytes.clone();
sorted.sort_unstable();
let mut deduped = sorted.clone();
deduped.dedup();
assert_eq!(
sorted, deduped,
"AtomKind hash discriminator bytes must be pairwise disjoint"
);
assert_eq!(sorted, vec![0, 1, 2, 3, 4, 5]);
}
// ── `AtomKind::{SYMBOL_HASH_DISCRIMINATOR,
// KEYWORD_HASH_DISCRIMINATOR, STR_HASH_DISCRIMINATOR,
// INT_HASH_DISCRIMINATOR, FLOAT_HASH_DISCRIMINATOR,
// BOOL_HASH_DISCRIMINATOR, HASH_DISCRIMINATORS}` — per-role `u8`
// cache-key byte algebra on the closed-set atomic-payload
// [`AtomKind`]. Second per-role axis on the algebra alongside the
// diagnostic-label (commit fc126b8) `&'static str` axis — direct
// sibling of the prior-run
// [`crate::error::QuoteForm::HASH_DISCRIMINATORS`] lift (commit
// cb9b026) on the quote-family sub-carving of the same outer-Sexp
// Hash body.
//
// The two families partition their respective cache-key spaces
// independently: `AtomKind` at `{0..=5}` NESTED inside
// `Sexp::Atom`'s outer `1u8` byte (`Hash for Atom` runs on the
// `Atom` type, not `Sexp`), `QuoteForm` at `{3..=6}` at the outer
// `Sexp` cache-key space itself. Post-lift ALL FOUR closed-set
// carvings that participate in `Hash for Sexp` / `Hash for Atom`
// (`AtomKind` here, `QuoteForm` prior-run, `StructuralKind` still
// inline `{0, 2}`, outer-`SexpShape` composed through the three
// carvings) name their canonical bytes on the typed algebra rather
// than at scattered inline literals.
#[test]
fn atom_kind_hash_discriminators_pin_legacy_cache_key_bytes() {
// Pin each per-role `pub(crate) const` at its exact canonical
// `u8` byte. Sibling of
// `atom_kind_hash_discriminator_pins_legacy_atom_cache_key_bytes`
// (which pins the method's projection) — this pin asserts the
// `pub(crate) const` value itself, so a regression that drifts
// the constant but leaves the method's arm literal in place
// (unlikely post-lift but structurally distinct) surfaces here.
// The cache-key partition `{0..=5}` is load-bearing for
// `Hash for Atom`'s injectivity contract — a `2u8` drift to
// `0u8` would silently collide `AtomKind::Str` with
// `AtomKind::Symbol`'s cache-key byte and mis-hash every
// `Str(x)` through the `Symbol(x)` arm's cache slot.
assert_eq!(AtomKind::SYMBOL_HASH_DISCRIMINATOR, 0);
assert_eq!(AtomKind::KEYWORD_HASH_DISCRIMINATOR, 1);
assert_eq!(AtomKind::STR_HASH_DISCRIMINATOR, 2);
assert_eq!(AtomKind::INT_HASH_DISCRIMINATOR, 3);
assert_eq!(AtomKind::FLOAT_HASH_DISCRIMINATOR, 4);
assert_eq!(AtomKind::BOOL_HASH_DISCRIMINATOR, 5);
}
#[test]
fn atom_kind_hash_discriminator_routes_through_typed_per_role_constants() {
// PATH-UNIFORMITY: `Self::hash_discriminator(self)` returns the
// per-role `pub(crate) const` byte-for-byte per variant,
// catching a regression that reverts ONE arm to an inline
// `0` / `1` / `2` / `3` / `4` / `5` `u8` literal (or drifts one
// arm's byte silently). Sibling posture to
// `quote_form_hash_discriminator_routes_through_typed_per_role_constants`
// on the quote-family sub-carving of the SAME outer-Sexp Hash
// body.
for (kind, expected) in [
(AtomKind::Symbol, AtomKind::SYMBOL_HASH_DISCRIMINATOR),
(AtomKind::Keyword, AtomKind::KEYWORD_HASH_DISCRIMINATOR),
(AtomKind::Str, AtomKind::STR_HASH_DISCRIMINATOR),
(AtomKind::Int, AtomKind::INT_HASH_DISCRIMINATOR),
(AtomKind::Float, AtomKind::FLOAT_HASH_DISCRIMINATOR),
(AtomKind::Bool, AtomKind::BOOL_HASH_DISCRIMINATOR),
] {
let actual = kind.hash_discriminator();
assert_eq!(
actual, expected,
"AtomKind::{kind:?}.hash_discriminator() `{actual}` \
drifted from per-role constant `{expected}` — the \
arm must route through the typed `pub(crate) const` \
rather than an inline `u8` literal",
);
}
}
#[test]
fn atom_kind_hash_discriminators_has_expected_cardinality() {
// Cardinality contract: `Self::HASH_DISCRIMINATORS.len() == 6`
// — pinned at the declaration site by rustc's forced-arity
// check on `[u8; 6]`. This test surfaces the arity as a
// fail-loud runtime pin so a future refactor that switches the
// array type to `&[u8]` (dropping the compile-time arity
// forcing) doesn't silently loosen the closed-set discipline
// the family relies on. Sibling posture to
// `atom_kind_labels_has_expected_cardinality` on the diagnostic
// label axis of the SAME closed set, and to
// `quote_form_hash_discriminators_has_expected_cardinality`
// on the quote-family sub-carving's cache-key-byte peer.
assert_eq!(
AtomKind::HASH_DISCRIMINATORS.len(),
6,
"AtomKind::HASH_DISCRIMINATORS cardinality drifted from 6 \
— the closed atomic-payload domain admits exactly six \
kinds by construction; a seventh extension surfaces here"
);
}
#[test]
fn atom_kind_hash_discriminators_align_with_all_by_index() {
// ALIGNMENT CONTRACT: `Self::HASH_DISCRIMINATORS[i] ==
// Self::ALL[i].hash_discriminator()` element-wise. Pins that
// the typed variant ALL and the `u8` HASH_DISCRIMINATORS ALL
// stay in lockstep under any reorder — a regression that
// reorders ONE array without reordering the other silently
// misaligns every `zip(ALL, HASH_DISCRIMINATORS)` consumer.
// Sibling posture to `atom_kind_labels_align_with_all_by_index`
// on the diagnostic label axis of the SAME closed set.
for (i, kind) in AtomKind::ALL.iter().enumerate() {
assert_eq!(
AtomKind::HASH_DISCRIMINATORS[i],
kind.hash_discriminator(),
"AtomKind::HASH_DISCRIMINATORS[{i}] `{disc}` drifted \
from AtomKind::ALL[{i}] ({kind:?}).hash_discriminator() \
`{via_variant}` — the canonical declaration order of \
the ALL array and the hash_discriminator projection \
must match element-wise",
disc = AtomKind::HASH_DISCRIMINATORS[i],
via_variant = kind.hash_discriminator(),
);
}
}
#[test]
fn atom_kind_hash_discriminators_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every entry of the
// `HASH_DISCRIMINATORS` array must differ so the nested `Atom`
// Hash body cannot route two atomic-payload variants through
// the same cache-key byte — a collision would silently mis-
// hash two structurally-distinct atoms (`Symbol("x")` and
// `Str("x")`) to the same `Expander::cache` slot. Family-wide
// sweep over `HASH_DISCRIMINATORS × HASH_DISCRIMINATORS` —
// supersedes any per-pair pin and picks up new discriminators
// mechanically. Sibling posture to
// `atom_kind_hash_discriminator_bytes_are_pairwise_disjoint`
// (which sweeps via the projection) — this sweep pins the array
// itself so a regression that lifts a fresh entry with a
// colliding byte surfaces at the ALL sweep.
for (i, a) in AtomKind::HASH_DISCRIMINATORS.iter().enumerate() {
for (j, b) in AtomKind::HASH_DISCRIMINATORS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"AtomKind::HASH_DISCRIMINATORS[{i}] `{a}` collides \
with AtomKind::HASH_DISCRIMINATORS[{j}] `{b}` — \
the nested Atom Hash body's cache-key partition \
would route two atomic-payload variants through \
the same slot"
);
}
}
}
#[test]
fn atom_kind_outer_hash_discriminator_pins_legacy_atomic_carve_outer_marker_byte() {
// Pin `AtomKind::OUTER_HASH_DISCRIMINATOR` at its exact canonical
// `u8` byte — the outer-Sexp cache-key byte at which ALL SIX
// atomic-payload shapes collapse when hashed at the outer
// `Hash for Sexp` level. Pre-lift the same byte lived at four
// sites: the inline `1u8` literal at
// `SexpShape::hash_discriminator`'s six-arm atomic collapse (in
// error.rs), the inline `1u8` literal at
// `sexp_shape_hash_discriminator_atomic_arms_collapse_to_outer_atom_marker`'s
// assertion body, the inline `1u8` literal at
// `sexp_shape_hash_discriminator_partitions_by_three_way_carving_disjointly`'s
// `expected_atomic` fixture, PLUS a duplicated local `const
// ATOM_OUTER_CARVE_BYTE: u8 = 1` inside
// `structural_kind_hash_discriminator_disjoint_from_atom_outer_carve_byte_and_quote_form_hash_discriminator_partition`.
// Post-lift the byte binds at ONE `pub(crate) const` on the
// closed-set `AtomKind` algebra; every downstream consumer
// (the shape-level projection's atomic collapse arm, the two
// three-way carving pins in error.rs, the joint-partition
// disjointness pin in error.rs, a future `tatara-check`
// predicate on the outer-Sexp cache-key partition) picks up
// the same canonical byte from ONE source of truth. Sibling
// posture to `atom_kind_hash_discriminators_pin_legacy_cache_key_bytes`
// (which pins the six NESTED INNER `{0..=5}` bytes on the
// per-atom-kind inner algebra) — this pin closes the (nested,
// outer) pairing on the same `AtomKind` algebra by naming the
// outer-Sexp marker byte alongside the nested inner carve.
// The cache-key partition is load-bearing for the outer
// `Hash for Sexp` prefix-uniqueness contract — a `1u8` drift
// to `0u8` would silently collide the atomic-carve outer
// marker with `StructuralKind::Nil`'s outer byte (`0`) and
// mis-hash every `Sexp::Atom(_)` through the `Sexp::Nil`
// arm's cache slot; a drift to `2u8` would collide with
// `StructuralKind::List`'s outer byte and mis-hash through
// the `Sexp::List(_)` arm's slot; a drift to `3u8` /
// `4u8` / `5u8` / `6u8` would collide with the quote-family
// carve's four bytes.
assert_eq!(AtomKind::OUTER_HASH_DISCRIMINATOR, 1);
}
#[test]
fn atom_kind_outer_hash_discriminator_disjoint_from_inner_hash_discriminators_at_outer_sexp_level(
) {
// OUTER-vs-INNER SEPARATION: the outer-Sexp cache-key algebra
// uses TWO distinct byte spaces at TWO hash-sequence positions
// for the atomic-carve: `AtomKind::OUTER_HASH_DISCRIMINATOR`
// (`1u8` at the outer `Hash for Sexp` position) AND the
// NESTED INNER `AtomKind::HASH_DISCRIMINATORS` bytes (`{0..=5}`
// at the inner `Hash for Atom` position). The two byte spaces
// OVERLAP numerically (both contain `1u8`) but do NOT collide
// at the cache because they live at DIFFERENT hash-sequence
// positions in the composed `(outer_discriminator,
// inner_discriminator, inner_payload)` triple. Pin the outer
// scalar's byte at `AtomKind::OUTER_HASH_DISCRIMINATOR` and
// the inner set at `AtomKind::HASH_DISCRIMINATORS` so a future
// refactor that conflates the two axes (e.g. drops the outer
// marker byte at `Hash for Sexp`'s Atom arm and expects the
// inner byte to distinguish outer-Sexp variants directly)
// surfaces at THIS test as a documentation-of-intent failure.
// The check is intentionally structural: it asserts the outer
// scalar is IN the same numeric range as the inner set (both
// are `u8`, both live within `{0..=6}` on the outer cache-key
// partition) BUT that the outer scalar sits at position 1
// where the inner byte space would otherwise have
// `AtomKind::KEYWORD_HASH_DISCRIMINATOR` collide. That
// numeric-collision without cache-collision is the
// load-bearing property this lift documents: the two axes are
// typed distinct because they live at typed distinct
// positions in the composed hash sequence, even though their
// byte spaces overlap.
assert!(
AtomKind::HASH_DISCRIMINATORS.contains(&AtomKind::OUTER_HASH_DISCRIMINATOR),
"the outer-carve marker byte `{outer}` MUST lie within the \
inner cache-key partition `{inner:?}` — the two axes' \
byte spaces overlap by design (the outer distinguishes \
`Sexp::Atom(_)` from every other outer-Sexp variant at \
the outer hash position; the inner distinguishes the six \
atomic-payload variants at the nested inner hash \
position). If this contains check fails, the outer \
scalar has drifted OUTSIDE the inner partition and the \
(outer, inner) numeric-overlap-without-cache-collision \
property this lift documents no longer holds — which \
would in turn mean either the outer byte drifted out of \
`{{0..=5}}` (compile the substrate against the resulting \
outer-Sexp partition to find the drift) or the inner \
partition shrank below `{{0..=5}}` (`atom_kind_hash_discriminators_align_with_all_by_index` \
fails-loudly first).",
outer = AtomKind::OUTER_HASH_DISCRIMINATOR,
inner = AtomKind::HASH_DISCRIMINATORS,
);
}
#[test]
fn atom_kind_sexp_shape_pins_canonical_shape_identity_for_every_variant() {
// CLOSED-SET SHAPE-PROJECTION CONTRACT: each `AtomKind` variant
// projects to its matching `SexpShape` variant — load-bearing
// for the (Atom variant, SexpShape variant) pairing the
// substrate's outer-shape projection `domain::sexp_shape` routes
// through. Sibling-arm sweep so the six pairings stay
// load-bearing under reordering refactors. A regression that
// drifts ONE arm (e.g. routes `AtomKind::Int` to
// `SexpShape::Float`) surfaces here immediately rather than as
// a silent operator-facing diagnostic drift at every
// `LispError::TypeMismatch.got` slot for an atomic witness.
// Sibling posture to
// `quote_form_sexp_shape_pins_canonical_shape_identity_for_every_variant`.
assert_eq!(AtomKind::Symbol.sexp_shape(), SexpShape::Symbol);
assert_eq!(AtomKind::Keyword.sexp_shape(), SexpShape::Keyword);
assert_eq!(AtomKind::Str.sexp_shape(), SexpShape::String);
assert_eq!(AtomKind::Int.sexp_shape(), SexpShape::Int);
assert_eq!(AtomKind::Float.sexp_shape(), SexpShape::Float);
assert_eq!(AtomKind::Bool.sexp_shape(), SexpShape::Bool);
}
#[test]
fn atom_kind_per_role_shapes_pin_canonical_sexp_shape_variants() {
// PER-ROLE ALIAS CONTRACT: each `AtomKind::*_SHAPE` per-role
// `pub const` binds byte-for-byte to its canonical `SexpShape`
// variant on the AtomKind ⊂ SexpShape carving. Pin so a
// regression that swaps ONE alias (e.g. re-aims `STR_SHAPE`
// at `SexpShape::Symbol`) surfaces at rustc / test time
// rather than as a silent operator-facing diagnostic drift at
// every consumer keyed on the typed embed target. Sibling
// posture to `atom_kind_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte`
// on the diagnostic label axis of the SAME closed set — this
// pin is the peer on the `SexpShape` embed-target axis.
assert_eq!(AtomKind::SYMBOL_SHAPE, SexpShape::Symbol);
assert_eq!(AtomKind::KEYWORD_SHAPE, SexpShape::Keyword);
assert_eq!(AtomKind::STR_SHAPE, SexpShape::String);
assert_eq!(AtomKind::INT_SHAPE, SexpShape::Int);
assert_eq!(AtomKind::FLOAT_SHAPE, SexpShape::Float);
assert_eq!(AtomKind::BOOL_SHAPE, SexpShape::Bool);
}
#[test]
fn atom_kind_shapes_has_expected_cardinality() {
// CLOSED-SET CARDINALITY CONTRACT: `AtomKind::SHAPES` carries
// exactly SIX entries — one per variant in the closed-set
// atomic-payload carving. Runtime companion to the `[SexpShape;
// 6]` type annotation's compile-time forced arity. A regression
// that widens the array without adding a matching per-role
// `*_SHAPE` alias would fail the `[SexpShape; 6]` type check
// at rustc time; this runtime pin catches a silent shrink or
// duplicate-arm coalesce. Sibling posture to
// `atom_kind_labels_has_expected_cardinality` and
// `atom_kind_hash_discriminators_has_expected_cardinality` on
// the other two per-role axes of the SAME closed set.
assert_eq!(AtomKind::SHAPES.len(), 6);
assert_eq!(AtomKind::SHAPES.len(), AtomKind::ALL.len());
}
#[test]
fn atom_kind_shapes_align_with_all_by_index() {
// ALIGNMENT CONTRACT: `Self::SHAPES[i] ==
// Self::ALL[i].sexp_shape()` element-wise. Pins that the typed
// variant ALL and the `SexpShape` SHAPES ALL stay in lockstep
// under any reorder — a regression that reorders ONE array
// without reordering the other silently misaligns every
// `zip(ALL, SHAPES)` consumer that wants to project each
// atomic variant to its canonical outer-shape identity
// (LSP completion, `tatara-check` predicate over the
// atomic ⊂ outer partition, Sekiban audit-trail metric
// jointly labeled by the embed target). Sibling posture to
// `atom_kind_labels_align_with_all_by_index` and
// `atom_kind_hash_discriminators_align_with_all_by_index` on
// the other two per-role axes of the SAME closed set.
for (i, kind) in AtomKind::ALL.iter().enumerate() {
assert_eq!(
AtomKind::SHAPES[i],
kind.sexp_shape(),
"AtomKind::SHAPES[{i}] `{shape:?}` drifted from \
AtomKind::ALL[{i}] ({kind:?}).sexp_shape() \
`{via_variant:?}` — the canonical declaration order \
of the ALL array and the sexp_shape projection must \
match element-wise",
shape = AtomKind::SHAPES[i],
via_variant = kind.sexp_shape(),
);
}
}
#[test]
fn atom_kind_shapes_align_with_all_by_index_through_as_atom_kind() {
// ROUND-TRIP CONTRACT: `Self::SHAPES[i].as_atom_kind() ==
// Some(Self::ALL[i])` element-wise. Pins the embed / project
// section of the (`AtomKind::sexp_shape`,
// `SexpShape::as_atom_kind`) `Iso(AtomKind, AtomShape ⊂
// SexpShape)` as a family-wide array-indexed law rather than
// as a per-variant assertion sweep. A regression that drifts
// EITHER the `SHAPES` array entries OR the peer inverse
// `as_atom_kind` arms silently breaks the (embed, project)
// section — this pin catches both directions at ONCE.
// Sibling posture to the pre-existing per-variant round-trip
// sweep `atom_kind_sexp_shape_round_trips_through_sexp_shape_as_atom_kind`
// (which sweeps through the projection method); this sweep
// pins the round-trip through the SHAPES array directly so a
// regression on ANY of the three surfaces (per-role alias,
// family-wide array, projection method) fails-loudly at the
// array-indexed sweep.
for (i, kind) in AtomKind::ALL.iter().enumerate() {
assert_eq!(
AtomKind::SHAPES[i].as_atom_kind(),
Some(*kind),
"AtomKind::SHAPES[{i}] `{shape:?}`.as_atom_kind() = \
{actual:?} drifted from Some(AtomKind::ALL[{i}]) = \
Some({expected:?}) — the (SHAPES entry, ALL variant) \
round-trip through the peer inverse SexpShape::as_atom_kind \
must hold element-wise",
shape = AtomKind::SHAPES[i],
actual = AtomKind::SHAPES[i].as_atom_kind(),
expected = kind,
);
}
}
#[test]
fn atom_kind_sexp_shape_routes_through_typed_per_role_constants() {
// ROUTING CONTRACT: `AtomKind::sexp_shape()`'s six arms bind
// through the per-role `pub const *_SHAPE` aliases rather
// than through inline `SexpShape::X` literals. Pin so a
// regression that re-inlines the six literals here (and
// gains its own drift surface separate from the canonical
// per-role alias site) surfaces immediately at variant
// equality. Sibling posture to
// `atom_kind_label_arms_route_through_per_role_labels_for_every_variant`
// and `atom_kind_hash_discriminator_routes_through_typed_per_role_constants`
// on the other two per-role axes of the SAME closed set.
assert_eq!(AtomKind::Symbol.sexp_shape(), AtomKind::SYMBOL_SHAPE);
assert_eq!(AtomKind::Keyword.sexp_shape(), AtomKind::KEYWORD_SHAPE);
assert_eq!(AtomKind::Str.sexp_shape(), AtomKind::STR_SHAPE);
assert_eq!(AtomKind::Int.sexp_shape(), AtomKind::INT_SHAPE);
assert_eq!(AtomKind::Float.sexp_shape(), AtomKind::FLOAT_SHAPE);
assert_eq!(AtomKind::Bool.sexp_shape(), AtomKind::BOOL_SHAPE);
}
#[test]
fn atom_kind_shapes_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every entry of the `SHAPES` array
// must differ so the (AtomKind variant, SexpShape embed
// target) mapping stays injective — a collision would silently
// route two distinct AtomKind variants through the SAME
// outer-shape identity, breaking the AtomKind ⊂ SexpShape
// 6-of-12 carving. Family-wide sweep over `SHAPES × SHAPES` —
// supersedes any per-pair pin and picks up new embed targets
// mechanically. Sibling posture to
// `atom_kind_labels_pairwise_distinct` and
// `atom_kind_hash_discriminators_pairwise_distinct` on the
// other two per-role axes of the SAME closed set.
for (i, a) in AtomKind::SHAPES.iter().enumerate() {
for (j, b) in AtomKind::SHAPES.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"AtomKind::SHAPES[{i}] `{a:?}` collides with \
AtomKind::SHAPES[{j}] `{b:?}` — the AtomKind ⊂ \
SexpShape 6-of-12 carving would route two atomic \
variants through the same outer-shape identity"
);
}
}
}
#[test]
fn quote_form_per_role_shapes_pin_canonical_sexp_shape_variants() {
// PER-ROLE ALIAS CONTRACT: each `QuoteForm::*_SHAPE` per-role
// `pub const` binds byte-for-byte to its canonical `SexpShape`
// variant on the QuoteForm ⊂ SexpShape 4-of-12 carving. Pin
// so a regression that swaps ONE alias (e.g. re-aims
// `UNQUOTE_SPLICE_SHAPE` at `SexpShape::Unquote`) surfaces at
// rustc / test time rather than as a silent operator-facing
// diagnostic drift at every consumer keyed on the typed embed
// target. Sibling posture to
// `quote_form_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte`
// on the diagnostic label axis of the SAME closed set — this
// pin is the peer on the `SexpShape` embed-target axis.
assert_eq!(QuoteForm::QUOTE_SHAPE, SexpShape::Quote);
assert_eq!(QuoteForm::QUASIQUOTE_SHAPE, SexpShape::Quasiquote);
assert_eq!(QuoteForm::UNQUOTE_SHAPE, SexpShape::Unquote);
assert_eq!(QuoteForm::UNQUOTE_SPLICE_SHAPE, SexpShape::UnquoteSplice);
}
#[test]
fn quote_form_shapes_has_expected_cardinality() {
// CLOSED-SET CARDINALITY CONTRACT: `QuoteForm::SHAPES` carries
// exactly FOUR entries — one per variant in the closed-set
// quote-family carving. Runtime companion to the `[SexpShape;
// 4]` type annotation's compile-time forced arity. A regression
// that widens the array without adding a matching per-role
// `*_SHAPE` alias would fail the `[SexpShape; 4]` type check
// at rustc time; this runtime pin catches a silent shrink or
// duplicate-arm coalesce. Sibling posture to
// `quote_form_labels_has_expected_cardinality` /
// `quote_form_prefixes_has_expected_cardinality` /
// `quote_form_iac_forge_tags_has_expected_cardinality` /
// `quote_form_hash_discriminators_has_expected_cardinality` on
// the other four per-role axes of the SAME closed set.
assert_eq!(QuoteForm::SHAPES.len(), 4);
assert_eq!(QuoteForm::SHAPES.len(), QuoteForm::ALL.len());
}
#[test]
fn quote_form_shapes_align_with_all_by_index() {
// ALIGNMENT CONTRACT: `Self::SHAPES[i] ==
// Self::ALL[i].sexp_shape()` element-wise. Pins that the typed
// variant ALL and the `SexpShape` SHAPES ALL stay in lockstep
// under any reorder — a regression that reorders ONE array
// without reordering the other silently misaligns every
// `zip(ALL, SHAPES)` consumer that wants to project each
// quote-family variant to its canonical outer-shape identity
// (LSP completion, `tatara-check` predicate over the quote-
// family ⊂ outer partition, Sekiban audit-trail metric jointly
// labeled by the embed target). Sibling posture to
// `quote_form_labels_align_with_all_by_index` /
// `quote_form_prefixes_align_with_all_by_index` on the other
// per-role axes of the SAME closed set.
for (i, form) in QuoteForm::ALL.iter().enumerate() {
assert_eq!(
QuoteForm::SHAPES[i],
form.sexp_shape(),
"QuoteForm::SHAPES[{i}] `{shape:?}` drifted from \
QuoteForm::ALL[{i}] ({form:?}).sexp_shape() \
`{via_variant:?}` — the canonical declaration order \
of the ALL array and the sexp_shape projection must \
match element-wise",
shape = QuoteForm::SHAPES[i],
via_variant = form.sexp_shape(),
);
}
}
#[test]
fn quote_form_shapes_align_with_all_by_index_through_as_quote_form() {
// ROUND-TRIP CONTRACT: `Self::SHAPES[i].as_quote_form() ==
// Some(Self::ALL[i])` element-wise. Pins the embed / project
// section of the (`QuoteForm::sexp_shape`,
// `SexpShape::as_quote_form`) `Iso(QuoteForm, QuoteShape ⊂
// SexpShape)` as a family-wide array-indexed law rather than
// as a per-variant assertion sweep. A regression that drifts
// EITHER the `SHAPES` array entries OR the peer inverse
// `as_quote_form` arms silently breaks the (embed, project)
// section — this pin catches both directions at ONCE. Sibling
// posture to
// `atom_kind_shapes_align_with_all_by_index_through_as_atom_kind`
// on the peer 6-of-12 atomic-payload carving.
for (i, form) in QuoteForm::ALL.iter().enumerate() {
assert_eq!(
QuoteForm::SHAPES[i].as_quote_form(),
Some(*form),
"QuoteForm::SHAPES[{i}] `{shape:?}`.as_quote_form() = \
{actual:?} drifted from Some(QuoteForm::ALL[{i}]) = \
Some({expected:?}) — the (SHAPES entry, ALL variant) \
round-trip through the peer inverse SexpShape::as_quote_form \
must hold element-wise",
shape = QuoteForm::SHAPES[i],
actual = QuoteForm::SHAPES[i].as_quote_form(),
expected = form,
);
}
}
#[test]
fn quote_form_sexp_shape_routes_through_typed_per_role_constants() {
// ROUTING CONTRACT: `QuoteForm::sexp_shape()`'s four arms bind
// through the per-role `pub const *_SHAPE` aliases rather than
// through inline `SexpShape::X` literals. Pin so a regression
// that re-inlines the four literals here (and gains its own
// drift surface separate from the canonical per-role alias
// site) surfaces immediately at variant equality. Sibling
// posture to
// `quote_form_label_composes_through_sexp_shape_label_for_every_variant`
// (which pins label routing through sexp_shape().label()) and
// `atom_kind_sexp_shape_routes_through_typed_per_role_constants`
// on the peer 6-of-12 atomic-payload carving.
assert_eq!(QuoteForm::Quote.sexp_shape(), QuoteForm::QUOTE_SHAPE);
assert_eq!(
QuoteForm::Quasiquote.sexp_shape(),
QuoteForm::QUASIQUOTE_SHAPE
);
assert_eq!(QuoteForm::Unquote.sexp_shape(), QuoteForm::UNQUOTE_SHAPE);
assert_eq!(
QuoteForm::UnquoteSplice.sexp_shape(),
QuoteForm::UNQUOTE_SPLICE_SHAPE
);
}
#[test]
fn quote_form_shapes_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every entry of the `SHAPES` array
// must differ so the (QuoteForm variant, SexpShape embed
// target) mapping stays injective — a collision would silently
// route two distinct QuoteForm variants through the SAME
// outer-shape identity, breaking the QuoteForm ⊂ SexpShape
// 4-of-12 carving. Family-wide sweep over `SHAPES × SHAPES` —
// supersedes any per-pair pin and picks up new embed targets
// mechanically. Sibling posture to
// `atom_kind_shapes_pairwise_distinct` on the peer 6-of-12
// atomic-payload carving.
for (i, a) in QuoteForm::SHAPES.iter().enumerate() {
for (j, b) in QuoteForm::SHAPES.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"QuoteForm::SHAPES[{i}] `{a:?}` collides with \
QuoteForm::SHAPES[{j}] `{b:?}` — the QuoteForm ⊂ \
SexpShape 4-of-12 carving would route two quote-\
family variants through the same outer-shape identity"
);
}
}
}
#[test]
fn atom_kind_label_round_trips_through_from_str() {
// Bidirectional `label` ↔ `FromStr` contract: for every variant
// in ALL, `kind.label().parse() == Ok(kind)`. A regression that
// drifts the (variant, literal) pairing at ONE arm of `label`
// (typo, capitalization drift) OR at the `FromStr` decode body
// (off-by-one, missing variant in the sweep) fails-loudly here.
// The canonical-literal site is singular (`label`) so the
// round-trip is the only way the typed surface and the
// rendered diagnostic literal can drift apart — pinning it
// here means they cannot. Sibling posture to
// `sexp_shape_label_round_trips_through_from_str`.
for kind in AtomKind::ALL {
let parsed: AtomKind = kind
.label()
.parse()
.expect("every ALL variant's label must round-trip through FromStr");
assert_eq!(
parsed,
kind,
"FromStr({}) must round-trip to the same variant",
kind.label()
);
}
}
#[test]
fn unknown_atom_kind_carries_offending_input_verbatim() {
// Operator-facing diagnostic contract: the offending input
// lands in the typed error verbatim — no normalization, no
// case-folding, no truncation. Pin the exact `#[error(...)]`
// rendering AND the typed `.0` field projection so a future
// refactor that normalizes (e.g. `.to_lowercase()`) before
// building the error or that drops the input fails-loudly
// here. Symmetric to every sibling `Unknown*` carrier in the
// workspace.
let err: UnknownAtomKind = "Symbol".parse::<AtomKind>().expect_err(
"capitalized `Symbol` must NOT decode — labels are byte-equal case-sensitive",
);
assert_eq!(err.0, "Symbol");
assert_eq!(format!("{err}"), "unknown atom kind: Symbol");
let err: UnknownAtomKind = "str"
.parse::<AtomKind>()
.expect_err("`str` is not a canonical AtomKind label — `string` is");
assert_eq!(err.0, "str");
assert_eq!(format!("{err}"), "unknown atom kind: str");
let err: UnknownAtomKind = ""
.parse::<AtomKind>()
.expect_err("empty input must NOT decode to an AtomKind");
assert_eq!(err.0, "");
assert_eq!(format!("{err}"), "unknown atom kind: ");
}
#[test]
fn atom_kind_from_str_rejects_non_atom_sexp_shape_labels() {
// CROSS-AXIS GUARD: `SexpShape::label()`'s vocabulary is the
// SUPERSET of `AtomKind::label()`'s — every AtomKind label
// decodes successfully through SexpShape's FromStr to the
// matching SexpShape variant (because the typed projections
// agree), but the SIX non-atom SexpShape labels (`"nil"`,
// `"list"`, `"quote"`, `"quasiquote"`, `"unquote"`,
// `"unquote-splice"`) MUST reject through AtomKind's FromStr
// — they have no atomic-kind preimage. A FromStr that
// silently accepted `"list"` as an AtomKind would corrupt
// the typed identity downstream of any future diagnostic
// round-trip. Pin BOTH directions: the six atom labels
// decode successfully (and to the matching `AtomKind`
// variant), the six non-atom labels reject.
assert_eq!("symbol".parse::<AtomKind>().unwrap(), AtomKind::Symbol);
assert_eq!("keyword".parse::<AtomKind>().unwrap(), AtomKind::Keyword);
assert_eq!("string".parse::<AtomKind>().unwrap(), AtomKind::Str);
assert_eq!("int".parse::<AtomKind>().unwrap(), AtomKind::Int);
assert_eq!("float".parse::<AtomKind>().unwrap(), AtomKind::Float);
assert_eq!("bool".parse::<AtomKind>().unwrap(), AtomKind::Bool);
// Non-atom SexpShape labels (the six structural shapes
// OUTSIDE the AtomKind closed set) must reject.
for label in [
"nil",
"list",
"quote",
"quasiquote",
"unquote",
"unquote-splice",
] {
assert!(
label.parse::<AtomKind>().is_err(),
"non-atom SexpShape label {label:?} must NOT decode to an AtomKind",
);
}
// Sanity: typed peers' labels (`UnquoteForm::marker`'s
// `,` / `,@` punctuation, `ExpectedKwargShape`'s
// `"number"` / `"list of strings"` vocabulary) live on
// different axes and MUST reject too — pin the closed-set
// boundary.
for label in [",", ",@", "number", "list of strings", "atom", "Atom"] {
assert!(
label.parse::<AtomKind>().is_err(),
"cross-axis label {label:?} must NOT decode to an AtomKind",
);
}
}
#[test]
fn atom_kind_is_well_formed_closed_set() {
// Structural contract: AtomKind's six variants are pairwise
// distinct, round-trip through the trait's `label` ↔
// `parse_label`, and reject the empty string — the
// workspace-wide `assert_closed_set_well_formed::<T>()` testkit
// pinned across every `tatara-process` closed-set implementor
// (`AllocationPhase`, `RequestorKind`, `ProcessPhase`,
// `ConditionKind`, `WorkloadKind`, …). The substrate-level
// assertion runs on the auto-derived `impl ClosedSet for
// AtomKind` emitted by `#[derive(tatara_closed_set::DeriveClosedSet)]`
// — a regression that drifts the derive's `make_unknown`
// delegation, the `via = "label"` projection, or the variant
// listing forced through `Self::ALL` fails-loudly here in
// isolation from the per-variant truth tables above.
tatara_closed_set::assert_closed_set_well_formed::<AtomKind>();
}
#[test]
fn atom_kind_per_role_labels_alias_sexp_shape_per_role_labels_byte_for_byte() {
// ALIAS CONTRACT: pin every one of the six per-role
// `pub const AtomKind::*_LABEL` aliases equals the corresponding
// `pub const SexpShape::*_LABEL` byte-for-byte — so the AtomKind
// ⊂ SexpShape marker-vocabulary containment routes through the
// typed `pub const AtomKind::V_LABEL: &'static str =
// SexpShape::V_LABEL` alias chain rather than through two
// independent literal-discipline sites. A regression that
// renames the SexpShape side without updating the AtomKind
// alias pointing at it fails-loudly here with the exact axis
// identified (SYMBOL / KEYWORD / STRING / INT / FLOAT / BOOL);
// a regression that re-inlines the AtomKind constant to a
// fresh literal still passes this pin but loses the alias-
// chain typing (which is what
// `atom_kind_label_arms_route_through_per_role_labels_for_every_variant`
// + `atom_kind_labels_align_with_all_by_index` catch in
// combination).
//
// Six per-role checks, each spelled out so a regression on ONE
// variant surfaces the exact axis rather than through a
// variant-loop that hides which arm drifted. The `Str →
// String` boundary rename is intentional and load-bearing (the
// wire vocabulary is `"string"` on both axes) — the
// STRING_LABEL alias is the canonical bridge, so a future
// rename that reverses the `Str → "string"` rename to a
// literal `"str"` fails the byte-equality pin at THIS test.
assert_eq!(AtomKind::SYMBOL_LABEL, SexpShape::SYMBOL_LABEL);
assert_eq!(AtomKind::KEYWORD_LABEL, SexpShape::KEYWORD_LABEL);
assert_eq!(AtomKind::STRING_LABEL, SexpShape::STRING_LABEL);
assert_eq!(AtomKind::INT_LABEL, SexpShape::INT_LABEL);
assert_eq!(AtomKind::FLOAT_LABEL, SexpShape::FLOAT_LABEL);
assert_eq!(AtomKind::BOOL_LABEL, SexpShape::BOOL_LABEL);
}
#[test]
fn atom_kind_label_arms_route_through_per_role_labels_for_every_variant() {
// PATH-UNIFORMITY: `AtomKind::V.label()` MUST equal the per-
// role `pub const AtomKind::V_LABEL` for every `v: AtomKind`.
// Pre-lift the six atomic-payload marker bytes were reachable
// through `AtomKind::label` (the composition
// `self.sexp_shape().label()` — routing into
// `SexpShape::*_LABEL`) OR through direct
// `SexpShape::*_LABEL` reach-across; post-lift each variant's
// canonical bytes are reachable through the per-role
// `AtomKind::*_LABEL` alias too. Pin the byte-equality between
// the runtime projection and the compile-time alias so a
// regression that renames the alias without updating the arm
// (or vice versa) fails-loudly at the exact axis.
//
// Sibling-shape pin to
// `sexp_shape_label_routes_through_typed_per_variant_constants`
// one algebra layer up — the parent superset's per-role
// constants are pinned against `SexpShape::label`'s arms
// there; this pin binds the AtomKind subset algebra's per-
// role aliases against `AtomKind::label`'s composition-routed
// arms so the six atomic-payload marker labels project through
// ONE aliased typed source of truth per role rather than
// through per-consumer inline literals.
assert_eq!(AtomKind::Symbol.label(), AtomKind::SYMBOL_LABEL);
assert_eq!(AtomKind::Keyword.label(), AtomKind::KEYWORD_LABEL);
assert_eq!(AtomKind::Str.label(), AtomKind::STRING_LABEL);
assert_eq!(AtomKind::Int.label(), AtomKind::INT_LABEL);
assert_eq!(AtomKind::Float.label(), AtomKind::FLOAT_LABEL);
assert_eq!(AtomKind::Bool.label(), AtomKind::BOOL_LABEL);
}
#[test]
fn atom_kind_labels_has_expected_cardinality() {
// Cardinality pin: `LABELS.len() == 6` matches `ALL.len()` so a
// refactor that loosens the type to `&'static [&'static str]`
// fails HERE (the `[_; 6]` slot cannot be sliced silently), and
// a variant added to `ALL` without a matching `LABELS` row fails
// the pair-arity gate at the array literal itself before this
// test even runs. The pin doubles as an operator-visible mark
// of the family's cardinality across the substrate — six
// atomic-payload markers, matching the six-arm carving of the
// parent `SexpShape::LABELS` (the atomic subset of the twelve
// canonical outer-shape labels).
assert_eq!(AtomKind::LABELS.len(), 6);
assert_eq!(AtomKind::LABELS.len(), AtomKind::ALL.len());
}
#[test]
fn atom_kind_labels_align_with_all_by_index() {
// ALIGNMENT PIN: sweep `LABELS[i] == ALL[i].label()` so any
// `zip(ALL, LABELS)` consumer reads a coherent (variant, label)
// pair off ONE forced-arity array pair. The declaration-order
// pin makes a family-wide consumer that walks the ALL /
// LABELS pair in lockstep (an LSP completion bar keyed on
// `AtomKind::LABELS`, a Sekiban metric emitter labeling
// `tatara_lisp_atom_type_mismatch_total{kind}` by the
// per-index label) read one canonical (variant, bytes) pair per
// slot rather than routing through per-consumer paired-
// iteration. A regression that reorders LABELS without also
// reordering ALL (or vice versa) fails-loudly at the exact
// index that drifted.
assert_eq!(AtomKind::LABELS.len(), AtomKind::ALL.len());
for (i, kind) in AtomKind::ALL.iter().enumerate() {
assert_eq!(
AtomKind::LABELS[i],
kind.label(),
"AtomKind::LABELS[{i}] `{lbl}` drifted from \
AtomKind::ALL[{i}].label() `{via_variant}` — the \
canonical ALL ordering and the LABELS ordering must \
match element-wise",
lbl = AtomKind::LABELS[i],
via_variant = kind.label(),
);
}
}
#[test]
fn atom_kind_labels_pairwise_distinct() {
// 6x6 pairwise sweep so a collision between any two labels
// (which would silently degrade two distinct atomic-payload
// markers to the SAME diagnostic bytes and violate the
// closed-set FromStr round-trip) fails-loudly at the exact
// pair. Distinctness is already enforced structurally by
// `assert_closed_set_well_formed::<AtomKind>()` (clause 3), so
// this pin is a secondary guard focused on the per-role
// `pub const` surface directly rather than the runtime
// projection through the trait's default `labels()`.
for (i, a) in AtomKind::LABELS.iter().enumerate() {
for (j, b) in AtomKind::LABELS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"AtomKind::LABELS[{i}] ({a:?}) collides with \
AtomKind::LABELS[{j}] ({b:?}) — two distinct \
atomic-payload markers cannot share diagnostic bytes",
);
}
}
}
#[test]
fn atom_label_projects_each_variant_to_canonical_diagnostic_label() {
// PER-ARM CONTRACT: pin the outer-`Atom` `Self::label`
// projection produces the SIX canonical `&'static str` labels
// byte-for-byte across every reachable atomic-payload variant.
// Pre-lift the outer-`Atom` label projection had no typed
// primitive on the value-carrier algebra — a consumer with an
// `Atom` value in hand wanting the canonical diagnostic label
// had to spell the two-step composition `atom.kind().label()`
// at every callsite, OR go through
// `Sexp::Atom(atom.clone()).type_name()` which wraps and
// unwraps for no runtime purpose. Post-lift the SIX arms bind
// at ONE typed projection on the outer-`Atom` algebra that
// routes through `AtomKind::label` (which itself composes
// through `AtomKind::sexp_shape().label()` into the canonical
// `SexpShape::label` site) — the (Atom variant, diagnostic
// label) pairing binds at ONE typed algebra composition
// spanning FOUR typed layers.
//
// Sibling-shape pin to
// `atom_kind_label_renders_canonical_string_for_every_variant`
// one algebra layer down and
// `sexp_type_name_method_projects_each_outer_arm_to_canonical_label`
// one algebra layer up. A regression that drifts ONE arm's
// label (e.g. Symbol → "sym", swapping Int ↔ Float, dropping
// the `Str → "string"` boundary rename) fails-loudly at THIS
// test AND the sibling `AtomKind::label` per-arm pin.
assert_eq!(Atom::Symbol("foo".to_owned()).label(), "symbol");
assert_eq!(Atom::Keyword("kw".to_owned()).label(), "keyword");
assert_eq!(Atom::Str("hi".to_owned()).label(), "string");
assert_eq!(Atom::Int(42).label(), "int");
assert_eq!(Atom::Float(1.5).label(), "float");
assert_eq!(Atom::Bool(true).label(), "bool");
assert_eq!(Atom::Bool(false).label(), "bool");
}
#[test]
fn atom_label_composes_through_kind_label_for_every_variant() {
// COMPOSITION-LAW CONTRACT: `atom.label() == atom.kind().label()`
// for every reachable atomic payload — the outer-`Atom` label
// projection is structurally derived through `Self::kind` +
// `AtomKind::label` rather than through a parallel six-arm
// inline match on the outer-`Atom` algebra. Pin the composition
// law so a future refactor that re-inlines the six atomic-arm
// literals here (and gains its own drift surface separate from
// the `AtomKind::label` canonical site) surfaces immediately.
// The pointer-equality check pins the composition produces the
// SAME `&'static str` (not just a byte-equal copy) for every
// variant — proof the routing hits ONE static literal site
// (`SexpShape::label` via `AtomKind::sexp_shape().label()` via
// `AtomKind::label`'s composition) rather than a parallel inline
// table on the outer-`Atom` algebra.
//
// Sibling-shape pin to
// `atom_kind_label_routes_through_sexp_shape_label_via_sexp_shape_projection`
// one algebra layer down (which pins `AtomKind::label`'s routing
// through `SexpShape::label`) and
// `sexp_type_name_method_composes_through_shape_label_for_every_outer_shape`
// one algebra layer up (which pins `Sexp::type_name`'s routing
// through `Sexp::shape().label()`). The three routing pins jointly
// enforce the (outer-`Atom` value, canonical label) pairing
// stays a full four-layer typed composition (`Atom` → `AtomKind`
// → `SexpShape` → `&'static str`) rather than degrading to a
// per-layer inline literal table.
let samples: Vec<Atom> = vec![
Atom::Symbol("foo".to_owned()),
Atom::Keyword("kw".to_owned()),
Atom::Str("hi".to_owned()),
Atom::Int(0),
Atom::Int(-7),
Atom::Int(42),
Atom::Float(0.0),
Atom::Float(-1.5),
Atom::Float(f64::INFINITY),
Atom::Bool(true),
Atom::Bool(false),
];
for atom in &samples {
let via_label = atom.label();
let via_composition = atom.kind().label();
assert_eq!(
via_label, via_composition,
"Atom::label() must route through self.kind().label() \
for {atom:?} — drift here means the lift was reverted \
to inline arms",
);
assert!(
std::ptr::eq(via_label.as_ptr(), via_composition.as_ptr()),
"Atom::label() must return the SAME `&'static str` as \
self.kind().label() for {atom:?} — pointer drift \
means the lift composes through a parallel literal \
table rather than routing into the canonical \
AtomKind::label site",
);
}
}
#[test]
fn atom_label_agrees_with_sexp_type_name_at_every_atom_arm() {
// CROSS-ALGEBRA AGREEMENT CONTRACT: for every atomic payload
// `a`, `a.label() == Sexp::Atom(a.clone()).type_name()`. The
// agreement is a TYPED CONSEQUENCE of the two typed
// compositions — `Sexp::Atom(a).type_name()` routes through
// `Sexp::shape()`'s `Self::Atom(a) => a.kind().sexp_shape()`
// arm which composes with `SexpShape::label` byte-for-byte
// with `a.kind().label()` (which itself composes through
// `AtomKind::sexp_shape().label()`). A regression that drifts
// either side of the cross-algebra bridge (an outer-`Atom`
// label re-inlined onto a different literal, an outer-`Sexp`
// Atom-arm re-routed through a stale shape projection, an
// `AtomKind::sexp_shape` arm that swaps Int ↔ Float) fails-
// loudly here rather than as a silent operator-facing
// diagnostic drift at every consumer that pattern-matches on
// the outer-`Sexp` label vs the outer-`Atom` label
// independently.
//
// Sibling posture to
// `atom_kind_label_agrees_with_sexp_shape_label_for_every_atom_arm`
// one algebra layer down — that pin binds the marker-level
// vocabulary containment (`AtomKind::label ==
// AtomKind::sexp_shape().label()`), this pin binds the
// outer-value-level vocabulary containment (`Atom::label ==
// Sexp::Atom(_).type_name()`) so the FOUR-layer typed
// composition on the outer-`Atom` algebra and the FIVE-layer
// typed composition on the outer-`Sexp` algebra agree at their
// common atomic-payload arms.
for atom in [
Atom::Symbol("foo".to_owned()),
Atom::Keyword("kw".to_owned()),
Atom::Str("hi".to_owned()),
Atom::Int(42),
Atom::Float(2.5),
Atom::Bool(true),
Atom::Bool(false),
] {
let via_atom = atom.label();
let via_sexp = Sexp::Atom(atom.clone()).type_name();
assert_eq!(
via_atom, via_sexp,
"Atom::label() must agree with Sexp::Atom(_).type_name() \
for {atom:?} — cross-algebra label drift at the \
atomic-payload arms would fracture the typed diagnostic \
vocabulary between the outer-Atom and outer-Sexp \
algebras",
);
assert!(
std::ptr::eq(via_atom.as_ptr(), via_sexp.as_ptr()),
"Atom::label() must return the SAME `&'static str` as \
Sexp::Atom(_).type_name() for {atom:?} — pointer drift \
means one algebra layer re-inlined the literal rather \
than routing into the canonical `SexpShape::label` \
site",
);
}
}
#[test]
fn atom_sexp_shape_projects_each_variant_to_canonical_outer_shape() {
// PER-ARM CONTRACT: pin the outer-`Atom` `Self::sexp_shape`
// projection produces the SIX canonical `SexpShape` variants
// byte-for-byte across every reachable atomic-payload variant.
// Pre-lift the outer-`Atom` outer-shape projection had no typed
// primitive on the value-carrier algebra — a consumer with an
// `Atom` value in hand wanting the canonical outer-shape had to
// spell the two-step composition `atom.kind().sexp_shape()` at
// every callsite, OR go through `Sexp::Atom(atom.clone()).shape()`
// which wraps and unwraps for no runtime purpose. Post-lift the
// SIX arms bind at ONE typed projection on the outer-`Atom`
// algebra that routes through `AtomKind::sexp_shape` — the
// (Atom variant, SexpShape variant) pairing binds at ONE typed
// algebra composition spanning THREE typed layers.
//
// Sibling-shape pin to
// `atom_kind_sexp_shape_projects_each_variant_to_canonical_outer_shape`
// one algebra layer down and `atom_label_projects_each_variant_to_canonical_diagnostic_label`
// one vocabulary axis over. A regression that drifts ONE arm's
// mapping (e.g. swapping Int ↔ Float, dropping the `Str →
// SexpShape::String` boundary rename) fails-loudly at THIS
// test AND the sibling `AtomKind::sexp_shape` per-arm pin.
assert_eq!(
Atom::Symbol("foo".to_owned()).sexp_shape(),
SexpShape::Symbol
);
assert_eq!(
Atom::Keyword("kw".to_owned()).sexp_shape(),
SexpShape::Keyword
);
assert_eq!(Atom::Str("hi".to_owned()).sexp_shape(), SexpShape::String);
assert_eq!(Atom::Int(42).sexp_shape(), SexpShape::Int);
assert_eq!(Atom::Float(1.5).sexp_shape(), SexpShape::Float);
assert_eq!(Atom::Bool(true).sexp_shape(), SexpShape::Bool);
assert_eq!(Atom::Bool(false).sexp_shape(), SexpShape::Bool);
}
#[test]
fn atom_sexp_shape_composes_through_kind_sexp_shape_for_every_variant() {
// COMPOSITION-LAW CONTRACT: `atom.sexp_shape() ==
// atom.kind().sexp_shape()` for every reachable atomic payload
// — the outer-`Atom` outer-shape projection is structurally
// derived through `Self::kind` + `AtomKind::sexp_shape` rather
// than through a parallel six-arm inline match on the outer-
// `Atom` algebra. Pin the composition law so a future refactor
// that re-inlines the six atomic-arm literals here (and gains
// its own drift surface separate from the `AtomKind::sexp_shape`
// canonical site) surfaces immediately.
//
// `SexpShape` carries the `String`-carrying `Unknown` arm so
// it can't be `Copy`; the pointer-equality axis
// `atom_label_composes_through_kind_label_for_every_variant`
// uses on the `&'static str` axis doesn't apply here. Byte-
// equality on the `SexpShape` discriminant IS the routing
// contract this pin binds: a regression that re-inlines the
// mapping produces byte-equal SexpShape values yet gains its
// own drift surface at the outer-`Atom` layer separate from
// the canonical `AtomKind::sexp_shape` site.
//
// Sibling-shape pin to
// `atom_label_composes_through_kind_label_for_every_variant`
// one vocabulary axis over (the diagnostic-label axis) and
// `atom_kind_sexp_shape_partition_matches_sexp_shape_atomic_carving`
// one algebra layer down (which pins `AtomKind::sexp_shape`'s
// partition-membership against `SexpShape::as_atom_kind`).
// The three pins jointly enforce the (outer-`Atom` value,
// outer-shape) pairing stays a full three-layer typed
// composition (`Atom` → `AtomKind` → `SexpShape`) rather than
// degrading to a per-layer inline literal table on the
// outer-`Atom` algebra.
let samples: Vec<Atom> = vec![
Atom::Symbol("foo".to_owned()),
Atom::Symbol(String::new()),
Atom::Keyword("kw".to_owned()),
Atom::Keyword(String::new()),
Atom::Str("hi".to_owned()),
Atom::Str(String::new()),
Atom::Int(0),
Atom::Int(-7),
Atom::Int(i64::MIN),
Atom::Int(i64::MAX),
Atom::Float(0.0),
Atom::Float(-1.5),
Atom::Float(f64::INFINITY),
Atom::Float(f64::from_bits(f64::NAN.to_bits())),
Atom::Bool(true),
Atom::Bool(false),
];
for atom in &samples {
let via_sexp_shape = atom.sexp_shape();
let via_composition = atom.kind().sexp_shape();
assert_eq!(
via_sexp_shape, via_composition,
"Atom::sexp_shape() must route through self.kind().sexp_shape() \
for {atom:?} — drift here means the lift was reverted \
to inline arms",
);
// Cross-projection agreement: the routed shape's diagnostic
// label is byte-equal to `atom.label()` (the sibling
// vocabulary axis' composition), pinning that the two typed
// projections through `AtomKind` (one via `label`, one via
// `sexp_shape`) agree at the canonical `SexpShape::label`
// site.
assert_eq!(
via_sexp_shape.label(),
atom.label(),
"atom.sexp_shape().label() must agree with atom.label() \
for {atom:?} — cross-axis vocabulary drift at the \
shape-projection site would fracture the FOUR-layer \
diagnostic composition on the outer-Atom algebra",
);
}
}
#[test]
fn atom_sexp_shape_agrees_with_sexp_shape_at_every_atom_arm() {
// CROSS-ALGEBRA AGREEMENT CONTRACT: for every atomic payload
// `a`, `a.sexp_shape() == Sexp::Atom(a.clone()).shape()`. The
// agreement is a TYPED CONSEQUENCE of the two typed
// compositions — `Sexp::Atom(a).shape()` routes through
// `Sexp::shape()`'s `Self::Atom(a) => a.kind().sexp_shape()`
// arm which byte-for-byte matches `a.sexp_shape()`'s composition
// through `Self::kind` + `AtomKind::sexp_shape`. A regression
// that drifts either side of the cross-algebra bridge (an
// outer-`Atom` shape re-inlined onto a different projection,
// an outer-`Sexp` Atom-arm re-routed through a stale kind
// projection, an `AtomKind::sexp_shape` arm that swaps Int ↔
// Float) fails-loudly here rather than as a silent operator-
// facing drift at every consumer that pattern-matches on the
// outer-`Sexp` shape vs the outer-`Atom` shape independently.
//
// Sibling posture to
// `atom_label_agrees_with_sexp_type_name_at_every_atom_arm`
// one vocabulary axis over — that pin binds the (outer-`Atom`,
// outer-`Sexp`) cross-algebra bridge on the diagnostic-label
// axis, this pin binds it on the outer-shape axis.
for atom in [
Atom::Symbol("foo".to_owned()),
Atom::Keyword("kw".to_owned()),
Atom::Str("hi".to_owned()),
Atom::Int(42),
Atom::Float(2.5),
Atom::Bool(true),
Atom::Bool(false),
] {
let via_atom = atom.sexp_shape();
let via_sexp = Sexp::Atom(atom.clone()).shape();
assert_eq!(
via_atom, via_sexp,
"Atom::sexp_shape() must agree with Sexp::Atom(_).shape() \
for {atom:?} — cross-algebra shape drift at the \
atomic-payload arms would fracture the typed shape \
vocabulary between the outer-Atom and outer-Sexp \
algebras",
);
}
}
#[test]
fn atom_sexp_shape_round_trips_through_sexp_shape_as_atom_kind() {
// ROUND-TRIP CONTRACT: for every atomic payload `a`,
// `a.sexp_shape().as_atom_kind() == Some(a.kind())`. The typed
// embed `Atom → AtomKind → SexpShape` inverts through the
// soft-projection retraction `SexpShape → AtomKind` exactly on
// the 6-of-12 atomic-payload image. A regression that ANY of
// the three embeds (`Self::kind`, `AtomKind::sexp_shape`) OR
// the soft-projection retraction `SexpShape::as_atom_kind`
// drifts on any arm fails-loudly here — the structural
// round-trip is the invariant that holds the closed-set-
// lattice's atomic-payload cell load-bearing across future
// edits.
//
// Peer to `unquote_form_sexp_shape_round_trips_through_sexp_shape_as_quote_form_and_as_unquote_form`
// (error.rs) one carving axis over on the substitution-subset
// side of the outer-shape lattice, and to `atom_kind_sexp_shape_round_trips_through_sexp_shape_as_atom_kind`
// one algebra layer down (which pins the marker-level round-
// trip). This pin extends the round-trip up to the outer-
// `Atom` value carrier.
for atom in [
Atom::Symbol("foo".to_owned()),
Atom::Keyword("kw".to_owned()),
Atom::Str("hi".to_owned()),
Atom::Int(0),
Atom::Int(i64::MIN),
Atom::Float(0.0),
Atom::Float(f64::INFINITY),
Atom::Bool(true),
Atom::Bool(false),
] {
let shape = atom.sexp_shape();
let round_tripped = shape.as_atom_kind();
assert_eq!(
round_tripped,
Some(atom.kind()),
"Atom::sexp_shape() must round-trip through \
SexpShape::as_atom_kind for {atom:?} — the typed embed \
Atom → AtomKind → SexpShape is no longer a section of \
SexpShape::as_atom_kind's inverse on the atomic \
6-of-12 image",
);
}
}
#[test]
fn hash_for_atom_preserves_legacy_discriminator_bytes() {
// CACHE-KEY CONTRACT (Hash side): pin that the lifted
// `Hash for Atom` impl produces byte-identical hashes for the
// six atomic variants as the pre-lift implementation. We
// compute the expected hash via a SECOND hasher that manually
// drives the pre-lift `<discr>u8.hash(h); <inner>.hash(h)`
// sequence (with `Float`'s `to_bits()` projection preserved
// and `String` payloads hashed via `String::hash`), then
// compare. A regression that drifts the discriminator OR
// re-orders the (discr, inner) sequence surfaces here as a
// hash-value mismatch. Sibling posture to
// `hash_for_sexp_preserves_legacy_quote_family_discriminator_bytes`
// on the quote-family axis.
use std::collections::hash_map::DefaultHasher;
let payload = String::from("payload");
// Helper: hash the legacy `<discr>u8.hash(h); <inner>` shape
// through a fresh DefaultHasher and finish.
let legacy_hash = |atom: &Atom, expected_discr: u8| -> u64 {
let mut h = DefaultHasher::new();
expected_discr.hash(&mut h);
match atom {
Atom::Symbol(s) | Atom::Keyword(s) | Atom::Str(s) => s.hash(&mut h),
Atom::Int(n) => n.hash(&mut h),
Atom::Float(f) => f.to_bits().hash(&mut h),
Atom::Bool(b) => b.hash(&mut h),
}
h.finish()
};
// (label, atom, pre-lift discriminator byte)
let cases: &[(&str, Atom, u8)] = &[
("symbol", Atom::Symbol(payload.clone()), 0u8),
("keyword", Atom::Keyword(payload.clone()), 1u8),
("str", Atom::Str(payload.clone()), 2u8),
("int", Atom::Int(42), 3u8),
("float", Atom::Float(1.5), 4u8),
("bool-true", Atom::Bool(true), 5u8),
("bool-false", Atom::Bool(false), 5u8),
];
for (label, atom, expected_discr) in cases {
let mut via_impl = DefaultHasher::new();
atom.hash(&mut via_impl);
let via_legacy = legacy_hash(atom, *expected_discr);
assert_eq!(
via_impl.finish(),
via_legacy,
"Hash for Atom drifted from legacy \
(discr={expected_discr}, inner) sequence at {label}"
);
}
}
#[test]
fn atom_hash_discriminator_composes_through_kind_hash_discriminator_for_every_variant() {
// COMPOSITION-LAW CONTRACT: `atom.hash_discriminator() ==
// atom.kind().hash_discriminator()` for every reachable atomic
// payload — the outer-`Atom` cache-key byte projection is
// structurally derived through `Self::kind` +
// `AtomKind::hash_discriminator` rather than through a parallel
// six-arm inline match on the outer-`Atom` algebra. Pin the
// composition law so a future refactor that re-inlines the six
// atomic-arm literals here (and gains its own drift surface
// separate from the `AtomKind::hash_discriminator` canonical
// site) surfaces immediately.
//
// Sibling-shape pin to
// `atom_label_composes_through_kind_label_for_every_variant`
// (diagnostic-label axis) and
// `atom_sexp_shape_composes_through_kind_sexp_shape_for_every_variant`
// (outer-shape axis) one vocabulary axis over — the three pins
// jointly enforce the outer-`Atom` algebra closes the (label,
// sexp_shape, hash_discriminator) trio through the SAME typed
// marker layer (`Self::kind` into `AtomKind`) rather than
// degrading to a per-layer inline literal table on the
// outer-`Atom` algebra. The sweep includes NaN and ±∞ Float
// payloads (matching `Hash for Atom`'s `f64::to_bits()`
// posture), both empty and non-empty String/Symbol/Keyword
// arms, `i64::{MIN, MAX}` on the Int arm, and both Bool arms —
// exhausting the byte-partition surface at every reachable
// atomic-payload witness.
let samples: Vec<Atom> = vec![
Atom::Symbol("foo".to_owned()),
Atom::Symbol(String::new()),
Atom::Keyword("kw".to_owned()),
Atom::Keyword(String::new()),
Atom::Str("hi".to_owned()),
Atom::Str(String::new()),
Atom::Int(0),
Atom::Int(-7),
Atom::Int(42),
Atom::Int(i64::MIN),
Atom::Int(i64::MAX),
Atom::Float(0.0),
Atom::Float(-1.5),
Atom::Float(f64::INFINITY),
Atom::Float(f64::NEG_INFINITY),
Atom::Float(f64::NAN),
Atom::Bool(true),
Atom::Bool(false),
];
for atom in &samples {
let via_outer = atom.hash_discriminator();
let via_composition = atom.kind().hash_discriminator();
assert_eq!(
via_outer, via_composition,
"Atom::hash_discriminator() must route through \
self.kind().hash_discriminator() for {atom:?} — drift \
here means the lift was reverted to inline arms and \
the outer-`Atom` cache-key algebra fractured from the \
canonical AtomKind::hash_discriminator site",
);
}
}
#[test]
fn hash_for_atom_routes_atom_discriminator_through_atom_hash_discriminator() {
// ROUTING-LAW CONTRACT: pin the outer-`Atom` routing IDENTITY —
// for every reachable atomic payload, `Hash for Atom` produces
// byte-identical output to a hand-driven
// `atom.hash_discriminator().hash(h); <inner-payload-hash>`
// sequence. Binds the composition IDENTITY (not just value
// equality) between the outer Hash body and the typed algebra
// method — a regression that re-inlines the two-hop
// `self.kind().hash_discriminator()` chain at the outer arm
// still drifts detectably if the future
// `Atom::hash_discriminator` composes through a different site.
// Sibling posture to
// `hash_for_sexp_routes_outer_discriminator_through_sexp_hash_discriminator`
// — that pin binds the `Hash for Sexp` body against the
// outer-`Sexp` cache-key method; this pin binds the
// `Hash for Atom` body against the outer-`Atom` cache-key
// method. Together the two routing pins enforce the outer-value
// Hash bodies at BOTH algebras stay structurally parallel
// (`self.hash_discriminator().hash(h); <inner>`).
use std::collections::hash_map::DefaultHasher;
let seeds: Vec<(&str, Atom)> = vec![
("symbol", Atom::Symbol("s".to_owned())),
("symbol-empty", Atom::Symbol(String::new())),
("keyword", Atom::Keyword("kw".to_owned())),
("str", Atom::Str("hi".to_owned())),
("int-zero", Atom::Int(0)),
("int-min", Atom::Int(i64::MIN)),
("int-max", Atom::Int(i64::MAX)),
("float", Atom::Float(2.5)),
("float-nan", Atom::Float(f64::NAN)),
("float-inf", Atom::Float(f64::INFINITY)),
("bool-true", Atom::Bool(true)),
("bool-false", Atom::Bool(false)),
];
for (label, atom) in &seeds {
let mut via_impl = DefaultHasher::new();
atom.hash(&mut via_impl);
let mut via_lifted = DefaultHasher::new();
atom.hash_discriminator().hash(&mut via_lifted);
match atom {
Atom::Symbol(s) | Atom::Keyword(s) | Atom::Str(s) => s.hash(&mut via_lifted),
Atom::Int(n) => n.hash(&mut via_lifted),
Atom::Float(f) => f.to_bits().hash(&mut via_lifted),
Atom::Bool(b) => b.hash(&mut via_lifted),
}
assert_eq!(
via_impl.finish(),
via_lifted.finish(),
"Hash for Atom drifted from routed-through-hash_discriminator sequence at {label}"
);
}
}
#[test]
fn atom_kind_composes_with_domain_sexp_shape_for_every_atomic_arm() {
// PATH-UNIFORMITY / COMPOSITION-LAW CONTRACT: the substrate's
// outer-shape projection `domain::sexp_shape` now routes the
// six atomic arms through `Atom::kind` + `AtomKind::sexp_shape`.
// Pin that the composed projection produces the SAME
// `SexpShape` variant that the pre-lift inline six-arm match
// produced for every `Atom` payload. A regression that drifts
// ONE arm of either `Atom::kind` (e.g. routes `Atom::Int(_)`
// through `AtomKind::Float`) or `AtomKind::sexp_shape` (e.g.
// routes `AtomKind::Symbol` through `SexpShape::Keyword`)
// surfaces as an immediate inequality between
// `domain::sexp_shape(&Sexp::Atom(a))` and
// `a.kind().sexp_shape()` — and since both projections are
// load-bearing for the diagnostic surface, the test pins both
// sides of the typed algebra at once. Sibling posture to
// `quote_form_sexp_shape_paired_with_as_quote_form_preserves_
// pre_lift_pairing_for_every_sexp` on the quote-family axis.
let cases: &[(Atom, SexpShape)] = &[
(Atom::Symbol("x".into()), SexpShape::Symbol),
(Atom::Keyword("k".into()), SexpShape::Keyword),
(Atom::Str("s".into()), SexpShape::String),
(Atom::Int(7), SexpShape::Int),
(Atom::Float(2.5), SexpShape::Float),
(Atom::Bool(true), SexpShape::Bool),
];
for (atom, expected_shape) in cases {
let via_composed = atom.kind().sexp_shape();
assert_eq!(
via_composed, *expected_shape,
"Atom::kind().sexp_shape() drifted for {atom:?}"
);
// Cross-projection identity with the public
// `domain::sexp_shape` projection — pins that the lifted
// arm routes through `AtomKind` exactly as the inline
// arms did pre-lift.
let via_domain = crate::domain::sexp_shape(&Sexp::Atom(atom.clone()));
assert_eq!(
via_domain, via_composed,
"domain::sexp_shape vs Atom::kind().sexp_shape() drift for {atom:?}"
);
}
}
#[test]
fn atom_display_renders_each_variant_to_canonical_form() {
// CANONICAL-RENDERING CONTRACT: pin that the lifted
// `fmt::Display for Atom` impl produces byte-identical
// canonical output for the seven atomic variant cases
// (Bool splits into true/false) as the pre-lift inline
// sub-arms inside `Display for Sexp`'s atom arm. Sibling-arm
// sweep so the seven pairings stay load-bearing under
// reordering refactors. A regression that drifts the Bool
// spelling (`#t`/`#f` vs Rust's `true`/`false`) — the
// CLAUDE.md-pinned reader-round-trip invariant — fails
// loudly here. Direct sibling to `atom_kind_label_renders_
// canonical_string_for_every_variant` on the diagnostic-
// label axis: this pins the rendered SOURCE (`#t`), that pins
// the rendered LABEL (`bool`); the two projections share the
// closed-set `AtomKind` algebra but render to distinct
// surfaces (source vs diagnostic vocabulary).
let cases: &[(Atom, &str)] = &[
(Atom::Symbol("foo".into()), "foo"),
(Atom::Keyword("k".into()), ":k"),
(Atom::Str("hello".into()), "\"hello\""),
(Atom::Int(42), "42"),
(Atom::Int(-7), "-7"),
(Atom::Float(1.5), "1.5"),
(Atom::Bool(true), "#t"),
(Atom::Bool(false), "#f"),
];
for (atom, expected) in cases {
assert_eq!(
atom.to_string(),
*expected,
"Atom::Display drifted from canonical rendering for {atom:?}"
);
}
}
#[test]
fn atom_display_renders_integral_float_with_dot_zero_suffix() {
// ROUND-TRIP-INVARIANT PIN: `fmt_float`'s `.0`-suffix
// discipline composes through `Atom::Display` — `Float(1.0)`
// renders as `"1.0"`, NOT `"1"` (which the reader would
// re-parse as `Atom::Int(1)`, silently coercing the typed
// `Float` track into the `Int` track at the Display→read
// boundary). Direct sibling pin to the existing Display-for-
// Sexp round-trip tests that exercise the same invariant
// through the `Sexp::Atom` outer wrap. Lifting the rendering
// onto the typed `Atom` algebra surfaces a future regression
// (e.g. an Atom::Display arm that bypasses `fmt_float` and
// formats `f64` directly) at the atom layer without
// requiring a Sexp wrap to reproduce.
assert_eq!(Atom::Float(1.0).to_string(), "1.0");
assert_eq!(Atom::Float(-42.0).to_string(), "-42.0");
assert_eq!(Atom::Float(0.99).to_string(), "0.99");
}
#[test]
fn sexp_atom_display_arm_routes_through_atom_display_for_every_variant() {
// LIFTED-BOUNDARY CONTRACT: pin that `Sexp::Atom(a).to_string()
// == a.to_string()` for every atomic payload variant. Pre-
// lift the per-variant body lived inline at the `Sexp::Atom(a)
// => match a { … }` arm of `Display for Sexp`; post-lift the
// outer arm delegates to `fmt::Display::fmt(a, f)`. A
// regression that drifts the outer arm (e.g. wraps the atom
// rendering in parens, or routes Symbol through a Sexp-
// specific arm before delegating) surfaces as an inequality
// here. The cases sweep all six `Atom` variants (Bool unified
// — both true/false agree under the impl). Sibling posture
// to the quote-family routing test
// `sexp_to_json_routes_quote_family_arms_through_as_quote_form_typed_marker`
// that pins the analogous `Sexp` outer arm routing through
// a typed algebra projection.
let cases: &[Atom] = &[
Atom::Symbol("name".into()),
Atom::Keyword("kw".into()),
Atom::Str("body".into()),
Atom::Int(7),
Atom::Float(2.5),
Atom::Float(1.0),
Atom::Bool(true),
Atom::Bool(false),
];
for atom in cases {
let via_sexp = Sexp::Atom(atom.clone()).to_string();
let via_atom = atom.to_string();
assert_eq!(
via_sexp, via_atom,
"Sexp::Atom Display arm drifted from Atom::Display for {atom:?}"
);
}
}
#[test]
fn atom_display_round_trips_through_reader_preserving_typed_identity() {
// BIDIRECTIONAL TYPED-IDENTITY CONTRACT: render an atom via
// `Atom::Display`, parse the rendering through
// `crate::reader::read`, and pin that the parsed value's
// outer shape is `Sexp::Atom(_)` carrying the SAME variant
// discriminator as the seed (via `Atom::kind`) AND that the
// payload round-trips bit-for-bit. This is the typed-exit /
// typed-entry mirror at the atomic-payload boundary — the
// load-bearing invariant the `fmt_float` `.0`-suffix
// discipline already exists to preserve. A regression that
// drifts ONE side (Display arm OR reader arm) corrupts the
// round-trip; pin it at the typed boundary directly. Sibling
// posture to the existing Sexp-layer round-trip tests:
// `float_display_round_trips_through_reader_into_typed_float`,
// `quote_prefix_round_trips_through_read_quoted_into_sexp_quote`.
let cases: &[Atom] = &[
Atom::Symbol("foo-bar".into()),
Atom::Keyword("kw".into()),
Atom::Int(42),
Atom::Int(-7),
Atom::Int(0),
Atom::Float(1.0),
Atom::Float(1.5),
Atom::Float(-42.0),
Atom::Bool(true),
Atom::Bool(false),
];
for seed in cases {
let rendered = seed.to_string();
let mut parsed = crate::reader::read(&rendered)
.unwrap_or_else(|e| panic!("reader rejected {rendered:?} for {seed:?}: {e}"));
assert_eq!(
parsed.len(),
1,
"rendered {rendered:?} for {seed:?} re-read as != 1 form"
);
let Sexp::Atom(round_tripped) = parsed.remove(0) else {
panic!("rendered {rendered:?} for {seed:?} re-read as non-Atom");
};
assert_eq!(
round_tripped.kind(),
seed.kind(),
"Atom::Display→reader drifted variant for {seed:?} via {rendered:?}"
);
assert_eq!(
round_tripped, *seed,
"Atom::Display→reader drifted payload for {seed:?} via {rendered:?}"
);
}
}
#[test]
fn atom_to_json_projects_each_variant_to_canonical_json_value() {
// CANONICAL-MAPPING CONTRACT: pin that `Atom::to_json` produces
// byte-identical `serde_json::Value` outputs for each
// `AtomKind` variant as the pre-lift inline arms inside
// `crate::domain::sexp_to_json` did. Sweeps a representative
// atom of each variant so a regression that drifts ONE arm
// (e.g. swaps `Symbol`'s mapping to a Number, or drops
// `Keyword`'s `:` prefix that `json_to_sexp`'s inverse strips
// — silently breaking every `:values-overlay` payload pinned
// by the CLAUDE.md bool warning) fails loudly. Sibling-arm
// sweep to `atom_display_renders_each_variant_to_canonical_form`
// — both pin the typed-algebra rendering of the atomic
// payload at its canonical projection. The float case uses
// `1.5` (finite) here; NaN / ±∞ get their own pin below.
use serde_json::Value as JValue;
assert_eq!(
Atom::Symbol("name".into()).to_json(),
JValue::String("name".into()),
);
assert_eq!(
Atom::Keyword("parent".into()).to_json(),
JValue::String(":parent".into()),
);
assert_eq!(
Atom::Str("body".into()).to_json(),
JValue::String("body".into()),
);
assert_eq!(Atom::Int(42).to_json(), JValue::Number(42i64.into()));
assert_eq!(Atom::Int(-7).to_json(), JValue::Number((-7i64).into()));
assert_eq!(
Atom::Float(1.5).to_json(),
JValue::Number(serde_json::Number::from_f64(1.5).unwrap()),
);
assert_eq!(Atom::Bool(true).to_json(), JValue::Bool(true));
assert_eq!(Atom::Bool(false).to_json(), JValue::Bool(false));
}
#[test]
fn atom_from_json_number_int_arm_projects_i64_backed_numbers_to_atom_int() {
// TYPED-INVERSE CONTRACT (Int arm): pin that `Atom::from_json_number`
// decodes every `serde_json::Number` whose `.as_i64()` returns
// `Some(i)` to `Atom::Int(i)`. Sweeps every i64-boundary value
// the substrate pinned in the sibling `Atom::to_json` sweep
// (0, ±1, ±42, i64::MAX, i64::MIN) plus a representative
// interior sample; the sweep pins that the `as_i64()` arm
// fires eagerly BEFORE the `as_f64()` arm, so an
// integer-valued `Number` never sinks to `Atom::Float` at the
// atomic-algebra boundary. A regression that drifts the arm
// (e.g. swaps the `as_i64` / `as_f64` order) fails at the
// `i64::MAX` / `i64::MIN` boundary samples because those two
// values exceed `f64`'s 53-bit mantissa and would silently
// round through the `as_f64` sink.
for i in [0i64, 1, -1, 42, -7, i64::MAX, i64::MIN] {
let n: serde_json::Number = i.into();
assert_eq!(
Atom::from_json_number(&n),
Atom::Int(i),
"Atom::from_json_number drifted Int arm for i64 sample {i}",
);
}
}
#[test]
fn atom_from_json_number_float_arm_projects_finite_non_integer_f64_backed_numbers_to_atom_float(
) {
// TYPED-INVERSE CONTRACT (Float arm): pin that
// `Atom::from_json_number` decodes every `serde_json::Number`
// whose `.as_i64()` returns `None` but `.as_f64()` returns
// `Some(f)` to `Atom::Float(f)`. Sweeps a representative set of
// finite non-integer-valued f64 samples the substrate pinned
// in the sibling `Atom::to_json` sweep (1.5, -2.5, positive
// and negative fractional values, subnormal, `f64::MIN_POSITIVE`).
// Every sample is constructed via `serde_json::Number::from_f64`
// which the standard library documents as f64-backed
// (`.as_i64()` returns `None`, `.as_f64()` returns
// `Some(input)`) so the Float arm fires deterministically.
// A regression that drifts the arm (e.g. drops the `as_f64`
// sink entirely and falls through to the `Int(0)` typed floor)
// fails HERE at the fractional-value assertions with an
// `Int(0)` mismatch.
for f in [
1.5f64,
-2.5,
0.1,
-0.1,
f64::MIN_POSITIVE,
1.234_567_890_123,
] {
let n = serde_json::Number::from_f64(f)
.unwrap_or_else(|| panic!("Number::from_f64({f}) must accept finite float"));
assert_eq!(
Atom::from_json_number(&n),
Atom::Float(f),
"Atom::from_json_number drifted Float arm for f64 sample {f}",
);
}
}
#[test]
fn atom_from_json_number_round_trips_atom_to_json_int_arm() {
// ROUND-TRIP LAW (Int axis): pin the paired-projection identity
// `Atom::from_json_number(&<Atom::Int(i).to_json() as Number>)
// == Atom::Int(i)` for every i64 boundary sample. The pair
// `Atom::to_json` (forward) + `Atom::from_json_number` (inverse)
// now lives on the SAME closed-set [`Atom`] algebra — this
// pin proves the closure at ONE algebra layer without a
// `Sexp::from_json` intermediary. A regression that drifts
// either side of the pair (e.g. `Atom::to_json` emits `Int(n)`
// as a JSON string, or `Atom::from_json_number` inverts the
// `as_i64` / `as_f64` cascade order) surfaces here at the
// boundary-value mismatch. Sibling-shape pin to
// `atom_display_round_trips_through_reader_preserving_typed_identity`
// — where that pin closes the `Atom → Display → reader → Atom`
// round-trip on the Display axis, THIS pin closes the
// `Atom::Int → to_json → Number → from_json_number → Atom::Int`
// round-trip on the JSON numeric axis, both on the SAME [`Atom`]
// algebra.
for i in [0i64, 1, -1, 42, -7, i64::MAX, i64::MIN] {
let atom_before = Atom::Int(i);
let via_forward = atom_before.to_json();
let n = match via_forward {
serde_json::Value::Number(n) => n,
other => {
panic!("Atom::Int({i}).to_json() must project to JValue::Number, got {other:?}",)
}
};
assert_eq!(
Atom::from_json_number(&n),
atom_before,
"Atom::Int({i}) round-trip through to_json + from_json_number drifted",
);
}
}
#[test]
fn atom_from_json_number_round_trips_atom_to_json_float_arm_for_non_integer_finite_samples() {
// ROUND-TRIP LAW (Float axis, non-integer subset): pin the
// paired-projection identity `Atom::from_json_number(&<Atom::Float(f)
// .to_json() as Number>) == Atom::Float(f)` for every finite
// non-integer f64 sample. The non-integer restriction is
// load-bearing: `serde_json::Number::from_f64` on an
// integer-valued f64 like `1.0` produces a Number whose
// `.as_i64()` may return `Some(1)` (the exact behavior depends
// on `serde_json`'s internal representation of the JSON
// number tower — integer-valued floats can round-trip through
// the `as_i64` arm, sinking to `Atom::Int(1)` instead of
// `Atom::Float(1.0)`). The three-way (`Symbol` / `Keyword` /
// `Str`) collapse on the string side of `Sexp::from_json`'s
// docstring is one axis; THIS pin covers the (`Int` / `Float`)
// collapse on the numeric side for the round-trippable subset
// (non-integer-valued finite floats). Together with the Int
// round-trip pin above the two floors close the numeric-axis
// round-trip closure at the algebra layer. NaN / ±∞ are
// pinned separately at `atom_to_json_float_nan_and_infinity_collapse_to_null`
// — those don't produce a `Number` from `to_json` so the
// round-trip law does NOT apply to them.
for f in [
1.5f64,
-2.5,
0.1,
-0.1,
f64::MIN_POSITIVE,
1.234_567_890_123,
] {
let atom_before = Atom::Float(f);
let via_forward = atom_before.to_json();
let n = match via_forward {
serde_json::Value::Number(n) => n,
other => panic!(
"Atom::Float({f}).to_json() must project to JValue::Number, got {other:?}",
),
};
assert_eq!(
Atom::from_json_number(&n),
atom_before,
"Atom::Float({f}) round-trip through to_json + from_json_number drifted",
);
}
}
#[test]
fn atom_to_json_float_nan_and_infinity_collapse_to_null() {
// JSON-INEXPRESSIBILITY PIN: JSON has no canonical form for
// `NaN` / `±∞` — `serde_json::Number::from_f64` returns `None`
// for those values, and the substrate's pre-lift behavior at
// `sexp_to_json` mapped them to `JValue::Null` via
// `unwrap_or(JValue::Null)`. Pin the special-case branch at
// the typed-algebra boundary directly so a future refactor
// that bypasses `serde_json::Number::from_f64` (e.g. emits
// `NaN` as the string `"NaN"`, which the JSON deserializer
// would silently re-read as a String at the round-trip
// boundary) surfaces at this test without requiring a Sexp
// wrap to reproduce. Sibling-shape pin to
// `atom_display_renders_integral_float_with_dot_zero_suffix`
// — both pin a non-default branch of the float projection's
// canonical rendering. The branch IS load-bearing for the
// `sexp_to_json` → `serde_json::from_value::<T>` bridge the
// derive-macro fallthrough uses: a downstream `f64` field
// that the operator wrote `:rate :nan` for collapses to
// `JValue::Null` HERE rather than at the serde boundary,
// emitting a clean structural diagnostic instead of a JSON
// parse error miles downstream.
use serde_json::Value as JValue;
assert_eq!(Atom::Float(f64::NAN).to_json(), JValue::Null);
assert_eq!(Atom::Float(f64::INFINITY).to_json(), JValue::Null);
assert_eq!(Atom::Float(f64::NEG_INFINITY).to_json(), JValue::Null);
}
#[test]
fn atom_from_lexeme_classifies_each_atom_kind_for_canonical_lexeme() {
// CANONICAL-CLASSIFICATION CONTRACT: pin that `Atom::from_lexeme`
// produces byte-identical typed `Atom` outputs for a canonical
// lexeme of each `AtomKind` variant against the pre-lift
// `crate::reader::atom_from_str` cascade. Sweeps a representative
// lexeme of each variant so a regression that drifts ONE arm
// (e.g. swaps `"#t"` to `Atom::Symbol("#t")` silently breaking
// every `:values-overlay` payload pinned by the CLAUDE.md bool
// warning, or strips `":kw"`'s prefix when classifying to
// `Atom::Symbol` rather than `Atom::Keyword`) fails loudly.
// Sibling-arm sweep to
// `atom_display_renders_each_variant_to_canonical_form` and
// `atom_to_json_projects_each_variant_to_canonical_json_value` —
// all three pin the typed-algebra at its canonical per-variant
// projection. This is the typed-ENTRY side of the bidirectional
// sweep; those are the typed-EXIT sides.
//
// `Atom::Str` is intentionally absent — `Atom::from_lexeme`'s
// typed-entry surface processes BARE reader-token lexemes, and
// string literals take the reader's `"`-quoted tokenizer branch
// (a `Token::Str(_)`, NOT a `Token::Atom(_)`). The reader's
// string round-trip is pinned by `string_escapes` in
// `crate::reader::tests`.
assert_eq!(Atom::from_lexeme("foo"), Atom::Symbol("foo".into()));
assert_eq!(
Atom::from_lexeme("defpoint"),
Atom::Symbol("defpoint".into())
);
assert_eq!(Atom::from_lexeme("seph.1"), Atom::Symbol("seph.1".into()));
assert_eq!(Atom::from_lexeme(":parent"), Atom::Keyword("parent".into()));
assert_eq!(Atom::from_lexeme(":kw"), Atom::Keyword("kw".into()));
assert_eq!(Atom::from_lexeme("42"), Atom::Int(42));
assert_eq!(Atom::from_lexeme("-7"), Atom::Int(-7));
assert_eq!(Atom::from_lexeme("0"), Atom::Int(0));
assert_eq!(Atom::from_lexeme("1.5"), Atom::Float(1.5));
assert_eq!(Atom::from_lexeme("-2.5"), Atom::Float(-2.5));
assert_eq!(Atom::from_lexeme("#t"), Atom::Bool(true));
assert_eq!(Atom::from_lexeme("#f"), Atom::Bool(false));
}
#[test]
fn atom_from_lexeme_prefers_int_over_float_for_integer_lexeme() {
// LOAD-BEARING DISPATCH-ORDERING PIN: `Atom::from_lexeme` tries
// `i64::from_str` BEFORE `f64::from_str` so a bare `"1"`
// classifies as `Atom::Int(1)`, NOT `Atom::Float(1.0)`. The
// typed-int-vs-typed-float distinction at the typed-entry
// boundary is the dual of `fmt_float`'s `.0`-suffix discipline
// on the typed-exit side — together the two projections form
// the round-trip identity `from_lexeme(a.to_string()) == a`
// for both `Int(_)` and `Float(_)` payloads pinned by
// `atom_from_lexeme_round_trips_with_atom_display_for_every_non_str_variant`
// below. A regression that reorders the parse-cascade (e.g.
// tries `f64::from_str` first, or unifies both via
// `f64::from_str` alone since `f64` parse accepts integer
// lexemes too) silently demotes every integer authoring slot
// into the float track at the reader, corrupting every
// downstream `i64` field's serde round-trip without a
// structural error to point to.
assert_eq!(Atom::from_lexeme("1"), Atom::Int(1));
assert_eq!(Atom::from_lexeme("0"), Atom::Int(0));
assert_eq!(Atom::from_lexeme("-100"), Atom::Int(-100));
// The bare-int lexeme MUST NOT classify to `Atom::Float`.
assert_ne!(Atom::from_lexeme("1"), Atom::Float(1.0));
// Float lexemes (with explicit `.` or scientific notation)
// route through the f64 arm — pin the cascade's fallthrough
// ordering so the int-shortcut doesn't swallow them.
assert_eq!(Atom::from_lexeme("1.0"), Atom::Float(1.0));
assert_eq!(Atom::from_lexeme("1.5"), Atom::Float(1.5));
assert_eq!(Atom::from_lexeme("1e3"), Atom::Float(1e3));
}
#[test]
fn atom_from_lexeme_routes_unknown_lexeme_to_symbol_default() {
// CLOSED-SET DEFAULT-ARM PIN: every lexeme that didn't match a
// structural prefix (`"#t"`/`"#f"` for Bool, `":"` prefix for
// Keyword) or parse as a number (`i64` then `f64`) classifies
// to `Atom::Symbol(_)` by default — the closed-set fallthrough
// arm the reader has shipped with from inception. Pin the
// default-arm projection so a future refactor that adds a new
// structural prefix (e.g. `"#["` for vector literals, `"#\\x"`
// for char literals) without updating the default-arm wording
// cannot silently drift previously-Symbol lexemes into a new
// bucket — the regression surfaces at this test, which sweeps
// the structural-prefix non-matches every closed-set extension
// must continue to classify as Symbol unless the extension
// explicitly claims them. Sibling-shape pin to
// `atom_from_lexeme_classifies_each_atom_kind_for_canonical_lexeme`
// — that pins the structural-prefix MATCHES, this pins the
// structural-prefix NON-MATCHES.
//
// The CLAUDE.md-pinned `true`/`false` round-trip discipline
// also rides this default arm: bare `true`/`false` re-read as
// `Atom::Symbol("true")` / `Atom::Symbol("false")` because the
// Scheme bool spellings are `"#t"`/`"#f"`. The pin guards the
// `serde_json::Value::Bool` field round-trip every
// `:values-overlay` payload depends on.
assert_eq!(Atom::from_lexeme("foo"), Atom::Symbol("foo".into()));
assert_eq!(
Atom::from_lexeme("defpoint"),
Atom::Symbol("defpoint".into())
);
// The CLAUDE.md `true`/`false` warning — these lexemes MUST
// route through the default Symbol arm, NOT through the Bool
// arm. A regression that adds `"true"`/`"false"` recognition
// silently flips every `:values-overlay` Bool field to the
// wrong serde shape.
assert_eq!(Atom::from_lexeme("true"), Atom::Symbol("true".into()));
assert_eq!(Atom::from_lexeme("false"), Atom::Symbol("false".into()));
// Non-structural-prefix shapes — pin a sampling so the
// default arm continues to absorb every shape the prefix
// arms haven't claimed.
assert_eq!(Atom::from_lexeme("seph.1"), Atom::Symbol("seph.1".into()));
assert_eq!(Atom::from_lexeme("a-b"), Atom::Symbol("a-b".into()));
assert_eq!(Atom::from_lexeme("+"), Atom::Symbol("+".into()));
}
#[test]
fn atom_from_lexeme_round_trips_with_atom_display_for_every_non_str_variant() {
// BIDIRECTIONAL TYPED-IDENTITY CONTRACT: render each `Atom`
// (excluding `Atom::Str` — see below) via `fmt::Display`, parse
// the rendering through `Atom::from_lexeme`, and pin that the
// round-trip preserves the typed identity exactly. This is the
// typed-exit / typed-entry mirror at the atomic-payload
// boundary AT THE ALGEBRA LEVEL — sibling-shape pin to
// `atom_display_round_trips_through_reader_preserving_typed_identity`
// which exercises the same round-trip through the full reader.
// Lifting the typed-entry surface onto `Atom::from_lexeme`
// means the round-trip law now lives at the algebra rather
// than at the reader's free-function boundary — a future
// tool that wants to round-trip an `Atom` through its
// canonical lexeme spelling (LSP token-completion, REPL
// pretty-printer, structural editor) binds to `from_lexeme` +
// `Display` directly without crossing through the reader's
// tokenizer.
//
// `Atom::Str` is intentionally absent — `Display for Atom`
// renders `Str(s)` as `"{s:?}"` (debug-quoted, with quote
// marks around the content). The quoted form is NOT a bare
// reader-token lexeme: it's a `Token::Str(_)` to the
// tokenizer, taking a distinct branch. The Str round-trip
// through the FULL reader is pinned by `string_escapes` in
// `crate::reader::tests`.
let cases: &[Atom] = &[
Atom::Symbol("foo-bar".into()),
Atom::Symbol("defpoint".into()),
Atom::Symbol("seph.1".into()),
Atom::Keyword("parent".into()),
Atom::Keyword("kw".into()),
Atom::Int(0),
Atom::Int(42),
Atom::Int(-7),
Atom::Float(1.0),
Atom::Float(1.5),
Atom::Float(-42.0),
Atom::Bool(true),
Atom::Bool(false),
];
for seed in cases {
let rendered = seed.to_string();
let round_tripped = Atom::from_lexeme(&rendered);
assert_eq!(
round_tripped.kind(),
seed.kind(),
"Atom::from_lexeme∘Display drifted variant for {seed:?} via {rendered:?}"
);
assert_eq!(
round_tripped, *seed,
"Atom::from_lexeme∘Display drifted payload for {seed:?} via {rendered:?}"
);
}
}
// ── Atom::as_X soft-projection family + Sexp::as_atom structural lift ──
//
// The six per-variant soft-projection methods on the typed `Atom` algebra
// (`as_symbol` / `as_keyword` / `as_string` / `as_int` / `as_float` /
// `as_bool`) lift the inline `Self::Atom(Atom::X(s)) => Some(s)` arms
// that previously lived at the six `Sexp::as_X` consumer sites onto ONE
// method per closed-set arm. The `Sexp::as_atom` structural lift gives
// the consumer family a uniform two-step composition `as_atom().and_then
// (Atom::as_X)`. The tests below pin:
//
// (1) per-variant typed projection — `Atom::as_X` returns `Some(payload)`
// iff the variant matches AND `None` for every other closed-set arm
// (path-uniformity over `AtomKind::ALL`);
// (2) the `Sexp::as_atom` projection — `Some(&Atom)` iff `Sexp::Atom(_)`
// AND `None` for the structural shapes (`Nil` / `List` /
// `Quote` / `Quasiquote` / `Unquote` / `UnquoteSplice`);
// (3) lifted-boundary composition — `Sexp::as_<X>(s) == s.as_atom()
// .and_then(Atom::as_<X>)` for every atomic variant, AND the
// `Sexp::as_float` widening specialization (`Atom::Int(n)` →
// `Some(n as f64)`) lives at the consumer layer, NOT the algebra
// layer (per the typed-identity discipline pinned at
// `Atom::as_int`'s docstring).
#[test]
fn atom_as_symbol_returns_payload_iff_symbol_variant() {
// PER-VARIANT PROJECTION CONTRACT: `Atom::as_symbol` projects
// `Atom::Symbol(s)` to `Some(&s)` and every other `AtomKind`
// variant to `None`. Sweeps `AtomKind::ALL` for the path-
// uniformity guard — catches a regression that mis-routes ONE
// arm (e.g. accepts `Atom::Keyword(s)` thinking it's "also a
// symbol-like identifier", or rejects `Atom::Symbol("foo")` if
// a future closed-set sweep accidentally narrows the projection
// by an `s.is_empty()` filter).
assert_eq!(Atom::Symbol("foo".into()).as_symbol(), Some("foo"));
assert_eq!(Atom::Symbol("seph.1".into()).as_symbol(), Some("seph.1"));
assert_eq!(Atom::Symbol(String::new()).as_symbol(), Some(""));
for kind in AtomKind::ALL {
if kind == AtomKind::Symbol {
continue;
}
let probe: Atom = match kind {
AtomKind::Symbol => unreachable!(),
AtomKind::Keyword => Atom::Keyword("kw".into()),
AtomKind::Str => Atom::Str("body".into()),
AtomKind::Int => Atom::Int(42),
AtomKind::Float => Atom::Float(1.5),
AtomKind::Bool => Atom::Bool(true),
};
assert_eq!(
probe.as_symbol(),
None,
"Atom::as_symbol must reject non-Symbol variant {kind:?}",
);
}
}
#[test]
fn atom_as_keyword_returns_payload_iff_keyword_variant() {
// PER-VARIANT PROJECTION CONTRACT: `Atom::as_keyword` projects
// `Atom::Keyword(s)` to `Some(&s)` and every other `AtomKind`
// variant to `None`. The returned `&str` is the BARE identifier
// (the `:` prefix was already stripped at the typed-ENTRY
// classifier boundary, `Atom::from_lexeme`); this projection
// does not re-add or re-strip the prefix — pinned by the empty
// probe to catch a regression that accidentally trims a leading
// char.
assert_eq!(Atom::Keyword("parent".into()).as_keyword(), Some("parent"));
assert_eq!(Atom::Keyword(String::new()).as_keyword(), Some(""));
for kind in AtomKind::ALL {
if kind == AtomKind::Keyword {
continue;
}
let probe: Atom = match kind {
AtomKind::Symbol => Atom::Symbol("foo".into()),
AtomKind::Keyword => unreachable!(),
AtomKind::Str => Atom::Str("body".into()),
AtomKind::Int => Atom::Int(42),
AtomKind::Float => Atom::Float(1.5),
AtomKind::Bool => Atom::Bool(true),
};
assert_eq!(
probe.as_keyword(),
None,
"Atom::as_keyword must reject non-Keyword variant {kind:?}",
);
}
}
#[test]
fn atom_as_string_returns_payload_iff_str_variant() {
// PER-VARIANT PROJECTION CONTRACT: `Atom::as_string` projects
// `Atom::Str(s)` to `Some(&s)` and every other `AtomKind`
// variant (including `Symbol` and `Keyword`, which also carry
// `String` payloads) to `None`. The closed-set discriminator is
// load-bearing: a `Symbol("foo")` MUST NOT route through this
// projection — a regression that conflates the three string-
// carrying variants would silently re-classify operator-position
// symbols as string-typed kwarg values at every `extract_string`
// boundary.
assert_eq!(Atom::Str("body".into()).as_string(), Some("body"));
assert_eq!(
Atom::Str("with\nnewline".into()).as_string(),
Some("with\nnewline"),
);
assert_eq!(Atom::Str(String::new()).as_string(), Some(""));
assert_eq!(
Atom::Symbol("looks-like-a-string".into()).as_string(),
None,
"Atom::as_string MUST NOT conflate Symbol with Str — load-bearing typed-identity",
);
assert_eq!(
Atom::Keyword("looks-like-a-string".into()).as_string(),
None,
"Atom::as_string MUST NOT conflate Keyword with Str — load-bearing typed-identity",
);
for kind in [AtomKind::Int, AtomKind::Float, AtomKind::Bool] {
let probe: Atom = match kind {
AtomKind::Int => Atom::Int(42),
AtomKind::Float => Atom::Float(1.5),
AtomKind::Bool => Atom::Bool(true),
_ => unreachable!(),
};
assert_eq!(
probe.as_string(),
None,
"Atom::as_string must reject non-Str variant {kind:?}",
);
}
}
#[test]
fn atom_as_int_returns_payload_iff_int_variant_strict_no_float_widening() {
// PER-VARIANT PROJECTION CONTRACT (STRICT): `Atom::as_int`
// projects `Atom::Int(n)` to `Some(n)` and every other variant
// to `None`. STRICT typed identity: `Atom::Float(1.0)` does
// NOT project through (stays `None`) — the typed-identity
// distinction `Int(1)` vs `Float(1.0)` (load-bearing at the
// `Atom::from_lexeme` ⇄ `Atom::Display` round-trip boundary, dual of
// `fmt_float`'s `.0`-suffix discipline) is preserved at the
// algebra layer. The widening face lives at the
// `Sexp::as_float` consumer (which accepts both `Float` AND
// `Int`); the strict typed identity at the `Atom` algebra is
// load-bearing.
assert_eq!(Atom::Int(42).as_int(), Some(42));
assert_eq!(Atom::Int(-7).as_int(), Some(-7));
assert_eq!(Atom::Int(0).as_int(), Some(0));
assert_eq!(
Atom::Float(1.0).as_int(),
None,
"Atom::as_int MUST be strict — Float(1.0) is NOT Int(1) at the algebra layer",
);
for kind in [
AtomKind::Symbol,
AtomKind::Keyword,
AtomKind::Str,
AtomKind::Float,
AtomKind::Bool,
] {
let probe: Atom = match kind {
AtomKind::Symbol => Atom::Symbol("foo".into()),
AtomKind::Keyword => Atom::Keyword("kw".into()),
AtomKind::Str => Atom::Str("body".into()),
AtomKind::Float => Atom::Float(1.5),
AtomKind::Bool => Atom::Bool(true),
_ => unreachable!(),
};
assert_eq!(
probe.as_int(),
None,
"Atom::as_int must reject non-Int variant {kind:?}",
);
}
}
#[test]
fn atom_as_float_returns_payload_iff_float_variant_strict_no_int_widening() {
// PER-VARIANT PROJECTION CONTRACT (STRICT): `Atom::as_float`
// projects `Atom::Float(n)` to `Some(n)` and every other
// variant to `None`. STRICT typed identity: `Atom::Int(1)`
// does NOT project through (stays `None`) — see
// `atom_as_int_returns_payload_iff_int_variant_strict_no_float_widening`
// for the symmetric discipline. The widening face
// (`Atom::Int(n) → Some(n as f64)`) lives at the `Sexp::as_float`
// consumer layer, NOT the algebra layer.
assert_eq!(Atom::Float(1.5).as_float(), Some(1.5));
assert_eq!(Atom::Float(1.0).as_float(), Some(1.0));
assert_eq!(Atom::Float(-42.0).as_float(), Some(-42.0));
assert_eq!(
Atom::Int(1).as_float(),
None,
"Atom::as_float MUST be strict — Int(1) is NOT Float(1.0) at the algebra layer",
);
for kind in [
AtomKind::Symbol,
AtomKind::Keyword,
AtomKind::Str,
AtomKind::Int,
AtomKind::Bool,
] {
let probe: Atom = match kind {
AtomKind::Symbol => Atom::Symbol("foo".into()),
AtomKind::Keyword => Atom::Keyword("kw".into()),
AtomKind::Str => Atom::Str("body".into()),
AtomKind::Int => Atom::Int(42),
AtomKind::Bool => Atom::Bool(true),
_ => unreachable!(),
};
assert_eq!(
probe.as_float(),
None,
"Atom::as_float must reject non-Float variant {kind:?}",
);
}
}
#[test]
fn atom_as_bool_returns_payload_iff_bool_variant() {
// PER-VARIANT PROJECTION CONTRACT: `Atom::as_bool` projects
// `Atom::Bool(b)` to `Some(b)` and every other variant to
// `None`. Both spellings (`true` / `false`) project through
// the SAME projection — the variant identity (`Bool`) is what
// routes; the inner payload (`true` / `false`) is the
// projected value. CLAUDE.md "Lisp bools": at the reader
// boundary the typed-entry classifier `Atom::from_lexeme`
// routes `"#t"` / `"#f"` to `Atom::Bool(_)` and bare
// `"true"` / `"false"` to `Atom::Symbol(_)`; this projection
// does NOT re-classify the symbol-spelled bools — they STAY
// symbols. The negative test (`Atom::Symbol("true")` rejects)
// pins the discriminator discipline.
assert_eq!(Atom::Bool(true).as_bool(), Some(true));
assert_eq!(Atom::Bool(false).as_bool(), Some(false));
assert_eq!(
Atom::Symbol("true".into()).as_bool(),
None,
"Atom::as_bool MUST reject Symbol(\"true\") — CLAUDE.md typed-identity discipline",
);
assert_eq!(
Atom::Symbol("false".into()).as_bool(),
None,
"Atom::as_bool MUST reject Symbol(\"false\") — CLAUDE.md typed-identity discipline",
);
for kind in [
AtomKind::Symbol,
AtomKind::Keyword,
AtomKind::Str,
AtomKind::Int,
AtomKind::Float,
] {
let probe: Atom = match kind {
AtomKind::Symbol => Atom::Symbol("foo".into()),
AtomKind::Keyword => Atom::Keyword("kw".into()),
AtomKind::Str => Atom::Str("body".into()),
AtomKind::Int => Atom::Int(42),
AtomKind::Float => Atom::Float(1.5),
_ => unreachable!(),
};
assert_eq!(
probe.as_bool(),
None,
"Atom::as_bool must reject non-Bool variant {kind:?}",
);
}
}
#[test]
fn atom_as_symbol_or_string_returns_payload_iff_symbol_or_str_variant() {
// UNION-PROJECTION CONTRACT: `Atom::as_symbol_or_string` projects
// BOTH `Atom::Symbol(s)` AND `Atom::Str(s)` to `Some(s)` and every
// other atomic kind (`Keyword`, `Int`, `Float`, `Bool`) to `None`.
// The disjunctive composition `as_symbol().or_else(||
// as_string())` lives at ONE typed-algebra projection on the
// closed-set `Atom` algebra; pre-lift the composition lived at
// `Sexp::as_symbol_or_string`'s consumer body and traversed
// `Sexp::as_atom` TWICE (once per per-variant projection),
// post-lift it traverses `Sexp::as_atom` ONCE through the
// algebra-level union projection. Pin the algebra-level contract
// sweep so a regression that drifts ONE union arm (e.g. drops the
// `Str` arm, accidentally widens to accept `Keyword`) surfaces
// structurally.
assert_eq!(
Atom::Symbol("my-name".into()).as_symbol_or_string(),
Some("my-name"),
"Atom::as_symbol_or_string must accept Atom::Symbol",
);
assert_eq!(
Atom::Str("my-name".into()).as_symbol_or_string(),
Some("my-name"),
"Atom::as_symbol_or_string must accept Atom::Str",
);
// Empty payloads project through too — the union projection
// is keyed on variant identity, not payload contents.
assert_eq!(
Atom::Symbol(String::new()).as_symbol_or_string(),
Some(""),
"Atom::as_symbol_or_string must accept empty Symbol payload",
);
assert_eq!(
Atom::Str(String::new()).as_symbol_or_string(),
Some(""),
"Atom::as_symbol_or_string must accept empty Str payload",
);
// Negative sweep: the four non-Symbol-non-Str variants reject.
for kind in [
AtomKind::Keyword,
AtomKind::Int,
AtomKind::Float,
AtomKind::Bool,
] {
let probe: Atom = match kind {
AtomKind::Keyword => Atom::Keyword("kw".into()),
AtomKind::Int => Atom::Int(42),
AtomKind::Float => Atom::Float(1.5),
AtomKind::Bool => Atom::Bool(true),
_ => unreachable!(),
};
assert_eq!(
probe.as_symbol_or_string(),
None,
"Atom::as_symbol_or_string must reject non-Symbol-non-Str variant {kind:?}",
);
}
}
#[test]
fn atom_as_symbol_or_string_borrow_ptr_eq_payload() {
// BORROW-LIFETIME CONTRACT: the yielded `&str` borrows the inner
// `String` payload's `&str` view verbatim — no copy, no
// allocation, no `to_string()` round-trip. Pin via `ptr::eq` on
// both projection sides (Symbol arm AND Str arm) so a regression
// that re-inlines the union as `match self { Symbol(s) =>
// Some(s.clone().as_str()), … }` (a `String::clone` reborrow that
// changes the byte-identity) surfaces structurally. Same posture
// as `as_call_to_args_borrow_is_same_pointer_as_as_call_tail` on
// the call-form algebra.
let sym = Atom::Symbol("my-name".into());
let projected = sym.as_symbol_or_string().expect("Symbol arm projects");
match &sym {
Atom::Symbol(s) => assert!(
std::ptr::eq(projected.as_ptr(), s.as_ptr()),
"Atom::as_symbol_or_string must borrow Atom::Symbol payload verbatim",
),
_ => unreachable!(),
}
let str_atom = Atom::Str("my-name".into());
let projected_str = str_atom.as_symbol_or_string().expect("Str arm projects");
match &str_atom {
Atom::Str(s) => assert!(
std::ptr::eq(projected_str.as_ptr(), s.as_ptr()),
"Atom::as_symbol_or_string must borrow Atom::Str payload verbatim",
),
_ => unreachable!(),
}
}
#[test]
fn atom_as_symbol_or_string_is_the_disjunction_of_as_symbol_and_as_string() {
// COMPOSITION LAW: pin that the union projection's value AGREES
// byte-for-byte with the explicit disjunctive composition
// `as_symbol().or_else(|| as_string())` across every atom kind.
// A regression that drifts the union from its disjunctive
// composition (e.g. swaps the `or_else` order so an
// `Atom::Symbol` somehow routes through the `Str` arm first, or
// adds a phantom arm that accepts `Keyword` payloads) surfaces
// here. Same posture as `is_kwargs_list` composing through
// `as_list ∘ atom_as_keyword`.
for atom in [
Atom::Symbol("foo".into()),
Atom::Keyword("kw".into()),
Atom::Str("body".into()),
Atom::Int(42),
Atom::Float(1.5),
Atom::Bool(true),
Atom::Bool(false),
Atom::Symbol(String::new()),
Atom::Str(String::new()),
] {
let by_hand = atom.as_symbol().or_else(|| atom.as_string());
assert_eq!(
atom.as_symbol_or_string(),
by_hand,
"Atom::as_symbol_or_string drifted from as_symbol().or_else(|| as_string()) for {atom:?}",
);
}
}
#[test]
fn sexp_as_symbol_or_string_routes_through_atom_as_symbol_or_string_via_as_atom_composition() {
// CONSUMER-LAYER COMPOSITION LAW: pin that `Sexp::as_symbol_or_string`
// routes through the structural lift `Sexp::as_atom` + the
// algebra-level `Atom::as_symbol_or_string` union projection —
// a regression that re-inlines the pre-lift body
// `self.as_symbol().or_else(|| self.as_string())` (TWO
// `Sexp::as_atom` traversals) at the `Sexp` consumer layer
// becomes detectable here. Sweeps every reachable outer shape so
// the closed-form composition is pinned across Nil + every Atom
// variant + every quote-family wrapper + List + the Sexp::Atom
// arms a regression could route to.
let cases = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::symbol(""),
Sexp::string("body"),
Sexp::string(""),
Sexp::keyword("kw"),
Sexp::int(7),
Sexp::float(2.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("x"))),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::List(vec![]),
];
for s in &cases {
let by_composition = s.as_atom().and_then(Atom::as_symbol_or_string);
assert_eq!(
s.as_symbol_or_string(),
by_composition,
"Sexp::as_symbol_or_string drifted from as_atom().and_then(Atom::as_symbol_or_string) for {s}",
);
}
}
#[test]
fn sexp_as_symbol_or_string_yields_none_for_non_atom_outer_shapes() {
// OUTER-SHAPE NEGATIVE SWEEP: pin that every non-Atom outer
// shape (`Nil`, `List`, every quote-family wrapper) projects to
// `None` — the structural-lift `Sexp::as_atom` rejects them at
// the outer match before the union projection even runs. Pins
// the soft-projection face: the named-form NAME gate
// (`crate::compile::split_name_slot`'s `as_symbol_or_string`
// consumer at compile.rs:671) sees `None` for these shapes and
// emits `NamedFormNonSymbolName` with the projected `SexpShape`
// — the lift preserves the same rejection arm boundary.
for outer in [
Sexp::Nil,
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::List(vec![]),
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("x"))),
] {
assert_eq!(
outer.as_symbol_or_string(),
None,
"Sexp::as_symbol_or_string must reject non-Atom outer shape {outer:?}",
);
}
}
#[test]
fn sexp_as_symbol_or_string_borrow_ptr_eq_atom_payload() {
// BORROW-LIFETIME CONTRACT: the yielded `&str` borrows the inner
// `Atom::Symbol` / `Atom::Str` payload verbatim — no copy, no
// allocation, same lifetime as the outer `&Sexp`. Pin via
// `ptr::eq` on both projection sides so a regression that
// re-inlines the union as a `String`-allocating reborrow (e.g.
// `.map(|s| s.to_owned())` somewhere along the chain) surfaces
// structurally. Sibling pin to
// `atom_as_symbol_or_string_borrow_ptr_eq_payload` at the outer
// (`&Sexp`) layer rather than the inner (`&Atom`) layer.
let sym_sexp = Sexp::symbol("my-name");
let projected = sym_sexp.as_symbol_or_string().expect("Symbol arm projects");
match &sym_sexp {
Sexp::Atom(Atom::Symbol(s)) => assert!(
std::ptr::eq(projected.as_ptr(), s.as_ptr()),
"Sexp::as_symbol_or_string must borrow Atom::Symbol payload verbatim",
),
_ => unreachable!(),
}
let str_sexp = Sexp::string("my-name");
let projected_str = str_sexp.as_symbol_or_string().expect("Str arm projects");
match &str_sexp {
Sexp::Atom(Atom::Str(s)) => assert!(
std::ptr::eq(projected_str.as_ptr(), s.as_ptr()),
"Sexp::as_symbol_or_string must borrow Atom::Str payload verbatim",
),
_ => unreachable!(),
}
}
#[test]
fn sexp_as_atom_projects_inner_atom_iff_outer_is_atom_variant() {
// STRUCTURAL-LIFT CONTRACT: `Sexp::as_atom` projects
// `Sexp::Atom(a)` to `Some(&a)` and every other outer shape
// (`Nil` / `List` / `Quote` / `Quasiquote` / `Unquote` /
// `UnquoteSplice`) to `None`. Sweeps each outer shape so a
// regression that mis-routes ONE arm (e.g. accepts the
// singleton list `(a)` thinking the inner counts as the
// "wrapped atom", or rejects an `Atom` whose payload is empty)
// fails loudly. The `&Atom` borrow is rooted at the outer
// `&Sexp` — the projection does not clone, allocate, or take
// ownership.
let atom = Atom::Symbol("foo".into());
let sexp = Sexp::Atom(atom.clone());
assert_eq!(sexp.as_atom(), Some(&atom));
for outer in [
Sexp::Nil,
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::List(vec![]),
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("x"))),
] {
assert_eq!(
outer.as_atom(),
None,
"Sexp::as_atom must reject non-Atom outer shape {outer:?}",
);
}
}
#[test]
fn sexp_shape_method_projects_each_outer_arm_to_canonical_sexp_shape() {
// CANONICAL-MAPPING CONTRACT: pin that `Sexp::shape()` produces
// byte-identical `SexpShape` markers for each outer-arm of the
// closed `Sexp` algebra. Sweeps every reachable outer shape
// (`Nil`, every `AtomKind` payload, `List`, every `QuoteForm`
// wrapper) so a regression that drifts ONE arm (e.g. routes the
// `Atom::Keyword` arm through `Atom::kind().sexp_shape()` to the
// wrong `SexpShape` variant, or drops the `expect_quote_form`
// projection's marker for a quote-family wrapper) fails loudly.
// Sibling-arm sweep to
// `quote_form_sexp_shape_pins_canonical_shape_identity_for_every_variant`
// (the four quote-family arms in isolation) AND
// `atom_kind_sexp_shape_pins_canonical_atom_payload_shape_for_every_variant`
// (the six atomic-payload arms in isolation) — this test pins
// the OUTER projection that COMPOSES both peer algebras + the
// `Nil` / `List` arms into ONE typed method on the `Sexp`
// algebra.
use crate::error::SexpShape;
assert_eq!(Sexp::Nil.shape(), SexpShape::Nil);
assert_eq!(Sexp::symbol("foo").shape(), SexpShape::Symbol);
assert_eq!(Sexp::keyword("k").shape(), SexpShape::Keyword);
assert_eq!(Sexp::string("s").shape(), SexpShape::String);
assert_eq!(Sexp::int(7).shape(), SexpShape::Int);
assert_eq!(Sexp::float(7.5).shape(), SexpShape::Float);
assert_eq!(Sexp::boolean(true).shape(), SexpShape::Bool);
assert_eq!(Sexp::List(vec![]).shape(), SexpShape::List);
assert_eq!(
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]).shape(),
SexpShape::List,
"non-empty list must project to SexpShape::List — payload count is irrelevant",
);
assert_eq!(Sexp::Quote(Box::new(Sexp::Nil)).shape(), SexpShape::Quote);
assert_eq!(
Sexp::Quasiquote(Box::new(Sexp::Nil)).shape(),
SexpShape::Quasiquote
);
assert_eq!(
Sexp::Unquote(Box::new(Sexp::Nil)).shape(),
SexpShape::Unquote
);
assert_eq!(
Sexp::UnquoteSplice(Box::new(Sexp::Nil)).shape(),
SexpShape::UnquoteSplice
);
}
#[test]
fn sexp_shape_method_agrees_with_domain_sexp_shape_for_every_outer_shape() {
// LIFTED-BOUNDARY CONTRACT: pin that the inherent
// `Sexp::shape()` method agrees with the free-function
// delegate `crate::domain::sexp_shape` for every reachable
// outer shape. Pre-lift the dispatcher lived as a free
// function in `domain.rs`; post-lift the canonical site is
// the inherent method on the `Sexp` algebra and the free
// function is a one-line delegate. Pin that the delegation
// stays byte-for-byte equivalent across every outer arm so a
// regression where the free function drifts from the inherent
// method (or vice versa) surfaces here immediately. Catches
// a future "consolidation" that removes the free function
// without updating the method, or vice versa.
let samples = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::int(-1),
Sexp::float(7.5),
Sexp::float(0.0),
Sexp::boolean(true),
Sexp::boolean(false),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1), Sexp::int(2)]),
Sexp::Quote(Box::new(Sexp::symbol("payload"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![Sexp::symbol("foo")]))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
];
for s in &samples {
let via_method = s.shape();
let via_delegate = crate::domain::sexp_shape(s);
assert_eq!(
via_method, via_delegate,
"Sexp::shape and domain::sexp_shape drifted at {s:?}",
);
}
}
#[test]
fn sexp_shape_method_routes_atom_arm_through_atom_kind_sexp_shape_projection() {
// PATH-UNIFORMITY CONTRACT (atomic axis): the lifted
// `Sexp::shape()` routes its Atom arm through
// `Atom::kind().sexp_shape()` — the typed closed-set projection
// on the `AtomKind` algebra. Pin that the composition agrees
// bit-for-bit with the direct `Sexp::shape()` projection across
// every atomic kind variant. A regression in EITHER projection
// direction (an `Atom::kind` arm that swaps markers, or an
// `AtomKind::sexp_shape` arm that drifts its `SexpShape` mapping)
// surfaces here immediately. Sibling shape to
// `sexp_shape_method_routes_quote_family_arms_through_quote_form_sexp_shape_projection`
// for the quote-family axis.
for kind in AtomKind::ALL {
let atom = match kind {
AtomKind::Symbol => Atom::Symbol("name".into()),
AtomKind::Keyword => Atom::Keyword("parent".into()),
AtomKind::Str => Atom::Str("body".into()),
AtomKind::Int => Atom::Int(42),
AtomKind::Float => Atom::Float(1.5),
AtomKind::Bool => Atom::Bool(true),
};
let via_outer = Sexp::Atom(atom.clone()).shape();
let via_composed = atom.kind().sexp_shape();
assert_eq!(
via_outer, via_composed,
"Sexp::shape's Atom arm drifted from Atom::kind().sexp_shape() at {kind:?}",
);
}
}
#[test]
fn sexp_shape_method_routes_quote_family_arms_through_quote_form_sexp_shape_projection() {
// PATH-UNIFORMITY CONTRACT (quote-family axis): the lifted
// `Sexp::shape()` routes its four quote-family arms through
// `as_quote_form() + QuoteForm::sexp_shape()`. Pin that the
// composition agrees bit-for-bit with the direct `Sexp::shape()`
// projection across every quote-family wrapper variant. A
// regression in EITHER projection direction (an `as_quote_form`
// arm that swaps markers, or a `QuoteForm::sexp_shape` arm that
// drifts its `SexpShape` mapping) surfaces here immediately.
// Mirrors the atomic-axis test
// `sexp_shape_method_routes_atom_arm_through_atom_kind_sexp_shape_projection`.
let samples = [
(
Sexp::Quote(Box::new(Sexp::symbol("payload"))),
QuoteForm::Quote,
),
(
Sexp::Quasiquote(Box::new(Sexp::symbol("payload"))),
QuoteForm::Quasiquote,
),
(
Sexp::Unquote(Box::new(Sexp::symbol("payload"))),
QuoteForm::Unquote,
),
(
Sexp::UnquoteSplice(Box::new(Sexp::symbol("payload"))),
QuoteForm::UnquoteSplice,
),
];
for (sexp, expected_qf) in &samples {
let via_outer = sexp.shape();
let (qf, _) = sexp
.as_quote_form()
.expect("quote-family sample must project through as_quote_form");
assert_eq!(
qf, *expected_qf,
"as_quote_form drifted typed marker at {sexp:?}"
);
let via_composed = qf.sexp_shape();
assert_eq!(
via_outer, via_composed,
"Sexp::shape drifted from as_quote_form + QuoteForm::sexp_shape at {sexp:?}"
);
}
}
#[test]
fn sexp_shape_method_routes_structural_arms_through_structural_kind_sexp_shape_projection() {
// PATH-UNIFORMITY CONTRACT (structural-residual axis): the
// lifted `Sexp::shape()` routes its two structural-residual
// arms (Nil, List) through `StructuralKind::sexp_shape()`. Pin
// that the composition agrees bit-for-bit with the direct
// `Sexp::shape()` projection across the two structural-residual
// variants. A regression that drifts EITHER projection direction
// (a `Sexp::shape` arm that inlines `SexpShape::Nil` /
// `SexpShape::List` back as a raw literal, or a
// `StructuralKind::sexp_shape` arm that drifts its `SexpShape`
// mapping) surfaces here immediately. Sibling-shape pin to the
// atomic-axis routing test
// `sexp_shape_method_routes_atom_arm_through_atom_kind_sexp_shape_projection`
// and the quote-family-axis routing test
// `sexp_shape_method_routes_quote_family_arms_through_quote_form_sexp_shape_projection`
// — together the three tests pin ALL THREE closed-set
// carving-marker `sexp_shape` compositions the lifted
// `Sexp::shape()` body owns.
let samples = [
(Sexp::Nil, StructuralKind::Nil),
(Sexp::List(vec![]), StructuralKind::List),
(Sexp::List(vec![Sexp::symbol("a")]), StructuralKind::List),
];
for (sexp, expected_sk) in &samples {
let via_outer = sexp.shape();
let sk = sexp
.as_structural_kind()
.expect("structural-residual sample must project through as_structural_kind");
assert_eq!(
sk, *expected_sk,
"as_structural_kind drifted typed marker at {sexp:?}"
);
let via_composed = sk.sexp_shape();
assert_eq!(
via_outer, via_composed,
"Sexp::shape drifted from as_structural_kind + StructuralKind::sexp_shape at {sexp:?}"
);
}
}
#[test]
fn sexp_as_structural_kind_projects_nil_and_list_to_canonical_structural_kind() {
// PER-ARM CONTRACT: pin that `Sexp::as_structural_kind()`
// projects `Sexp::Nil` to `Some(StructuralKind::Nil)` and
// `Sexp::List(_)` to `Some(StructuralKind::List)` — the two
// structural-residual arms of the `Sexp` algebra. A regression
// that swaps the two arms (routes `Nil` to `Some(List)` or
// vice versa), returns `None` for either, or projects to a
// wrong `StructuralKind` variant surfaces here immediately.
// The List arm is exercised with an empty AND a non-empty
// items slice so a body that gates on `items.is_empty()`
// (rather than the outer arm) fails loudly.
assert_eq!(Sexp::Nil.as_structural_kind(), Some(StructuralKind::Nil));
assert_eq!(
Sexp::List(vec![]).as_structural_kind(),
Some(StructuralKind::List)
);
assert_eq!(
Sexp::List(vec![Sexp::symbol("a")]).as_structural_kind(),
Some(StructuralKind::List)
);
assert_eq!(
Sexp::List(vec![Sexp::int(1), Sexp::int(2), Sexp::int(3)]).as_structural_kind(),
Some(StructuralKind::List)
);
}
#[test]
fn sexp_as_structural_kind_rejects_non_structural_outer_shapes() {
// KERNEL CONTRACT: pin that `Sexp::as_structural_kind()`
// returns `None` for every non-structural outer shape — every
// `Sexp::Atom` variant (the atomic-payload carving) AND every
// quote-family wrapper (the quote-family carving). Sweeps
// every non-residual arm so a regression that accepts an atom
// (e.g. routes `Sexp::Atom(_)` to `Some(List)` because the
// outer arm is misread as a "container" of an atomic payload)
// or a quote-family wrapper (e.g. routes `Sexp::Quote(_)`
// through `_ => Some(_)` because the residual match falls
// through) fails loudly. Sibling-cohort sweep to
// `sexp_as_atom_projects_inner_atom_iff_outer_is_atom_variant`
// — that test pins the atomic-projection kernel, this one
// pins the structural-residual kernel.
for outer in [
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("x"))),
] {
assert_eq!(
outer.as_structural_kind(),
None,
"Sexp::as_structural_kind must reject non-structural outer shape {outer:?}",
);
}
}
#[test]
fn sexp_as_structural_kind_agrees_with_shape_as_structural_kind_for_every_variant() {
// COMPOSITION-LAW CONTRACT: `s.as_structural_kind() ==
// s.shape().as_structural_kind()` for every reachable Sexp
// outer shape. The value-level projection and the shape-level
// projection MUST agree bit-for-bit — the substrate's
// (Sexp value, StructuralKind marker) pairing binds at TWO
// typed methods (one on `Sexp`, one on `SexpShape`) that must
// stay in lockstep. Sweeps every outer shape (residual + atom
// + quote-family) so a drift on ANY arm surfaces immediately.
// Sibling-shape pin to the (Sexp → SexpShape → label) path-
// uniformity test
// `sexp_shape_method_label_composes_with_sexp_type_name_for_every_outer_shape`
// — where that test pins the label-projection composition,
// this one pins the structural-carving-marker projection
// composition.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.as_structural_kind(),
s.shape().as_structural_kind(),
"Sexp::as_structural_kind and Sexp::shape().as_structural_kind must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_structural_kind_partitions_outer_shapes_jointly_with_as_atom_and_as_quote_form() {
// PARTITION-TOTAL CONTRACT (value-level): pin that for every
// reachable Sexp outer shape, EXACTLY ONE of `as_atom`,
// `as_quote_form`, `as_structural_kind` returns `Some(_)`.
// Post-lift the three carving-marker projections at the value
// level form a partition of the `Sexp` variant algebra —
// symmetric with the partition-total invariant pinned at the
// shape level by
// `sexp_shape_partition_is_total_across_atom_quote_structural_carvings`
// (in `error.rs`). A regression that drifts any carving's
// membership (an `as_atom` arm that accepts a non-atom, an
// `as_quote_form` arm that misses a quote-family wrapper, an
// `as_structural_kind` arm that swaps its Nil/List
// membership) surfaces here immediately, so the value-level
// partition invariant is a TYPED THEOREM (rustc-enforced
// exhaustiveness through the joint sweep) rather than a
// runtime `matches!` assertion.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
let hits = [
s.as_atom().is_some(),
s.as_quote_form().is_some(),
s.as_structural_kind().is_some(),
];
let hit_count: usize = hits.iter().filter(|b| **b).count();
assert_eq!(
hit_count, 1,
"value-level carvings must partition Sexp variants — {s:?} matched {hit_count} carvings (as_atom/as_quote_form/as_structural_kind = {hits:?})",
);
}
}
#[test]
fn sexp_as_structural_kind_composes_with_label_via_structural_kind_label() {
// CROSS-PROJECTION COHERENCE: pin that
// `s.as_structural_kind().map(StructuralKind::label)` agrees
// with `s.shape().label()` for every residual-carving Sexp
// (and returns `None` for every non-residual Sexp). Composes
// the new value-level projection with the closed-set
// `StructuralKind::label` projection (which itself composes
// through `sexp_shape().label()`) so the label vocabulary
// stays load-bearing at ONE canonical site
// (`SexpShape::label`) rather than a parallel per-projection
// literal table.
let residual = [
(Sexp::Nil, "nil"),
(Sexp::List(vec![]), "list"),
(Sexp::List(vec![Sexp::symbol("a")]), "list"),
];
for (sexp, expected_label) in &residual {
let via_carving = sexp.as_structural_kind().map(StructuralKind::label);
assert_eq!(
via_carving,
Some(*expected_label),
"structural-carving-marker label drifted at {sexp:?}"
);
assert_eq!(
via_carving,
Some(sexp.shape().label()),
"as_structural_kind.map(label) must equal shape().label() for residual sample {sexp:?}"
);
}
for non_residual in [
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
] {
assert_eq!(
non_residual.as_structural_kind().map(StructuralKind::label),
None,
"non-residual Sexp must project to None on as_structural_kind.map(label) — {non_residual:?}"
);
}
}
#[test]
fn sexp_as_atom_kind_projects_each_atom_variant_to_canonical_atom_kind() {
// PER-VARIANT TRUTH-TABLE (atomic axis): pin byte-for-byte per-
// Sexp-atom-arm mapping — Symbol payload → Some(AtomKind::Symbol),
// Keyword payload → Some(AtomKind::Keyword), Str payload →
// Some(AtomKind::Str), Int payload → Some(AtomKind::Int), Float
// payload → Some(AtomKind::Float), Bool payload →
// Some(AtomKind::Bool). Value-level peer of the shape-level
// sweep `as_atom_kind_projects_each_atom_shape_to_canonical_atom_kind_and_rejects_non_atom_shapes`
// in error.rs — each atomic Sexp value's carving-marker
// projection must land on the matching AtomKind arm the shape-
// level projection lands on. A future thirteenth Atom variant
// extends both this sweep + the composition body via the
// as_atom + Atom::kind primitives, with rustc enforcing the
// match arms in lockstep.
assert_eq!(Sexp::symbol("foo").as_atom_kind(), Some(AtomKind::Symbol));
assert_eq!(Sexp::keyword("k").as_atom_kind(), Some(AtomKind::Keyword));
assert_eq!(Sexp::string("s").as_atom_kind(), Some(AtomKind::Str));
assert_eq!(Sexp::int(7).as_atom_kind(), Some(AtomKind::Int));
assert_eq!(Sexp::float(7.5).as_atom_kind(), Some(AtomKind::Float));
assert_eq!(Sexp::boolean(true).as_atom_kind(), Some(AtomKind::Bool));
// Empty-payload edge cases (empty-string vs Symbol vs Keyword)
// — pin the projection ignores payload content entirely (it
// reads only the outer variant discriminant), so a body that
// gates on payload emptiness fails loudly.
assert_eq!(Sexp::symbol("").as_atom_kind(), Some(AtomKind::Symbol));
assert_eq!(Sexp::string("").as_atom_kind(), Some(AtomKind::Str));
}
#[test]
fn sexp_as_atom_kind_rejects_non_atom_outer_shapes() {
// KERNEL: every non-atom outer shape (Nil, List, every quote-
// family wrapper) projects to `None`. Sibling kernel-pin to
// `sexp_as_structural_kind_rejects_non_structural_outer_shapes`
// on the residual axis. Together the two kernel pins bracket
// the atomic-carving membership from BOTH sides of the
// partition — the atomic-arm membership from
// `sexp_as_atom_kind_projects_each_atom_variant_to_canonical_atom_kind`
// and the non-atomic-arm kernel from THIS test.
for non_atom in [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
] {
assert_eq!(
non_atom.as_atom_kind(),
None,
"non-atom Sexp must project to None on as_atom_kind — {non_atom:?}"
);
}
}
#[test]
fn sexp_as_atom_kind_agrees_with_as_atom_map_kind_for_every_variant() {
// COMPOSITION-LAW CONTRACT (atomic-axis peer of the shape-
// agreement law): `s.as_atom_kind() == s.as_atom().map(Atom::kind)`
// for every reachable Sexp outer shape. Pre-lift the atomic
// carving marker at the value level was reachable via this
// two-step composition through the Atom algebra; post-lift the
// new projection MUST agree bit-for-bit — the substrate's
// (Sexp value, AtomKind marker) pairing binds at TWO
// compositions (this Atom-axis composition AND the shape-axis
// composition pinned by the sibling test below) that must stay
// in lockstep. Sweeps every outer shape (atom + residual +
// quote-family) so a drift on ANY arm surfaces immediately.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.as_atom_kind(),
s.as_atom().map(Atom::kind),
"Sexp::as_atom_kind and Sexp::as_atom().map(Atom::kind) must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_atom_kind_agrees_with_shape_as_atom_kind_for_every_variant() {
// COMPOSITION-LAW CONTRACT (shape-axis peer): `s.as_atom_kind()
// == s.shape().as_atom_kind()` for every reachable Sexp outer
// shape. Sibling to
// `sexp_as_structural_kind_agrees_with_shape_as_structural_kind_for_every_variant`
// on the atomic axis. Pre-lift the atomic carving marker at
// the value level was reachable via this two-step composition
// through the shape algebra; post-lift the new projection MUST
// agree bit-for-bit — the substrate's (Sexp value, AtomKind
// marker) pairing binds at THREE typed methods (Sexp::as_atom_kind,
// Sexp::as_atom + Atom::kind composition, Sexp::shape +
// SexpShape::as_atom_kind composition) that must ALL stay in
// lockstep.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.as_atom_kind(),
s.shape().as_atom_kind(),
"Sexp::as_atom_kind and Sexp::shape().as_atom_kind must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_atom_kind_partitions_outer_shapes_jointly_with_as_quote_form_and_as_structural_kind()
{
// PARTITION-TOTAL CONTRACT (value-level, marker-only axis):
// pin that for every reachable Sexp outer shape, EXACTLY ONE
// of `as_atom_kind`, `as_quote_form`, `as_structural_kind`
// returns `Some(_)`. Post-lift ALL THREE carving-marker
// projections at the value level form a partition of the
// `Sexp` variant algebra using ONLY the marker-only siblings —
// symmetric with the shape-level partition-total invariant
// pinned by
// `sexp_shape_partition_is_total_across_atom_quote_structural_carvings`
// (in error.rs). The pre-existing value-level partition pin
// `sexp_as_structural_kind_partitions_outer_shapes_jointly_with_as_atom_and_as_quote_form`
// uses `as_atom().is_some()` on the atomic axis (the
// structural-lift projection); THIS pin uses `as_atom_kind()
// .is_some()` (the marker-only projection). Both partition
// invariants must hold — they pin the atomic axis's TWO
// value-level projections (structural + marker) as jointly
// partition-consistent with the residual and quote-family
// siblings. A regression that drifts any carving's
// marker-only membership (an `as_atom_kind` arm that accepts
// a non-atom, an `as_quote_form` arm that misses a quote-
// family wrapper, an `as_structural_kind` arm that swaps its
// Nil/List membership) surfaces here immediately.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
let hits = [
s.as_atom_kind().is_some(),
s.as_quote_form().is_some(),
s.as_structural_kind().is_some(),
];
let hit_count: usize = hits.iter().filter(|b| **b).count();
assert_eq!(
hit_count, 1,
"value-level marker-only carvings must partition Sexp variants — {s:?} matched {hit_count} carvings (as_atom_kind/as_quote_form/as_structural_kind = {hits:?})",
);
}
}
#[test]
fn sexp_as_atom_kind_composes_with_label_via_atom_kind_label() {
// CROSS-PROJECTION COHERENCE: pin that
// `s.as_atom_kind().map(AtomKind::label)` agrees with
// `s.shape().label()` for every atomic Sexp (and returns
// `None` for every non-atomic Sexp). Sibling to
// `sexp_as_structural_kind_composes_with_label_via_structural_kind_label`
// on the atomic axis. Composes the new value-level marker
// projection with the closed-set `AtomKind::label` projection
// (which itself composes through `sexp_shape().label()`) so
// the label vocabulary stays load-bearing at ONE canonical
// site (`SexpShape::label`) rather than a parallel per-
// projection literal table.
let atomic = [
(Sexp::symbol("foo"), "symbol"),
(Sexp::keyword("k"), "keyword"),
(Sexp::string("s"), "string"),
(Sexp::int(7), "int"),
(Sexp::float(7.5), "float"),
(Sexp::boolean(true), "bool"),
];
for (sexp, expected_label) in &atomic {
let via_carving = sexp.as_atom_kind().map(AtomKind::label);
assert_eq!(
via_carving,
Some(*expected_label),
"atomic-carving-marker label drifted at {sexp:?}"
);
assert_eq!(
via_carving,
Some(sexp.shape().label()),
"as_atom_kind.map(label) must equal shape().label() for atomic sample {sexp:?}"
);
}
for non_atomic in [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
] {
assert_eq!(
non_atomic.as_atom_kind().map(AtomKind::label),
None,
"non-atomic Sexp must project to None on as_atom_kind.map(label) — {non_atomic:?}"
);
}
}
#[test]
fn sexp_as_unquote_form_projects_each_variant_to_canonical_unquote_form() {
// PER-VARIANT TRUTH-TABLE (unquote-subset axis): pin byte-for-
// byte per-Sexp-substitution-arm mapping — `Sexp::Unquote(inner)`
// → `Some(UnquoteForm::Unquote)`, `Sexp::UnquoteSplice(inner)`
// → `Some(UnquoteForm::Splice)`. Value-level peer of the shape-
// level sweep
// `as_unquote_form_projects_each_unquote_shape_to_canonical_unquote_form_and_rejects_non_unquote_shapes`
// in error.rs — each substitution-wrapper Sexp value's carving-
// marker projection must land on the matching UnquoteForm arm
// the shape-level projection lands on. A future third UnquoteForm
// variant (e.g. `,~` reverse-unquote) extends both this sweep +
// the composition body via the as_unquote + QuoteForm::as_unquote_form
// primitives, with rustc enforcing the match arms in lockstep.
assert_eq!(
Sexp::Unquote(Box::new(Sexp::symbol("x"))).as_unquote_form(),
Some(UnquoteForm::Unquote)
);
assert_eq!(
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))).as_unquote_form(),
Some(UnquoteForm::Splice)
);
// Inner-payload invariance edge cases — pin the projection
// ignores inner payload content entirely (it reads only the
// outer wrapper variant discriminant), so a body that gates on
// inner payload shape fails loudly.
assert_eq!(
Sexp::Unquote(Box::new(Sexp::Nil)).as_unquote_form(),
Some(UnquoteForm::Unquote)
);
assert_eq!(
Sexp::UnquoteSplice(Box::new(Sexp::List(vec![]))).as_unquote_form(),
Some(UnquoteForm::Splice)
);
assert_eq!(
Sexp::Unquote(Box::new(Sexp::List(vec![
Sexp::symbol("nested"),
Sexp::int(42),
])))
.as_unquote_form(),
Some(UnquoteForm::Unquote)
);
}
#[test]
fn sexp_as_unquote_form_rejects_non_unquote_subset_outer_shapes() {
// KERNEL: every non-unquote-subset outer shape (Nil, every Atom
// variant, List, AND the two non-substitution quote-family
// wrappers `Sexp::Quote` and `Sexp::Quasiquote`) projects to
// `None`. Sibling kernel-pin to
// `sexp_as_atom_kind_rejects_non_atom_outer_shapes` and
// `sexp_as_structural_kind_rejects_non_structural_outer_shapes`
// on the substitution axis. The two non-substitution quote-
// family wrappers ARE quote-family (`as_quote_form` accepts
// them) but NOT substitution-subset (`as_unquote_form` must
// reject them) — pin the 2-of-4 subset gate operates at the
// value level exactly as the shape-level
// `QuoteForm::as_unquote_form` gate operates on the closed-set
// marker enum.
for non_unquote in [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
] {
assert_eq!(
non_unquote.as_unquote_form(),
None,
"non-substitution-subset Sexp must project to None on as_unquote_form — {non_unquote:?}"
);
}
}
#[test]
fn sexp_as_unquote_form_agrees_with_as_unquote_map_marker_for_every_variant() {
// COMPOSITION-LAW CONTRACT (parent-projection peer): pin
// `s.as_unquote_form() == s.as_unquote().map(|(uf, _)| uf)` for
// every reachable Sexp outer shape. Pre-lift the substitution
// carving marker at the value level was reachable via this
// two-step composition through the parent [`Sexp::as_unquote`]
// projection (discarding the wrapped inner); post-lift the new
// marker-only projection MUST agree bit-for-bit — the
// substrate's (Sexp value, UnquoteForm marker) pairing binds at
// FOUR compositions (this parent-projection composition AND the
// shape-axis composition AND the quote-family + subset-gate
// composition, all pinned by the sibling tests below) that must
// stay in lockstep. Sweeps every outer shape (atom + residual +
// quote-family) so a drift on ANY arm surfaces immediately.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.as_unquote_form(),
s.as_unquote().map(|(uf, _)| uf),
"Sexp::as_unquote_form and Sexp::as_unquote().map(|(uf, _)| uf) must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_unquote_form_agrees_with_shape_as_unquote_form_for_every_variant() {
// COMPOSITION-LAW CONTRACT (shape-axis peer): `s.as_unquote_form()
// == s.shape().as_unquote_form()` for every reachable Sexp outer
// shape. Sibling to
// `sexp_as_atom_kind_agrees_with_shape_as_atom_kind_for_every_variant`
// and
// `sexp_as_structural_kind_agrees_with_shape_as_structural_kind_for_every_variant`
// on the substitution axis. Pre-lift the substitution carving
// marker at the value level was reachable via this two-step
// composition through the shape algebra; post-lift the new
// projection MUST agree bit-for-bit — the substrate's (Sexp
// value, UnquoteForm marker) pairing binds at FOUR typed methods
// (Sexp::as_unquote_form, Sexp::as_unquote + `|(uf, _)| uf`
// composition, Sexp::shape + SexpShape::as_unquote_form
// composition, Sexp::as_quote_form +
// QuoteForm::as_unquote_form composition) that must ALL stay
// in lockstep.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.as_unquote_form(),
s.shape().as_unquote_form(),
"Sexp::as_unquote_form and Sexp::shape().as_unquote_form must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_unquote_form_agrees_with_as_quote_form_and_quote_form_as_unquote_form_for_every_variant(
) {
// COMPOSITION-LAW CONTRACT (parent-family + subset-gate peer):
// pin `s.as_unquote_form() ==
// s.as_quote_form().and_then(|(qf, _)| qf.as_unquote_form())`
// for every reachable Sexp outer shape. Value-level peer of the
// shape-level route
// `as_unquote_form_routes_through_as_quote_form_and_quote_form_as_unquote_form_via_composition`
// in error.rs — where that test pins the shape-level
// `SexpShape::as_unquote_form` routes through the shape-level
// `SexpShape::as_quote_form` + `QuoteForm::as_unquote_form`
// subset gate, THIS test pins the value-level
// `Sexp::as_unquote_form` routes through the value-level
// `Sexp::as_quote_form` + the SAME subset gate. Pre-lift the
// substitution carving marker at the value level was reachable
// via this three-step composition through the parent quote-
// family projection [`Sexp::as_quote_form`] composed with the
// 2-of-4 subset gate [`QuoteForm::as_unquote_form`]; post-lift
// the new marker-only projection MUST agree bit-for-bit — the
// subset-gate composition (which the pre-existing
// [`Sexp::as_unquote`] projection ALSO routes through, per its
// body `let (qf, inner) = self.as_quote_form()?;
// qf.as_unquote_form().map(|uf| (uf, inner))`) must land the
// same marker as the new value-level projection.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.as_unquote_form(),
s.as_quote_form().and_then(|(qf, _)| qf.as_unquote_form()),
"Sexp::as_unquote_form and Sexp::as_quote_form().and_then(|(qf, _)| qf.as_unquote_form()) must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_unquote_form_composes_with_marker_via_unquote_form_marker() {
// CROSS-PROJECTION COHERENCE: pin that
// `s.as_unquote_form().map(UnquoteForm::marker)` agrees with
// `s.shape().label()` for every substitution-subset Sexp (and
// returns `None` for every non-substitution-subset Sexp).
// Sibling to `sexp_as_atom_kind_composes_with_label_via_atom_kind_label`
// on the substitution axis. Composes the new value-level
// marker projection with the closed-set `UnquoteForm::marker`
// projection (which itself composes through
// `to_quote_form().prefix()` — see `UnquoteForm::marker`'s
// docstring for the composition route) so the marker vocabulary
// (`","` / `",@"`) stays load-bearing at ONE canonical site
// (`QuoteForm::prefix`'s Unquote/UnquoteSplice arms) rather
// than a parallel per-projection literal table.
//
// Note: `UnquoteForm::marker` returns the READER prefix (`,` or
// `,@`) which is ALSO the canonical `SexpShape::label` for the
// Unquote / UnquoteSplice arms — the shape-label vocabulary
// was pinned to the reader-prefix vocabulary in the
// `SexpShape::label` truth-table (Unquote → "unquote",
// UnquoteSplice → "unquote-splice"). This test uses
// `UnquoteForm::marker` = reader prefix directly (`,` /
// `,@`), NOT the shape label — the two are distinct
// vocabularies, both derived from the closed-set carving
// marker, both stable across the lift.
let substitution = [
(
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
UnquoteForm::Unquote,
),
(
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
UnquoteForm::Splice,
),
];
for (sexp, expected_uf) in &substitution {
let via_carving = sexp.as_unquote_form().map(UnquoteForm::marker);
assert_eq!(
via_carving,
Some(expected_uf.marker()),
"substitution-carving-marker string drifted at {sexp:?}"
);
}
for non_substitution in [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
] {
assert_eq!(
non_substitution.as_unquote_form().map(UnquoteForm::marker),
None,
"non-substitution-subset Sexp must project to None on as_unquote_form.map(marker) — {non_substitution:?}"
);
}
}
#[test]
fn sexp_as_unquote_form_narrows_as_quote_form_to_substitution_subset() {
// SUBSET-GATE CONTRACT (value-level): pin that at every
// reachable Sexp outer shape, `as_unquote_form().is_some()`
// implies `as_quote_form().is_some()` (subset containment) AND
// `as_quote_form().is_some() && !as_unquote_form().is_some()`
// holds exactly for the two non-substitution quote-family
// wrappers (`Sexp::Quote` and `Sexp::Quasiquote`) — the 2-of-4
// subset gate at the VALUE level, symmetric with the shape-
// level subset gate pinned by the sibling
// `QuoteForm::as_unquote_form` truth-table in error.rs. Pins the
// (substitution-subset ⊂ quote-family) inclusion as an invariant
// on the value algebra so a regression that widens
// `as_unquote_form` beyond its 2-of-4 subset (e.g. an emitter
// that starts accepting `Sexp::Quote` as substitution) surfaces
// immediately as a subset-inclusion drift.
let samples = [
(Sexp::Nil, false, false),
(Sexp::List(vec![]), false, false),
(Sexp::List(vec![Sexp::symbol("a")]), false, false),
(Sexp::symbol("foo"), false, false),
(Sexp::keyword("k"), false, false),
(Sexp::string("s"), false, false),
(Sexp::int(7), false, false),
(Sexp::float(7.5), false, false),
(Sexp::boolean(true), false, false),
// Quote-family, NOT substitution-subset
(Sexp::Quote(Box::new(Sexp::Nil)), true, false),
(Sexp::Quasiquote(Box::new(Sexp::Nil)), true, false),
// Quote-family AND substitution-subset
(Sexp::Unquote(Box::new(Sexp::Nil)), true, true),
(Sexp::UnquoteSplice(Box::new(Sexp::Nil)), true, true),
];
for (s, quote_expected, unquote_expected) in &samples {
let quote_hit = s.as_quote_form().is_some();
let unquote_hit = s.as_unquote_form().is_some();
assert_eq!(
quote_hit, *quote_expected,
"as_quote_form membership drifted at {s:?}"
);
assert_eq!(
unquote_hit, *unquote_expected,
"as_unquote_form membership drifted at {s:?}"
);
// Subset containment: substitution ⊂ quote-family.
assert!(
!unquote_hit || quote_hit,
"subset containment violated at {s:?}: as_unquote_form Some but as_quote_form None",
);
}
}
#[test]
fn sexp_as_quote_form_marker_projects_each_variant_to_canonical_quote_form() {
// PER-VARIANT TRUTH-TABLE (quote-family axis): pin byte-for-byte
// per-Sexp-quote-family-arm mapping — `Sexp::Quote(inner)`
// → `Some(QuoteForm::Quote)`, `Sexp::Quasiquote(inner)`
// → `Some(QuoteForm::Quasiquote)`, `Sexp::Unquote(inner)`
// → `Some(QuoteForm::Unquote)`, `Sexp::UnquoteSplice(inner)`
// → `Some(QuoteForm::UnquoteSplice)`. Value-level marker-only
// peer of the pre-existing tuple projection
// `Sexp::as_quote_form` — each quote-family-wrapper Sexp value's
// carving-marker projection must land on the matching QuoteForm
// arm the parent projection's tuple carries. A future fifth
// QuoteForm variant (e.g. `,~` reverse-unquote) extends both
// this sweep + the composition body via the as_quote_form
// primitive, with rustc enforcing the match arms in lockstep.
assert_eq!(
Sexp::Quote(Box::new(Sexp::symbol("x"))).as_quote_form_marker(),
Some(QuoteForm::Quote)
);
assert_eq!(
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))).as_quote_form_marker(),
Some(QuoteForm::Quasiquote)
);
assert_eq!(
Sexp::Unquote(Box::new(Sexp::symbol("x"))).as_quote_form_marker(),
Some(QuoteForm::Unquote)
);
assert_eq!(
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))).as_quote_form_marker(),
Some(QuoteForm::UnquoteSplice)
);
// Inner-payload invariance edge cases — pin the projection
// ignores inner payload content entirely (it reads only the
// outer wrapper variant discriminant), so a body that gates on
// inner payload shape fails loudly.
assert_eq!(
Sexp::Quote(Box::new(Sexp::Nil)).as_quote_form_marker(),
Some(QuoteForm::Quote)
);
assert_eq!(
Sexp::Quasiquote(Box::new(Sexp::List(vec![]))).as_quote_form_marker(),
Some(QuoteForm::Quasiquote)
);
assert_eq!(
Sexp::Unquote(Box::new(Sexp::List(vec![
Sexp::symbol("nested"),
Sexp::int(42),
])))
.as_quote_form_marker(),
Some(QuoteForm::Unquote)
);
assert_eq!(
Sexp::UnquoteSplice(Box::new(Sexp::Quote(Box::new(Sexp::symbol("y")))))
.as_quote_form_marker(),
Some(QuoteForm::UnquoteSplice)
);
}
#[test]
fn sexp_as_quote_form_marker_rejects_non_quote_family_outer_shapes() {
// KERNEL: every non-quote-family outer shape (Nil, every Atom
// variant, List — empty and non-empty) projects to `None`.
// Sibling kernel-pin to
// `sexp_as_atom_kind_rejects_non_atom_outer_shapes`,
// `sexp_as_structural_kind_rejects_non_structural_outer_shapes`,
// and `sexp_as_unquote_form_rejects_non_unquote_subset_outer_shapes`
// on the quote-family axis. A body that widens the projection to
// any non-quote-family arm (e.g. `Sexp::List` starts returning
// `Some(QuoteForm::Quote)`) surfaces as a `None` expectation
// failure at the specific offending variant.
for non_quote in [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::List(vec![Sexp::symbol("a"), Sexp::int(1)]),
] {
assert_eq!(
non_quote.as_quote_form_marker(),
None,
"non-quote-family Sexp must project to None on as_quote_form_marker — {non_quote:?}"
);
}
}
#[test]
fn sexp_as_quote_form_marker_agrees_with_as_quote_form_map_marker_for_every_variant() {
// COMPOSITION-LAW CONTRACT (parent-projection peer): pin
// `s.as_quote_form_marker() == s.as_quote_form().map(|(qf, _)| qf)`
// for every reachable Sexp outer shape. Pre-lift the quote-
// family carving marker at the value level was reachable via
// this two-step composition through the parent
// [`Sexp::as_quote_form`] projection (discarding the wrapped
// inner via `.map(|(qf, _)| qf)`); post-lift the new marker-
// only projection MUST agree bit-for-bit — the substrate's
// (Sexp value, QuoteForm marker) pairing binds at THREE
// compositions (this parent-projection composition AND the
// shape-axis composition, both pinned in this module, AND the
// direct match in the new method's body) that must stay in
// lockstep. Sweeps every outer shape (atom + residual +
// quote-family) so a drift on ANY arm surfaces immediately.
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.as_quote_form_marker(),
s.as_quote_form().map(|(qf, _)| qf),
"Sexp::as_quote_form_marker and Sexp::as_quote_form().map(|(qf, _)| qf) must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_quote_form_marker_agrees_with_shape_as_quote_form_for_every_variant() {
// COMPOSITION-LAW CONTRACT (shape-axis peer):
// `s.as_quote_form_marker() == s.shape().as_quote_form()` for
// every reachable Sexp outer shape. Sibling to
// `sexp_as_atom_kind_agrees_with_shape_as_atom_kind_for_every_variant`,
// `sexp_as_structural_kind_agrees_with_shape_as_structural_kind_for_every_variant`,
// and `sexp_as_unquote_form_agrees_with_shape_as_unquote_form_for_every_variant`
// on the quote-family axis. Pre-lift the quote-family carving
// marker at the value level was reachable via this two-step
// composition through the shape algebra (`shape().as_quote_form()`,
// walking the full 12-variant [`SexpShape`](crate::error::SexpShape)
// closed set to arrive at the 4-of-12 carving marker); post-
// lift the new projection MUST agree bit-for-bit — the
// substrate's (Sexp value, QuoteForm marker) pairing now binds
// at ONE typed method on the value algebra, with both
// compositions (this shape-axis peer and the parent-projection
// peer pinned above) staying in lockstep.
use crate::error::SexpShape;
let samples = [
Sexp::Nil,
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
let via_value: Option<QuoteForm> = s.as_quote_form_marker();
let via_shape: Option<QuoteForm> = SexpShape::as_quote_form(s.shape());
assert_eq!(
via_value, via_shape,
"Sexp::as_quote_form_marker and Sexp::shape().as_quote_form must agree at {s:?}",
);
}
}
#[test]
fn sexp_as_quote_form_marker_composes_with_prefix_via_quote_form_prefix() {
// CROSS-PROJECTION COHERENCE: pin that
// `s.as_quote_form_marker().map(QuoteForm::prefix)` agrees with
// the reader-prefix vocabulary carried on [`QuoteForm::prefix`]
// for every quote-family Sexp (and returns `None` for every
// non-quote-family Sexp). Sibling to
// `sexp_as_unquote_form_composes_with_marker_via_unquote_form_marker`
// on the quote-family axis. Composes the new value-level marker
// projection with the closed-set [`QuoteForm::prefix`]
// projection so the reader/writer prefix vocabulary (`'` / `` ` ``
// / `,` / `,@`) stays load-bearing at ONE canonical site
// ([`QuoteForm::prefix`]'s four arms) rather than a parallel
// per-projection literal table on the value algebra.
let quote_family = [
(Sexp::Quote(Box::new(Sexp::symbol("x"))), QuoteForm::Quote),
(
Sexp::Quasiquote(Box::new(Sexp::symbol("x"))),
QuoteForm::Quasiquote,
),
(
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
QuoteForm::Unquote,
),
(
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
QuoteForm::UnquoteSplice,
),
];
for (sexp, expected_qf) in "e_family {
let via_carving = sexp.as_quote_form_marker().map(QuoteForm::prefix);
assert_eq!(
via_carving,
Some(expected_qf.prefix()),
"quote-family carving-marker prefix drifted at {sexp:?}"
);
}
for non_quote in [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("a")]),
] {
assert_eq!(
non_quote.as_quote_form_marker().map(QuoteForm::prefix),
None,
"non-quote-family Sexp must project to None on as_quote_form_marker.map(prefix) — {non_quote:?}"
);
}
}
#[test]
fn sexp_as_quote_form_marker_extends_as_unquote_form_to_full_quote_family() {
// SUPERSET-GATE CONTRACT (value-level): pin that at every
// reachable Sexp outer shape,
// `as_unquote_form().is_some()` implies
// `as_quote_form_marker().is_some()` (the 2-of-12 substitution
// subset is a proper subset of the 4-of-12 quote family) AND
// `as_quote_form_marker().is_some() && !as_unquote_form().is_some()`
// holds exactly for the two non-substitution quote-family
// wrappers (`Sexp::Quote` and `Sexp::Quasiquote`) — the value-
// level image of the 2-of-4 subset gate
// [`QuoteForm::as_unquote_form`], mirroring
// `sexp_as_unquote_form_narrows_as_quote_form_to_substitution_subset`
// from the substitution-axis side. Pins the (substitution-
// subset ⊂ quote-family) inclusion as an invariant on the
// value algebra where the SUPERSET side is now a NAMED typed
// method — so a regression that widens either projection
// beyond its cell (e.g. `as_quote_form_marker` starts accepting
// `Sexp::List`, or `as_unquote_form` starts accepting
// `Sexp::Quote`) surfaces immediately as a subset-inclusion
// drift. Also pin that
// `as_unquote_form() == as_quote_form_marker().and_then(
// QuoteForm::as_unquote_form)` — the value-level projection
// composes with the 2-of-4 subset gate at the marker algebra
// level, so the substrate's (Sexp value, UnquoteForm marker)
// pairing derives from the (Sexp value, QuoteForm marker)
// pairing at ONE composition rather than two parallel value-
// level projections.
let samples = [
(Sexp::Nil, false, false),
(Sexp::List(vec![]), false, false),
(Sexp::List(vec![Sexp::symbol("a")]), false, false),
(Sexp::symbol("foo"), false, false),
(Sexp::keyword("k"), false, false),
(Sexp::string("s"), false, false),
(Sexp::int(7), false, false),
(Sexp::float(7.5), false, false),
(Sexp::boolean(true), false, false),
// Quote-family, NOT substitution-subset
(Sexp::Quote(Box::new(Sexp::Nil)), true, false),
(Sexp::Quasiquote(Box::new(Sexp::Nil)), true, false),
// Quote-family AND substitution-subset
(Sexp::Unquote(Box::new(Sexp::Nil)), true, true),
(Sexp::UnquoteSplice(Box::new(Sexp::Nil)), true, true),
];
for (s, quote_expected, unquote_expected) in &samples {
let quote_hit = s.as_quote_form_marker().is_some();
let unquote_hit = s.as_unquote_form().is_some();
assert_eq!(
quote_hit, *quote_expected,
"as_quote_form_marker membership drifted at {s:?}"
);
assert_eq!(
unquote_hit, *unquote_expected,
"as_unquote_form membership drifted at {s:?}"
);
// Superset containment: substitution ⊂ quote-family.
assert!(
!unquote_hit || quote_hit,
"subset containment violated at {s:?}: as_unquote_form Some but as_quote_form_marker None",
);
// Composition through the 2-of-4 subset gate:
// `s.as_unquote_form() == s.as_quote_form_marker().and_then(QuoteForm::as_unquote_form)`.
assert_eq!(
s.as_unquote_form(),
s.as_quote_form_marker()
.and_then(QuoteForm::as_unquote_form),
"as_unquote_form and as_quote_form_marker + QuoteForm::as_unquote_form composition disagree at {s:?}",
);
}
}
#[test]
fn sexp_shape_method_label_composes_with_sexp_type_name_for_every_outer_shape() {
// COMPOSITION-LAW CONTRACT: `s.shape().label() ==
// crate::domain::sexp_type_name(&s)` for every reachable Sexp
// outer shape. Post-lift `sexp_type_name` routes through
// `s.shape().label()` directly (no longer through the free-
// function `sexp_shape`). Pin the composition law so a future
// refactor that drifts either projection (e.g. a label typo
// in `SexpShape::label`, a change in `sexp_type_name`'s
// delegation) surfaces here immediately.
let samples = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.shape().label(),
crate::domain::sexp_type_name(s),
"Sexp::shape().label() must equal domain::sexp_type_name for {s:?}",
);
}
}
#[test]
fn sexp_type_name_method_projects_each_outer_arm_to_canonical_label() {
// PER-ARM CONTRACT: pin that the inherent `Sexp::type_name()`
// method projects each reachable outer Sexp shape to its
// canonical `&'static str` label. Pre-lift the projection
// lived as a free function `domain::sexp_type_name`; post-
// lift the canonical site is the inherent method on the
// `Sexp` algebra and the free function delegates. A
// regression that drifts a per-arm label (e.g. a typo in
// `SexpShape::label`, a stale arm in `Sexp::shape`'s match,
// a change in the body away from `self.shape().label()`)
// surfaces here immediately. Sweeps every outer shape and
// every atomic payload kind so all 8 `SexpShape` variants
// are covered.
assert_eq!(Sexp::Nil.type_name(), "nil");
assert_eq!(Sexp::symbol("foo").type_name(), "symbol");
assert_eq!(Sexp::keyword("k").type_name(), "keyword");
assert_eq!(Sexp::string("s").type_name(), "string");
assert_eq!(Sexp::int(7).type_name(), "int");
assert_eq!(Sexp::float(7.5).type_name(), "float");
assert_eq!(Sexp::boolean(true).type_name(), "bool");
assert_eq!(Sexp::List(vec![]).type_name(), "list");
assert_eq!(Sexp::Quote(Box::new(Sexp::Nil)).type_name(), "quote");
assert_eq!(
Sexp::Quasiquote(Box::new(Sexp::Nil)).type_name(),
"quasiquote",
);
assert_eq!(Sexp::Unquote(Box::new(Sexp::Nil)).type_name(), "unquote");
assert_eq!(
Sexp::UnquoteSplice(Box::new(Sexp::Nil)).type_name(),
"unquote-splice",
);
}
#[test]
fn sexp_type_name_method_composes_through_shape_label_for_every_outer_shape() {
// COMPOSITION-LAW CONTRACT: `s.type_name() == s.shape().label()`
// for every reachable Sexp outer shape — the method body is
// structurally derived through `Self::shape` + `SexpShape::label`
// rather than re-matching `Sexp` arms directly. Pin the
// composition law so a future refactor that re-inlines the
// match (and gains its own drift surface) surfaces here
// immediately. Sibling-shape pin to the existing
// `sexp_shape_method_label_composes_with_sexp_type_name_for_every_outer_shape`
// pin (which pins the inverse direction: the free function
// routes through the inherent method).
let samples = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::List(vec![]),
Sexp::Quote(Box::new(Sexp::Nil)),
Sexp::Quasiquote(Box::new(Sexp::Nil)),
Sexp::Unquote(Box::new(Sexp::Nil)),
Sexp::UnquoteSplice(Box::new(Sexp::Nil)),
];
for s in &samples {
assert_eq!(
s.type_name(),
s.shape().label(),
"Sexp::type_name() must compose through Sexp::shape().label() for {s:?}",
);
}
}
#[test]
fn sexp_type_name_method_agrees_with_domain_sexp_type_name_for_every_outer_shape() {
// LIFTED-BOUNDARY CONTRACT: pin that the inherent
// `Sexp::type_name()` method agrees with the free-function
// delegate `crate::domain::sexp_type_name` for every
// reachable outer shape. Pre-lift the dispatcher lived as a
// free function in `domain.rs`; post-lift the canonical site
// is the inherent method on the `Sexp` algebra and the free
// function is a one-line delegate. Pin that the delegation
// stays byte-for-byte equivalent across every outer arm so
// a regression where the free function drifts from the
// inherent method (or vice versa) surfaces here immediately.
// Mirrors `sexp_witness_method_agrees_with_domain_sexp_witness_for_every_outer_shape`
// for the canonical-label-only peer projection.
let samples = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::int(-1),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::boolean(false),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1), Sexp::int(2)]),
Sexp::Quote(Box::new(Sexp::symbol("payload"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![Sexp::symbol("foo")]))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
];
for s in &samples {
assert_eq!(
s.type_name(),
crate::domain::sexp_type_name(s),
"Sexp::type_name() must equal domain::sexp_type_name for {s:?}",
);
}
}
#[test]
fn sexp_witness_method_pairs_shape_with_display_for_every_outer_shape() {
// LIFTED-BOUNDARY CONTRACT: pin that the inherent
// `Sexp::witness()` method projects each reachable outer Sexp
// shape to a `SexpWitness` whose `shape` field equals
// `s.shape()` AND whose `display` field equals
// `s.to_string()` for every variant + payload combination.
// Pre-lift the projection lived as a free function in
// `domain.rs`; post-lift the canonical site is the inherent
// method on the `Sexp` algebra. A regression where the method
// drifts EITHER half of the joint identity (a stale `shape`
// projection that re-inlines without composing through
// `Sexp::shape`, a `display` projection that diverges from
// `Sexp::Display`) surfaces here immediately. Sweeps every
// outer shape, every atomic payload kind, and every
// quote-family wrapper.
let samples = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::int(-1),
Sexp::float(7.5),
Sexp::boolean(true),
Sexp::boolean(false),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1), Sexp::int(2)]),
Sexp::Quote(Box::new(Sexp::symbol("payload"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![Sexp::symbol("foo")]))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
];
for s in &samples {
let w = s.witness();
assert_eq!(
w.shape,
s.shape(),
"Sexp::witness().shape drifted from Sexp::shape() for {s:?}",
);
assert_eq!(
w.display,
s.to_string(),
"Sexp::witness().display drifted from Sexp::Display for {s:?}",
);
}
}
#[test]
fn sexp_witness_method_agrees_with_domain_sexp_witness_for_every_outer_shape() {
// LIFTED-BOUNDARY CONTRACT: pin that the inherent
// `Sexp::witness()` method agrees with the free-function
// delegate `crate::domain::sexp_witness` for every reachable
// outer shape. Pre-lift the dispatcher lived as a free
// function in `domain.rs`; post-lift the canonical site is
// the inherent method on the `Sexp` algebra and the free
// function is a one-line delegate. Pin that the delegation
// stays byte-for-byte equivalent across every outer arm so
// a regression where the free function drifts from the
// inherent method (or vice versa) surfaces here immediately.
// Mirrors `sexp_shape_method_agrees_with_domain_sexp_shape_for_every_outer_shape`
// for the joint-identity peer projection. Catches a future
// "consolidation" that removes the free function without
// updating the method, or vice versa.
let samples = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::int(-1),
Sexp::float(7.5),
Sexp::float(0.0),
Sexp::boolean(true),
Sexp::boolean(false),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1), Sexp::int(2)]),
Sexp::Quote(Box::new(Sexp::symbol("payload"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![Sexp::symbol("foo")]))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
];
for s in &samples {
let via_method = s.witness();
let via_delegate = crate::domain::sexp_witness(s);
assert_eq!(
via_method.shape, via_delegate.shape,
"Sexp::witness().shape drifted from domain::sexp_witness().shape at {s:?}",
);
assert_eq!(
via_method.display, via_delegate.display,
"Sexp::witness().display drifted from domain::sexp_witness().display at {s:?}",
);
}
}
#[test]
fn sexp_witness_method_routes_through_shape_and_display_projections() {
// PATH-UNIFORMITY CONTRACT: the lifted `Sexp::witness()` body
// composes the two algebra-level projections `Sexp::shape()`
// (structural identity) + `Sexp::Display` (renderable
// identity) into ONE `SexpWitness::new(shape, display)`
// value. Pin that the composition agrees bit-for-bit with
// the direct `SexpWitness::new(s.shape(), s.to_string())`
// construction across a sweep covering every outer shape.
// A regression in EITHER projection direction (a
// `Sexp::witness` arm that bypasses `Sexp::shape` and
// re-inlines the dispatch, a `Sexp::witness` arm that
// bypasses `Sexp::Display` and re-formats the literal) is
// structurally impossible — the typed joint primitive
// composes through the typed primitive halves once.
// Sibling shape to `sexp_shape_method_routes_atom_arm_through_atom_kind_sexp_shape_projection`
// for the joint-identity axis.
let samples = [
Sexp::Nil,
Sexp::symbol("x"),
Sexp::keyword("kw"),
Sexp::string("text"),
Sexp::int(0),
Sexp::float(2.5),
Sexp::boolean(true),
Sexp::List(vec![Sexp::symbol("f"), Sexp::int(1)]),
Sexp::Quote(Box::new(Sexp::symbol("q"))),
Sexp::Quasiquote(Box::new(Sexp::symbol("qq"))),
Sexp::Unquote(Box::new(Sexp::symbol("uq"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("uqs"))),
];
for s in &samples {
let via_method = s.witness();
let via_composed = crate::error::SexpWitness::new(s.shape(), s.to_string());
assert_eq!(
via_method.shape, via_composed.shape,
"Sexp::witness drifted shape from SexpWitness::new(s.shape(), s.to_string()) at {s:?}",
);
assert_eq!(
via_method.display, via_composed.display,
"Sexp::witness drifted display from SexpWitness::new(s.shape(), s.to_string()) at {s:?}",
);
}
}
#[test]
fn sexp_witness_distinguishes_int_atom_from_symbol_with_identical_display() {
// STRUCTURAL-IDENTITY CONTRACT: `Sexp::int(5)` and
// `Sexp::symbol("5")` Display-render identically (`"5"`) but
// are STRUCTURALLY DISTINCT — one is `SexpShape::Int`, the
// other is `SexpShape::Symbol`. Pin that `Sexp::witness()`
// carries the structural identity through the `shape` slot
// so the rejection diagnostic distinguishes the two even
// when the rendered literal collides. Mirrors the
// free-function-delegate sibling test
// `sexp_witness_distinguishes_int_atom_from_symbol_with_same_display`
// in `domain.rs::tests` — that test pins the delegate; this
// one pins the inherent method on the algebra. Both stay
// load-bearing across the lifted boundary.
let w_int = Sexp::int(5).witness();
let w_sym = Sexp::symbol("5").witness();
assert_eq!(
w_int.display, w_sym.display,
"display collision precondition"
);
assert_ne!(
w_int.shape, w_sym.shape,
"Sexp::witness must distinguish Int from Symbol via shape even when display collides",
);
assert_eq!(w_int.shape, crate::error::SexpShape::Int);
assert_eq!(w_sym.shape, crate::error::SexpShape::Symbol);
}
#[test]
fn sexp_as_x_family_routes_through_atom_as_x_for_every_atomic_variant() {
// LIFTED-BOUNDARY CONTRACT: pin that the six `Sexp::as_X`
// consumer-side projections equal the two-step composition
// `s.as_atom().and_then(Atom::as_X)` for every atomic payload
// variant. Pre-lift the six methods opened the same `Self::Atom
// (Atom::X(s)) => Some(s)` inline arm; post-lift they delegate
// through the typed projection family on the closed-set `Atom`
// algebra. A regression that drifts the outer arm (e.g. re-
// inlines one variant's match without updating the typed
// projection) surfaces as an inequality here. Sweeps every
// atomic variant + every consumer projection, AND pins the
// `Sexp::as_float` widening specialization (`Atom::Int(n)` →
// `Some(n as f64)`) lives at the consumer layer.
let cases: &[Atom] = &[
Atom::Symbol("name".into()),
Atom::Keyword("kw".into()),
Atom::Str("body".into()),
Atom::Int(42),
Atom::Int(-7),
Atom::Float(1.5),
Atom::Float(1.0),
Atom::Bool(true),
Atom::Bool(false),
];
for atom in cases {
let sexp = Sexp::Atom(atom.clone());
assert_eq!(
sexp.as_symbol(),
sexp.as_atom().and_then(Atom::as_symbol),
"Sexp::as_symbol drifted from as_atom().and_then(Atom::as_symbol) for {atom:?}",
);
assert_eq!(
sexp.as_keyword(),
sexp.as_atom().and_then(Atom::as_keyword),
"Sexp::as_keyword drifted from as_atom().and_then(Atom::as_keyword) for {atom:?}",
);
assert_eq!(
sexp.as_string(),
sexp.as_atom().and_then(Atom::as_string),
"Sexp::as_string drifted from as_atom().and_then(Atom::as_string) for {atom:?}",
);
assert_eq!(
sexp.as_int(),
sexp.as_atom().and_then(Atom::as_int),
"Sexp::as_int drifted from as_atom().and_then(Atom::as_int) for {atom:?}",
);
assert_eq!(
sexp.as_bool(),
sexp.as_atom().and_then(Atom::as_bool),
"Sexp::as_bool drifted from as_atom().and_then(Atom::as_bool) for {atom:?}",
);
// `Sexp::as_float` specializes through the widening composition
// `s.as_atom().and_then(|a| a.as_float().or_else(|| a.as_int()
// .map(|n| n as f64)))` so the algebra-level `Atom::as_float`
// stays strict and the typed-identity distinction `Int(1)` vs
// `Float(1.0)` is preserved at the algebra layer.
let expected_float = sexp
.as_atom()
.and_then(|a| a.as_float().or_else(|| a.as_int().map(|n| n as f64)));
assert_eq!(
sexp.as_float(),
expected_float,
"Sexp::as_float drifted from widening composition for {atom:?}",
);
}
}
#[test]
fn sexp_as_float_widens_int_to_float_at_consumer_layer_only() {
// CONSUMER-LAYER WIDENING CONTRACT: pin that the `Sexp::as_float`
// consumer DOES widen `Atom::Int(n)` to `Some(n as f64)` (the
// load-bearing widening at the numeric-kwarg boundary the
// `extract_float` extractor depends on) AND that the algebra-
// level `Atom::as_float` does NOT (the strict typed-identity
// discipline pinned at `atom_as_float_returns_payload_iff_float_variant_strict_no_int_widening`).
// The widening lives at the CONSUMER layer ONLY; a regression
// that drifts the widening into the algebra layer (e.g. re-
// adds an `Atom::Int(n) => Some(n as f64)` arm at
// `Atom::as_float`) would silently coerce `Int(1)` slots into
// the `Float` track at every `Atom` consumer that bypasses
// `Sexp`, breaking the typed-identity discipline at the
// canonical-form rendering surfaces (Display, JSON,
// iac-forge).
let int_sexp = Sexp::int(7);
assert_eq!(
int_sexp.as_float(),
Some(7.0),
"Sexp::as_float must widen Atom::Int to f64 at the consumer layer",
);
assert_eq!(
Atom::Int(7).as_float(),
None,
"Atom::as_float must stay strict at the algebra layer",
);
// The widening sweeps the int domain — pin a few canonical
// values so a regression that loses the `as f64` cast (e.g. an
// accidental `usize` round-trip) surfaces directly.
for n in [-42i64, -1, 0, 1, 42] {
assert_eq!(
Sexp::int(n).as_float(),
Some(n as f64),
"Sexp::as_float widening drifted for Int({n})",
);
}
}
#[test]
fn sexp_to_json_method_projects_each_outer_arm_to_canonical_json() {
// LIFTED-BOUNDARY CONTRACT: pin that the inherent
// `Sexp::to_json()` method projects each reachable outer Sexp
// shape to a `serde_json::Value` byte-identical to the
// pre-lift inline rule at `crate::domain::sexp_to_json`'s
// outer match — Nil → Null, Atom → `Atom::to_json` (composed
// through the typed-algebra projection), List(kwargs) →
// Object keyed by kebab→camel, List(other) → Array, and
// each quote-family wrapper → recurse on inner (the wrapper
// is structurally erased into JSON). A regression that
// drifts ANY outer arm (e.g. emits Nil as `"nil"` instead of
// Null, swaps List(kwargs) for Array unconditionally, drops
// a quote-family arm's recursion) surfaces here. Pre-lift
// the dispatcher lived as a free function in `domain.rs`;
// post-lift the canonical site is the inherent method on
// the `Sexp` algebra (same posture as the prior
// `Sexp::shape` (121bb60) and `Sexp::witness` (a427e3b)
// lifts).
assert_eq!(
Sexp::Nil.to_json().expect("nil to_json"),
serde_json::Value::Null,
);
assert_eq!(
Sexp::symbol("foo").to_json().expect("symbol to_json"),
serde_json::Value::String("foo".into()),
);
assert_eq!(
Sexp::keyword("k").to_json().expect("keyword to_json"),
serde_json::Value::String(":k".into()),
);
assert_eq!(
Sexp::string("body").to_json().expect("string to_json"),
serde_json::Value::String("body".into()),
);
assert_eq!(
Sexp::int(7).to_json().expect("int to_json"),
serde_json::json!(7),
);
assert_eq!(
Sexp::float(1.5).to_json().expect("float to_json"),
serde_json::json!(1.5),
);
assert_eq!(
Sexp::boolean(true).to_json().expect("true to_json"),
serde_json::Value::Bool(true),
);
// List(kwargs) → Object with kebab→camel keys.
let kwargs = Sexp::List(vec![
Sexp::keyword("point-type"),
Sexp::symbol("Gate"),
Sexp::keyword("must-reach"),
Sexp::boolean(true),
]);
assert_eq!(
kwargs.to_json().expect("kwargs list to_json"),
serde_json::json!({"pointType": "Gate", "mustReach": true}),
);
// List(non-kwargs) → Array.
let arr = Sexp::List(vec![Sexp::int(1), Sexp::int(2), Sexp::int(3)]);
assert_eq!(
arr.to_json().expect("non-kwargs list to_json"),
serde_json::json!([1, 2, 3]),
);
// Empty list → Array (kwargs guard rejects empty lists).
let empty = Sexp::List(vec![]);
assert_eq!(
empty.to_json().expect("empty list to_json"),
serde_json::json!([]),
);
// Quote-family wrappers strip and recurse.
let payload = Sexp::List(vec![Sexp::keyword("k"), Sexp::int(42)]);
let expected = serde_json::json!({"k": 42});
for wrapped in [
Sexp::Quote(Box::new(payload.clone())),
Sexp::Quasiquote(Box::new(payload.clone())),
Sexp::Unquote(Box::new(payload.clone())),
Sexp::UnquoteSplice(Box::new(payload.clone())),
] {
assert_eq!(
wrapped.to_json().expect("quote-family to_json"),
expected,
"quote-family wrapper {wrapped:?} drifted from inner-recursion shape",
);
}
}
#[test]
fn sexp_to_json_method_agrees_with_domain_sexp_to_json_for_every_outer_shape() {
// LIFTED-BOUNDARY CONTRACT: pin that the inherent
// `Sexp::to_json()` method agrees with the free-function
// delegate `crate::domain::sexp_to_json` for every reachable
// outer shape. Pre-lift the dispatcher lived as a free
// function in `domain.rs`; post-lift the canonical site is
// the inherent method and the free function is a one-line
// delegate. Pin that the delegation stays byte-for-byte
// equivalent across every outer arm so a regression where
// the free function drifts from the inherent method (or
// vice versa) surfaces here immediately. Mirrors
// `sexp_shape_method_agrees_with_domain_sexp_shape_for_every_outer_shape`
// and
// `sexp_witness_method_agrees_with_domain_sexp_witness_for_every_outer_shape`
// for the JSON canonical-form projection peer.
let samples = [
Sexp::Nil,
Sexp::symbol("foo"),
Sexp::keyword("k"),
Sexp::string("s"),
Sexp::int(7),
Sexp::int(-1),
Sexp::float(7.5),
Sexp::float(0.0),
Sexp::boolean(true),
Sexp::boolean(false),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1), Sexp::int(2)]),
Sexp::List(vec![
Sexp::keyword("point-type"),
Sexp::symbol("Gate"),
Sexp::keyword("must-reach"),
Sexp::boolean(true),
]),
Sexp::Quote(Box::new(Sexp::symbol("payload"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![Sexp::symbol("foo")]))),
Sexp::Unquote(Box::new(Sexp::symbol("x"))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
];
for s in &samples {
let via_method = s.to_json().expect("method projection must succeed");
let via_delegate =
crate::domain::sexp_to_json(s).expect("delegate projection must succeed");
assert_eq!(
via_method, via_delegate,
"Sexp::to_json drifted from domain::sexp_to_json at {s:?}",
);
}
}
#[test]
fn sexp_to_json_method_routes_atom_arm_through_atom_to_json() {
// PATH-UNIFORMITY CONTRACT: the lifted `Sexp::to_json()`
// body composes through the typed-algebra primitive
// [`Atom::to_json`] at the Atom arm — `Sexp::Atom(a).to_json()
// == Ok(a.to_json())` for every atomic payload variant. A
// regression in EITHER direction (a `Sexp::to_json` arm
// that bypasses `Atom::to_json` and re-inlines a per-variant
// mapping, or an `Atom::to_json` projection that diverges
// from the rendering the outer arm depends on) is
// structurally impossible — the typed JSON primitive composes
// through the typed primitive halves once. Sibling-shape pin
// to `sexp_to_json_atom_arms_route_through_atom_to_json` in
// `domain.rs` (the free-function-delegate peer that pinned
// the same identity at the pre-lift site).
let cases: &[Atom] = &[
Atom::Symbol("name".into()),
Atom::Keyword("kw".into()),
Atom::Str("body".into()),
Atom::Int(7),
Atom::Int(-3),
Atom::Float(2.5),
Atom::Float(1.0),
Atom::Bool(true),
Atom::Bool(false),
];
for atom in cases {
let via_method = Sexp::Atom(atom.clone())
.to_json()
.expect("atom must serialize through Sexp::to_json");
let via_atom = atom.to_json();
assert_eq!(
via_method, via_atom,
"Sexp::to_json Atom arm drifted from Atom::to_json for {atom:?}",
);
}
}
#[test]
fn sexp_to_json_method_routes_quote_family_arms_through_inner_recursion() {
// PATH-UNIFORMITY CONTRACT: the four quote-family arms each
// strip the wrapper and recurse on the projected `inner`
// (via `Self::expect_quote_form`), NOT on the outer `self`.
// Pin that this binding semantic is observable across all
// four wrappers: `wrap_qf(inner).to_json() == inner.to_json()`
// for every `QuoteForm` variant. A regression that lifted
// the recursion onto `self` (the outer wrapper) instead of
// the projected inner would infinite-loop or surface as a
// structural mismatch here. Sibling shape to
// `sexp_to_json_routes_quote_family_arms_through_as_quote_form_typed_marker`
// in `domain.rs::tests` (the free-function-delegate peer)
// — both pin the same invariant at the lifted boundary.
let inner = Sexp::List(vec![Sexp::keyword("k"), Sexp::int(42)]);
let expected = inner.to_json().expect("inner serializes");
for wrap in [
Sexp::Quote(Box::new(inner.clone())),
Sexp::Quasiquote(Box::new(inner.clone())),
Sexp::Unquote(Box::new(inner.clone())),
Sexp::UnquoteSplice(Box::new(inner.clone())),
] {
let via_method = wrap
.to_json()
.expect("quote-family wrapper must serialize via Sexp::to_json");
assert_eq!(
via_method, expected,
"Sexp::to_json drifted from inner-recursion shape at {wrap:?}",
);
}
}
#[test]
fn sexp_to_json_method_rejects_duplicate_kwargs_at_lifted_boundary() {
// TYPED-ENTRY CONTRACT: the duplicate-keyword rejection at
// the kwargs-list arm fires at the inherent method directly,
// not at the delegate — the canonical typed-entry gate lives
// on the algebra. Pin that two `:k` entries in the same
// kwargs list collapse to `LispError::DuplicateKwarg { key }`
// with `key == "notify-ref"` (the kebab spelling, before
// kebab→camel conversion — the diagnostic surface matches
// the spelling the operator typed). The error type
// discriminator is checked via debug-format substring so a
// future LispError variant rename doesn't silently break
// this pin. Mirrors `sexp_to_json_nested_duplicate_emits_structural_variant`
// in `domain.rs::tests` (the free-function delegate peer at
// the pre-lift site) at the lifted boundary.
let dup = Sexp::List(vec![
Sexp::keyword("notify-ref"),
Sexp::string("a"),
Sexp::keyword("notify-ref"),
Sexp::string("b"),
]);
let err = dup.to_json().expect_err("duplicate kwarg must reject");
let rendered = format!("{err:?}");
assert!(
rendered.contains("DuplicateKwarg"),
"expected DuplicateKwarg variant, got {rendered}",
);
assert!(
rendered.contains("notify-ref"),
"expected diagnostic to name the kebab-spelled duplicate key, got {rendered}",
);
}
// ── Sexp::from_json: the inverse JSON-projection on the algebra ─────
//
// `Sexp::from_json` lifts the `domain::json_to_sexp` free-function
// dispatcher onto the inherent-method canonical site on the [`Sexp`]
// algebra — sibling-lift posture to the prior `sexp_to_json` →
// `Sexp::to_json` (875ee3b), `sexp_witness` → `Sexp::witness`
// (a427e3b), and `sexp_shape` → `Sexp::shape` (121bb60). The tests
// below pin the per-arm contract on the new canonical site directly;
// the free function delegates so the existing path-uniformity tests
// at `domain::json_to_sexp_*` continue to pass post-lift unchanged.
#[test]
fn sexp_from_json_projects_each_outer_arm_to_canonical_sexp() {
// LIFTED-BOUNDARY CONTRACT: pin that the inherent
// `Sexp::from_json` associated function projects each reachable
// outer `serde_json::Value` shape to a `Sexp` byte-identical to
// the pre-lift inline rule at `crate::domain::json_to_sexp`'s
// outer match — Null → Nil, Bool → boolean, Number(i64) → int,
// Number(f64-only) → float, String → string, Array → List(map),
// Object → List of alternating `:k v` pairs in iteration order
// via `camel_to_kebab` on each key. A regression that drifts ANY
// outer arm (e.g. emits Null as Sexp::string(""), swaps Array
// for a kwargs-shaped List, drops the camel→kebab projection on
// Object keys) surfaces here. Pre-lift the dispatcher lived as a
// free function in `domain.rs`; post-lift the canonical site is
// the inherent associated function on the `Sexp` algebra.
assert_eq!(Sexp::from_json(&serde_json::Value::Null), Sexp::Nil);
assert_eq!(
Sexp::from_json(&serde_json::Value::Bool(true)),
Sexp::boolean(true),
);
assert_eq!(
Sexp::from_json(&serde_json::Value::Bool(false)),
Sexp::boolean(false),
);
assert_eq!(Sexp::from_json(&serde_json::json!(42)), Sexp::int(42));
assert_eq!(Sexp::from_json(&serde_json::json!(-1)), Sexp::int(-1));
assert_eq!(Sexp::from_json(&serde_json::json!(0)), Sexp::int(0));
// Float that does NOT fit i64 falls through to the float arm.
assert_eq!(Sexp::from_json(&serde_json::json!(1.5)), Sexp::float(1.5));
assert_eq!(
Sexp::from_json(&serde_json::Value::String("body".into())),
Sexp::string("body"),
);
// Array → List with each element projected recursively.
let arr = serde_json::json!([1, "x", true, null]);
assert_eq!(
Sexp::from_json(&arr),
Sexp::List(vec![
Sexp::int(1),
Sexp::string("x"),
Sexp::boolean(true),
Sexp::Nil,
]),
);
// Object → List of alternating `:k v` pairs, JSON key projected
// through camel→kebab so the kwarg authoring shape is recovered.
// The iteration order of the JSON object is implementation-
// defined here (no `preserve_order` feature on `serde_json`), so
// pin the SET of (kebab-key, value) pairs rather than the
// sequence — order-uniformity vs. the delegate is pinned in the
// path-uniformity test below.
let obj = serde_json::json!({"pointType": "Gate", "mustReach": true});
let result = Sexp::from_json(&obj);
let items = match &result {
Sexp::List(items) => items.clone(),
other => panic!("expected List, got {other:?}"),
};
assert_eq!(items.len(), 4);
let mut pairs: Vec<(String, Sexp)> = items
.chunks_exact(2)
.map(|c| (c[0].as_keyword().expect("kw").to_string(), c[1].clone()))
.collect();
pairs.sort_by(|a, b| a.0.cmp(&b.0));
assert_eq!(
pairs,
vec![
("must-reach".to_string(), Sexp::boolean(true)),
("point-type".to_string(), Sexp::string("Gate")),
],
);
}
#[test]
fn sexp_from_json_agrees_with_domain_json_to_sexp_for_every_outer_shape() {
// PATH-UNIFORMITY GUARD: pin that the free-function delegate
// `crate::domain::json_to_sexp(v) == Sexp::from_json(v)` for
// every reachable `serde_json::Value` outer shape. Post-lift the
// free function delegates to the inherent associated function;
// this test pins the delegation byte-for-byte so a future
// regression that drifts the delegate (e.g. inlines a stale
// pre-lift body, swaps the iteration order at one site) fires
// here, parallel to `sexp_to_json_method_agrees_with_domain_
// sexp_to_json_for_every_outer_shape`'s posture for the forward
// direction.
let shapes = [
serde_json::Value::Null,
serde_json::Value::Bool(true),
serde_json::Value::Bool(false),
serde_json::json!(7),
serde_json::json!(-3),
serde_json::json!(2.5),
serde_json::Value::String("body".into()),
serde_json::json!([1, 2, 3]),
serde_json::json!({"camelCase": "v", "another-key": 5}),
serde_json::json!({"nested": {"inner": [1, 2]}}),
serde_json::json!([]),
serde_json::json!({}),
];
for v in &shapes {
assert_eq!(
Sexp::from_json(v),
crate::domain::json_to_sexp(v),
"delegate drifted from inherent associated function for {v}",
);
}
}
#[test]
fn sexp_from_json_object_keys_route_through_camel_to_kebab() {
// KEY-PROJECTION CONTRACT: pin that JSON object keys land in
// the resulting `Sexp::List` as `Sexp::keyword(camel_to_kebab(k))`
// — the inverse of `Sexp::to_json`'s kebab→camel projection.
// A regression that drops the projection (writes the JSON key
// verbatim, breaking the kwarg round-trip), substitutes a
// different camel→kebab implementation at this site, or routes
// through `kebab_to_camel` (the wrong direction) surfaces here.
let obj = serde_json::json!({
"pointType": 1,
"mustReach": 2,
"already-kebab": 3,
"withABC": 4,
});
let result = Sexp::from_json(&obj);
let items = match &result {
Sexp::List(items) => items,
other => panic!("expected List, got {other:?}"),
};
// Even-position elements are keywords; odd-position elements are
// values. Pin the keyword spellings against the camel→kebab
// projection (camel boundaries become `-`; consecutive uppercase
// each get a leading `-` per the implementation in
// `domain::camel_to_kebab`).
let kws: Vec<&str> = items
.iter()
.step_by(2)
.map(|s| s.as_keyword().expect("even position must be keyword"))
.collect();
// Match the order JSON preserve_order gives us — sortable for
// stability; the contract is just that each key landed through
// camel→kebab, not the insertion order itself.
let mut sorted = kws.clone();
sorted.sort();
assert_eq!(
sorted,
vec!["already-kebab", "must-reach", "point-type", "with-a-b-c"],
);
}
#[test]
fn sexp_from_json_number_arm_routes_through_atom_from_json_number() {
// LIFTED-BOUNDARY CONTRACT: pin that the outer `Sexp::from_json`'s
// `serde_json::Value::Number(_)` arm delegates through the
// typed-algebra method `Atom::from_json_number` for every
// reachable `serde_json::Number` shape (i64-backed, finite
// f64-backed, and the empty structural-impossibility residual —
// although `serde_json::Number`'s closed-set discriminator
// excludes the last case in practice, so it's exercised only
// via the direct algebra method). Pre-lift the outer arm
// carried its own inline three-branch cascade (`n.as_i64` then
// `n.as_f64` then `Self::int(0)` typed floor); post-lift the
// arm collapses to `Self::Atom(Atom::from_json_number(n))` and
// the per-variant numeric-axis body binds at ONE typed
// projection on the [`Atom`] algebra. A regression that drifts
// the outer arm (e.g. re-inlines ONE variant's rendering
// without updating `Atom::from_json_number`, or introduces a
// spurious f64→JValue::Null re-wrap) surfaces as an inequality
// here. The sweep covers every Number shape the substrate
// encounters in practice.
//
// Sibling-shape pin to `sexp_to_json_atom_arms_route_through_atom_to_json`
// (in `crate::domain::tests`) — where that pin closes the
// FORWARD `Sexp::Atom → JValue` routing through
// `Atom::to_json`, THIS pin closes the INVERSE
// `JValue::Number → Sexp::Atom` routing through
// `Atom::from_json_number`. Together the two pins pin the
// round-trip closure `Sexp::from_json ∘ Sexp::to_json` for
// the numeric-axis subset AT the algebra layer rather than
// per consumer.
let number_shapes: Vec<serde_json::Number> = vec![
0i64.into(),
1i64.into(),
(-1i64).into(),
42i64.into(),
i64::MAX.into(),
i64::MIN.into(),
serde_json::Number::from_f64(1.5).unwrap(),
serde_json::Number::from_f64(-2.5).unwrap(),
serde_json::Number::from_f64(1.234_567_890_123).unwrap(),
];
for n in &number_shapes {
let via_outer = Sexp::from_json(&serde_json::Value::Number(n.clone()));
let via_algebra = Sexp::Atom(Atom::from_json_number(n));
assert_eq!(
via_outer, via_algebra,
"Sexp::from_json Number arm drifted from \
Sexp::Atom(Atom::from_json_number(n)) for {n:?}",
);
}
}
// ── Sexp::is_kwargs_list: the kwargs-shape predicate on the algebra ─
//
// `Sexp::is_kwargs_list` lifts the `pub(crate) domain::is_kwargs_list`
// free function onto the inherent-method canonical site on the
// [`Sexp`] algebra — sibling-shape predicate peer of [`Sexp::is_list`]
// narrowing the structural witness to the kwargs-shaped sub-cohort.
// The tests below pin the per-arm contract on the new canonical site
// directly; the `pub(crate)` free function has zero remaining callers
// post-lift and is removed in the same patch so the substrate's
// "kwargs-shape predicate" lives at exactly one canonical site on the
// algebra rather than splitting across a `domain.rs` helper and the
// `Sexp::to_json` call site.
#[test]
fn sexp_is_kwargs_list_method_returns_true_for_canonical_kwargs_shape() {
// PER-ARM CONTRACT (true cell): pin that a `Sexp::List` whose
// even-indexed items are all keywords and whose length is non-zero
// even returns `true` — the canonical kwargs shape `(:k v :k v …)`.
// Covers the two-arity and four-arity baseline cases plus a mixed
// payload (keyword odd index — even-index check is keyword-only,
// odd-index payload is unconstrained per the kwargs convention).
// A regression that drifts the predicate (incorrect parity check,
// wrong keyword-position check, off-by-one in the step) surfaces
// here immediately.
let two = Sexp::List(vec![Sexp::keyword("k"), Sexp::int(1)]);
assert!(two.is_kwargs_list());
let four = Sexp::List(vec![
Sexp::keyword("k1"),
Sexp::int(1),
Sexp::keyword("k2"),
Sexp::string("v2"),
]);
assert!(four.is_kwargs_list());
// Odd-position values can themselves be keywords; the convention
// only constrains the EVEN positions.
let mixed = Sexp::List(vec![
Sexp::keyword("k1"),
Sexp::keyword("v-is-keyword-too"),
Sexp::keyword("k2"),
Sexp::Nil,
]);
assert!(mixed.is_kwargs_list());
}
#[test]
fn sexp_is_kwargs_list_method_returns_false_for_non_list_outer_shapes_and_violating_lists() {
// PER-ARM CONTRACT (false cell): pin that every non-`Self::List`
// outer shape (Nil, every Atom payload variant, every quote-family
// wrapper) returns `false`, and that every `Self::List` violating
// the kwargs convention (empty, odd length, non-keyword at any
// even index) also returns `false`. A regression that returns
// `true` for a wrong shape (e.g. claiming a Nil or a non-kwargs
// list satisfies the predicate, opening the door to a
// `Sexp::to_json` arm misrouting) surfaces here immediately.
// Non-list outer shapes:
assert!(!Sexp::Nil.is_kwargs_list());
assert!(!Sexp::symbol("s").is_kwargs_list());
assert!(!Sexp::keyword("k").is_kwargs_list());
assert!(!Sexp::string("body").is_kwargs_list());
assert!(!Sexp::int(0).is_kwargs_list());
assert!(!Sexp::float(0.0).is_kwargs_list());
assert!(!Sexp::boolean(true).is_kwargs_list());
assert!(!Sexp::Quote(Box::new(Sexp::keyword("k"))).is_kwargs_list());
assert!(!Sexp::Quasiquote(Box::new(Sexp::keyword("k"))).is_kwargs_list());
assert!(!Sexp::Unquote(Box::new(Sexp::keyword("k"))).is_kwargs_list());
assert!(!Sexp::UnquoteSplice(Box::new(Sexp::keyword("k"))).is_kwargs_list());
// List arm violations:
assert!(!Sexp::List(vec![]).is_kwargs_list()); // empty
assert!(!Sexp::List(vec![Sexp::keyword("k")]).is_kwargs_list()); // odd length 1
assert!(
!Sexp::List(vec![Sexp::keyword("k1"), Sexp::int(1), Sexp::keyword("k2")])
.is_kwargs_list()
); // odd length 3
assert!(!Sexp::List(vec![Sexp::int(1), Sexp::int(2)]).is_kwargs_list()); // non-keyword at even 0
assert!(!Sexp::List(vec![
Sexp::keyword("k1"),
Sexp::int(1),
Sexp::symbol("not-kw"),
Sexp::int(2)
])
.is_kwargs_list()); // non-keyword at even 2
}
#[test]
fn sexp_is_kwargs_list_method_composes_through_as_list_and_atom_as_keyword() {
// COMPOSITION LAW: pin that the lifted predicate composes through
// the already-lifted `Self::as_list` (structural projection onto
// `&[Sexp]`) and `Atom::as_keyword` (typed projection onto the
// keyword payload) primitives — a regression that re-inlines the
// body without routing through the algebra-level soft-projection
// family becomes detectable here. Sweeps every reachable outer
// shape (Nil, every Atom variant, every quote-family wrapper, a
// selection of List shapes covering the true + false cells) and
// asserts the predicate's value agrees with the by-hand
// `as_list().is_some_and(...)` recomposition.
fn by_hand(s: &Sexp) -> bool {
s.as_list().is_some_and(|items| {
!items.is_empty()
&& items.len().is_multiple_of(2)
&& items.iter().step_by(2).all(|e| e.as_keyword().is_some())
})
}
let cases = [
Sexp::Nil,
Sexp::symbol("s"),
Sexp::keyword("k"),
Sexp::string("body"),
Sexp::int(7),
Sexp::float(2.5),
Sexp::boolean(false),
Sexp::Quote(Box::new(Sexp::keyword("k"))),
Sexp::Quasiquote(Box::new(Sexp::keyword("k"))),
Sexp::Unquote(Box::new(Sexp::keyword("k"))),
Sexp::UnquoteSplice(Box::new(Sexp::keyword("k"))),
Sexp::List(vec![]),
Sexp::List(vec![Sexp::int(1)]),
Sexp::List(vec![Sexp::keyword("k"), Sexp::int(1)]),
Sexp::List(vec![
Sexp::keyword("k1"),
Sexp::int(1),
Sexp::keyword("k2"),
Sexp::int(2),
]),
Sexp::List(vec![Sexp::int(1), Sexp::int(2)]),
Sexp::List(vec![Sexp::keyword("k1"), Sexp::int(1), Sexp::symbol("x")]),
];
for s in &cases {
assert_eq!(
s.is_kwargs_list(),
by_hand(s),
"predicate drifted from as_list ∘ atom_as_keyword composition for {s}",
);
}
}
#[test]
fn sexp_to_json_object_arm_routes_through_is_kwargs_list_method() {
// CALLSITE-CONTRACT: pin that `Sexp::to_json`'s kwargs-vs-array
// bifurcation routes through the lifted `Sexp::is_kwargs_list`
// method — the kwargs-shape witness that gates the
// `serde_json::Value::Object` arm vs the `serde_json::Value::Array`
// arm at the `Sexp::List` outer shape. The pin walks the gate
// both directions: a kwargs-shaped list must project as `Object`
// (and the inherent predicate must agree, `true`); a non-kwargs
// list (empty, odd-length, or even-index non-keyword) must
// project as `Array` (and the predicate must agree, `false`). A
// regression that decouples the two paths (e.g. `to_json` routes
// through a re-inlined check while `is_kwargs_list` continues to
// delegate, or vice versa) surfaces here.
// Kwargs-shaped: Object projection, predicate true.
let kw = Sexp::List(vec![Sexp::keyword("foo-bar"), Sexp::int(1)]);
assert!(kw.is_kwargs_list());
assert!(matches!(
kw.to_json().expect("kwargs list projects"),
serde_json::Value::Object(_)
));
// Non-kwargs (empty list): Array projection, predicate false.
let empty = Sexp::List(vec![]);
assert!(!empty.is_kwargs_list());
assert!(matches!(
empty.to_json().expect("empty list projects"),
serde_json::Value::Array(arr) if arr.is_empty(),
));
// Non-kwargs (positional): Array projection, predicate false.
let positional = Sexp::List(vec![Sexp::int(1), Sexp::int(2), Sexp::int(3)]);
assert!(!positional.is_kwargs_list());
assert!(matches!(
positional.to_json().expect("positional list projects"),
serde_json::Value::Array(arr) if arr.len() == 3,
));
// Non-kwargs (even-index non-keyword): Array projection.
let mixed = Sexp::List(vec![
Sexp::keyword("k"),
Sexp::int(1),
Sexp::symbol("x"),
Sexp::int(2),
]);
assert!(!mixed.is_kwargs_list());
assert!(matches!(
mixed.to_json().expect("mixed list projects"),
serde_json::Value::Array(_)
));
}
#[test]
fn sexp_from_json_round_trips_to_json_for_canonical_subset() {
// ROUND-TRIP LAW: pin `Sexp::to_json(s)?.from_json() == s` for
// the round-trippable subset of Sexp shapes — Nil, Atom::Str
// (the lossless atomic floor that absorbs Symbol/Keyword on
// re-projection, so this test stays inside the lossless cell),
// Atom::Int, Atom::Float, Atom::Bool, and recursively
// Sexp::List of round-trippable elements. Pin that the inverse
// composes byte-for-byte against the forward projection inside
// the lossless cell — the round-trip law's structural anchor
// documented at `Sexp::from_json`'s docstring.
let cases = [
Sexp::Nil,
Sexp::string("body"),
Sexp::int(42),
Sexp::float(1.5),
Sexp::boolean(true),
Sexp::List(vec![Sexp::int(1), Sexp::string("x"), Sexp::Nil]),
// Empty list → empty array → empty list. Round-trips cleanly.
Sexp::List(vec![]),
];
for s in &cases {
let projected = s
.to_json()
.expect("round-trippable Sexp must project to JSON");
let recovered = Sexp::from_json(&projected);
assert_eq!(recovered, *s, "round-trip drifted at {s}");
}
}
// ── Atom typed-construct family + Sexp outer-constructor routing ─────
//
// The six `Atom::{symbol, keyword, string, int, float, boolean}`
// typed-construct methods are the section sibling of the existing
// six `Atom::as_{symbol, keyword, string, int, float, bool}` soft-
// projection family — closing the (construct, project) algebra dual
// on the closed-set `Atom` algebra. The six `Sexp::{symbol, ...,
// boolean}` outer constructors now route through
// `Self::Atom(Atom::X(_))` so the `impl Into<String>` ergonomy +
// tuple-variant constructor pair lives at ONE site per kind on the
// `Atom` algebra. Pin the four structural laws:
// (a) each `Atom::X` constructor produces the canonical tuple
// variant payload byte-for-byte (`Atom::symbol("foo") ==
// Atom::Symbol("foo".into())`, etc.) — pre-lift behavior
// under the new construction face;
// (b) the (construct, kind-project) round-trip
// `Atom::X(_).kind() == AtomKind::X` for every (kind, payload)
// pair — the typed-construct family pairs section-for-
// retraction with the `Atom::kind` projection;
// (c) the (construct, soft-project) round-trip
// `Atom::X(payload).as_X() == Some(payload)` for every kind —
// the typed-construct family pairs section-for-retraction
// with the `Atom::as_X` family it now siblings;
// (d) the outer-constructor composition law `Sexp::X(p) ==
// Sexp::Atom(Atom::X(p))` for every kind — the `Sexp` outer
// constructors route through the typed `Atom` constructors
// rather than re-deriving the `Self::Atom(Atom::X(_))` pair
// inline.
#[test]
fn atom_typed_constructors_emit_canonical_tuple_variant_for_every_kind() {
// STRUCTURAL CONSTRUCT CONTRACT: each `Atom::X` constructor
// emits the matching `Atom::Variant(payload)` tuple-variant
// value byte-for-byte. A regression that drifts ONE arm (e.g.
// a typo routing `Atom::keyword(s)` to `Self::Symbol(s.into())`
// — type-checks but silently mis-classifies every kwarg key
// authored through the algebra-level constructor) surfaces
// here. The `impl Into<String>` arms also accept `String`
// payloads — pinned alongside `&str` so the `.into()` ergonomy
// is exercised across both source types.
assert_eq!(Atom::symbol("foo"), Atom::Symbol("foo".into()));
assert_eq!(
Atom::symbol(String::from("seph.1")),
Atom::Symbol("seph.1".into()),
);
assert_eq!(Atom::symbol(""), Atom::Symbol(String::new()));
assert_eq!(Atom::keyword("parent"), Atom::Keyword("parent".into()));
assert_eq!(
Atom::keyword(String::from("attr")),
Atom::Keyword("attr".into()),
);
assert_eq!(Atom::keyword(""), Atom::Keyword(String::new()));
assert_eq!(Atom::string("body"), Atom::Str("body".into()));
assert_eq!(
Atom::string(String::from("with\nnewline")),
Atom::Str("with\nnewline".into()),
);
assert_eq!(Atom::string(""), Atom::Str(String::new()));
assert_eq!(Atom::int(0), Atom::Int(0));
assert_eq!(Atom::int(42), Atom::Int(42));
assert_eq!(Atom::int(-7), Atom::Int(-7));
assert_eq!(Atom::int(i64::MIN), Atom::Int(i64::MIN));
assert_eq!(Atom::int(i64::MAX), Atom::Int(i64::MAX));
assert_eq!(Atom::float(0.0), Atom::Float(0.0));
assert_eq!(Atom::float(1.5), Atom::Float(1.5));
assert_eq!(Atom::float(-2.5), Atom::Float(-2.5));
// NaN compares unequal to itself; pin via `to_bits` round-trip,
// matching the `Hash for Atom` Float-arm posture
// (`f.to_bits().hash(...)`).
assert_eq!(Atom::float(f64::NAN).kind(), AtomKind::Float);
match Atom::float(f64::NAN) {
Atom::Float(n) => assert!(n.is_nan()),
_ => panic!("Atom::float must emit Atom::Float"),
}
assert_eq!(Atom::float(f64::INFINITY), Atom::Float(f64::INFINITY));
assert_eq!(Atom::boolean(true), Atom::Bool(true));
assert_eq!(Atom::boolean(false), Atom::Bool(false));
}
#[test]
fn atom_typed_constructors_round_trip_through_kind_projection() {
// SECTION LAW (construct → kind): every typed constructor's
// output projects through `Atom::kind` to its matching
// `AtomKind` variant. The `(construct, kind-project)` pair
// forms a deterministic surjection from the construct face
// onto the closed-set `AtomKind` algebra — six (kind,
// representative payload) probes sweep `AtomKind::ALL` so a
// future seventh atomic kind landing on the algebra extends
// BOTH the construct face AND this sweep in lockstep (rustc-
// enforced through the closed-set match below).
for kind in AtomKind::ALL {
let constructed = match kind {
AtomKind::Symbol => Atom::symbol("foo"),
AtomKind::Keyword => Atom::keyword("parent"),
AtomKind::Str => Atom::string("body"),
AtomKind::Int => Atom::int(42),
AtomKind::Float => Atom::float(1.5),
AtomKind::Bool => Atom::boolean(true),
};
assert_eq!(
constructed.kind(),
kind,
"Atom typed constructor for {kind:?} drifted from its closed-set kind projection",
);
}
}
#[test]
fn atom_typed_constructors_round_trip_through_per_variant_soft_projection() {
// RETRACTION LAW (construct → soft-project): every typed
// constructor's output projects through its matching `Atom::as_X`
// soft projection to `Some(payload)` — the (construct, soft-
// project) pair forms an `Iso(payload, Atom::Variant(payload))`
// on the typed-payload axis. Sibling-axis to the
// `(construct, kind-project)` pair above and to the
// `Sexp::as_quote_form / QuoteForm::wrap` round-trip on the
// outer-shape axis (`QuoteForm::wrap(inner).as_quote_form()
// == Some((qf, &inner))`). The retraction's load-bearing
// contract is what the substrate's named-form NAME gate
// (`split_name_slot` → `as_symbol_or_string`) depends on at
// every typed-domain dispatcher.
assert_eq!(Atom::symbol("foo").as_symbol(), Some("foo"));
assert_eq!(Atom::symbol("").as_symbol(), Some(""));
assert_eq!(Atom::keyword("parent").as_keyword(), Some("parent"));
assert_eq!(Atom::keyword("").as_keyword(), Some(""));
assert_eq!(Atom::string("body").as_string(), Some("body"));
assert_eq!(Atom::string("").as_string(), Some(""));
assert_eq!(Atom::int(42).as_int(), Some(42));
assert_eq!(Atom::int(0).as_int(), Some(0));
assert_eq!(Atom::int(i64::MIN).as_int(), Some(i64::MIN));
assert_eq!(Atom::float(1.5).as_float(), Some(1.5));
assert_eq!(Atom::float(0.0).as_float(), Some(0.0));
assert_eq!(Atom::boolean(true).as_bool(), Some(true));
assert_eq!(Atom::boolean(false).as_bool(), Some(false));
}
#[test]
fn sexp_outer_constructors_route_through_atom_typed_construct_family() {
// OUTER-CONSTRUCTOR COMPOSITION LAW: pin that each `Sexp::X`
// outer constructor emits `Sexp::Atom(Atom::X(_))` byte-for-byte
// — a regression that re-inlines the pre-lift body
// `Self::Atom(Atom::Variant(s.into()))` and drifts ONE arm
// (e.g. a future copy-edit that swaps `Sexp::symbol` to route
// through `Atom::Keyword` after a refactor) becomes detectable
// at this site. Sibling-shape pin to the `Sexp::as_X` family's
// structural-lift composition through `Sexp::as_atom +
// Atom::as_X` on the projection axis (sweep posture in
// `sexp_as_symbol_or_string_routes_through_atom_as_symbol_or_string_via_as_atom_composition`).
assert_eq!(Sexp::symbol("foo"), Sexp::Atom(Atom::symbol("foo")));
assert_eq!(Sexp::symbol(""), Sexp::Atom(Atom::symbol("")));
assert_eq!(
Sexp::symbol(String::from("seph.1")),
Sexp::Atom(Atom::symbol("seph.1")),
);
assert_eq!(Sexp::keyword("parent"), Sexp::Atom(Atom::keyword("parent")),);
assert_eq!(Sexp::string("body"), Sexp::Atom(Atom::string("body")));
assert_eq!(Sexp::int(42), Sexp::Atom(Atom::int(42)));
assert_eq!(Sexp::int(i64::MIN), Sexp::Atom(Atom::int(i64::MIN)));
assert_eq!(Sexp::float(1.5), Sexp::Atom(Atom::float(1.5)));
assert_eq!(Sexp::boolean(true), Sexp::Atom(Atom::boolean(true)));
assert_eq!(Sexp::boolean(false), Sexp::Atom(Atom::boolean(false)));
}
#[test]
fn atom_typed_constructors_partition_atom_kind_across_constructed_payloads() {
// PARTITION LAW: every typed constructor's output projects to
// `Some(_)` on its matching soft projection AND to `None` on
// every other soft projection. The (construct, soft-project)
// matrix is the diagonal of `AtomKind::ALL × AtomKind::ALL`:
// on-diagonal cells return `Some`, off-diagonal cells return
// `None`. Pin the full matrix so a regression that conflates
// two construct arms (e.g. a future `Atom::keyword(s)` typo
// routing to `Self::Symbol(s.into())` — type-checks, passes
// the kind-projection sweep above iff the typo also drifts
// `Atom::kind`, but fails THIS sweep because the off-diagonal
// `Atom::keyword(s).as_symbol() == None` cell flips to `Some`)
// surfaces structurally. The matrix's diagonal-restriction
// form rebuilds the closed-set partition law every soft-
// projection sweep above pins per-axis into ONE joint pin
// across the (construct, project) algebra dual.
let constructed = [
(AtomKind::Symbol, Atom::symbol("foo")),
(AtomKind::Keyword, Atom::keyword("parent")),
(AtomKind::Str, Atom::string("body")),
(AtomKind::Int, Atom::int(42)),
(AtomKind::Float, Atom::float(1.5)),
(AtomKind::Bool, Atom::boolean(true)),
];
for (built_kind, a) in &constructed {
assert_eq!(
a.as_symbol().is_some(),
*built_kind == AtomKind::Symbol,
"as_symbol partition row drifted for {built_kind:?}",
);
assert_eq!(
a.as_keyword().is_some(),
*built_kind == AtomKind::Keyword,
"as_keyword partition row drifted for {built_kind:?}",
);
assert_eq!(
a.as_string().is_some(),
*built_kind == AtomKind::Str,
"as_string partition row drifted for {built_kind:?}",
);
assert_eq!(
a.as_int().is_some(),
*built_kind == AtomKind::Int,
"as_int partition row drifted for {built_kind:?}",
);
assert_eq!(
a.as_float().is_some(),
*built_kind == AtomKind::Float,
"as_float partition row drifted for {built_kind:?}",
);
assert_eq!(
a.as_bool().is_some(),
*built_kind == AtomKind::Bool,
"as_bool partition row drifted for {built_kind:?}",
);
}
}
// ── Sexp quote-family typed-construct algebra ────────────────────────
//
// `Sexp::quote` / `Sexp::quasiquote` / `Sexp::unquote` /
// `Sexp::unquote_splice` are the outer-Sexp typed-construct family for
// the four homoiconic prefix wrappers, section-for-retraction with the
// `Sexp::as_quote_form` soft-projection sibling. Each routes through
// `QuoteForm::X.wrap(inner)` so the (marker, `Sexp::* tuple-variant
// constructor + `Box::new`) welded triple lives at ONE site on the
// closed-set `QuoteForm` algebra. Pin FOUR structural laws:
// (a) the canonical-tuple emission
// `Sexp::quote(inner) == Sexp::Quote(Box::new(inner))` for
// every wrapper marker — the typed constructor pairs section-
// for-retraction with the tuple-variant constructor;
// (b) the composition law
// `Sexp::X_variant(inner) == QuoteForm::X.wrap(inner)` for
// every marker — the outer typed constructor routes through
// the inner-algebra `QuoteForm::wrap` typed dispatch;
// (c) the round-trip law
// `Sexp::X_variant(inner).as_quote_form() == Some((QuoteForm::X,
// &inner))` for every marker — the (construct, soft-project)
// algebra dual closes on the outer [`Sexp`] algebra with
// marker + inner-body cross-projection preserved;
// (d) the outer-shape pairing
// `Sexp::X_variant(inner).shape() == QuoteForm::X.sexp_shape()`
// for every marker — the construct family composes coherently
// through the outer-shape projection on the typed-shape
// lattice, so a regression that drifts ONE marker's outer-
// shape pairing from `QuoteForm::sexp_shape` surfaces here.
#[test]
fn sexp_quote_family_constructors_emit_canonical_tuple_variant_for_every_marker() {
// STRUCTURAL CONSTRUCT CONTRACT: each `Sexp::X_variant`
// constructor emits the matching `Sexp::X(Box::new(inner))`
// tuple-variant value byte-for-byte. A regression that drifts
// ONE arm (e.g. a typo routing `Sexp::unquote(inner)` to
// `Sexp::UnquoteSplice(Box::new(inner))` — type-checks but
// silently mis-classifies every macro-template substitution
// authored through the algebra-level constructor) surfaces
// here. Sibling-shape pin to the `Atom` typed-construct
// family's canonical-tuple-variant test posture
// (`atom_typed_constructors_emit_canonical_tuple_variant_for_every_kind`).
let payloads = [
Sexp::Nil,
Sexp::symbol("x"),
Sexp::keyword("k"),
Sexp::string("body"),
Sexp::int(42),
Sexp::boolean(true),
Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]),
];
for inner in &payloads {
assert_eq!(
Sexp::quote(inner.clone()),
Sexp::Quote(Box::new(inner.clone())),
"Sexp::quote drifted from canonical tuple variant for {inner:?}",
);
assert_eq!(
Sexp::quasiquote(inner.clone()),
Sexp::Quasiquote(Box::new(inner.clone())),
"Sexp::quasiquote drifted from canonical tuple variant for {inner:?}",
);
assert_eq!(
Sexp::unquote(inner.clone()),
Sexp::Unquote(Box::new(inner.clone())),
"Sexp::unquote drifted from canonical tuple variant for {inner:?}",
);
assert_eq!(
Sexp::unquote_splice(inner.clone()),
Sexp::UnquoteSplice(Box::new(inner.clone())),
"Sexp::unquote_splice drifted from canonical tuple variant for {inner:?}",
);
}
}
#[test]
fn sexp_quote_family_constructors_route_through_quote_form_wrap() {
// COMPOSITION LAW: pin that each `Sexp::X_variant` outer
// constructor emits `QuoteForm::X.wrap(inner)` byte-for-byte —
// a regression that re-inlines the pre-lift body
// `Self::X(Box::new(inner))` and drifts ONE arm (e.g. a future
// copy-edit that swaps `Sexp::quote` to route through
// `QuoteForm::Quasiquote` after a refactor) becomes detectable
// at this site. Sibling-shape pin to the `Sexp::X_atom` family's
// composition-through-`Atom::X` posture
// (`sexp_outer_constructors_route_through_atom_typed_construct_family`).
let inner = Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]);
assert_eq!(
Sexp::quote(inner.clone()),
QuoteForm::Quote.wrap(inner.clone())
);
assert_eq!(
Sexp::quasiquote(inner.clone()),
QuoteForm::Quasiquote.wrap(inner.clone()),
);
assert_eq!(
Sexp::unquote(inner.clone()),
QuoteForm::Unquote.wrap(inner.clone())
);
assert_eq!(
Sexp::unquote_splice(inner.clone()),
QuoteForm::UnquoteSplice.wrap(inner.clone()),
);
}
#[test]
fn sexp_quote_family_constructors_round_trip_through_as_quote_form() {
// ROUND-TRIP LAW (construct → soft-project): every quote-family
// typed constructor's output projects through `Sexp::as_quote_form`
// to `Some((matching QuoteForm, &inner))`. Sweeps `QuoteForm::ALL`
// paired with a representative inner payload — the four
// (construct, project) pairs form an `Iso(inner, Sexp::X(inner))`
// on the typed-marker axis at the outer [`Sexp`] algebra. A
// regression that drifts ONE marker's construct arm (marker/
// constructor swap) fails BOTH the marker-projection AND the
// inner-borrow round-trip. Sibling-shape pin to the `Atom` typed-
// construct family's per-variant soft-projection round-trip test
// posture
// (`atom_typed_constructors_round_trip_through_per_variant_soft_projection`).
let inner = Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]);
let constructed: [(QuoteForm, Sexp); 4] = [
(QuoteForm::Quote, Sexp::quote(inner.clone())),
(QuoteForm::Quasiquote, Sexp::quasiquote(inner.clone())),
(QuoteForm::Unquote, Sexp::unquote(inner.clone())),
(
QuoteForm::UnquoteSplice,
Sexp::unquote_splice(inner.clone()),
),
];
for qf in QuoteForm::ALL {
let (built_qf, sexp) = constructed
.iter()
.find(|(m, _)| *m == qf)
.expect("QuoteForm::ALL sweep must reach every marker");
assert_eq!(*built_qf, qf);
let (proj_qf, proj_inner) = sexp
.as_quote_form()
.unwrap_or_else(|| panic!("construct→as_quote_form drifted at {qf:?}"));
assert_eq!(
proj_qf, qf,
"typed-marker round-trip drifted at {qf:?} — construct+project pair broken",
);
assert_eq!(
proj_inner, &inner,
"inner-body round-trip drifted at {qf:?} — construct+project pair broken",
);
}
}
#[test]
fn sexp_quote_family_constructors_compose_with_shape_via_quote_form_sexp_shape() {
// OUTER-SHAPE COMPOSITION LAW: every quote-family typed
// constructor's output projects through `Sexp::shape` to the
// matching `QuoteForm::X.sexp_shape()` — the (construct,
// outer-shape) composition binds through the closed-set
// `QuoteForm::sexp_shape` embed already lifted onto the
// typed-shape lattice. A regression that drifts ONE construct
// arm's outer-shape from `QuoteForm::sexp_shape` (e.g. a future
// marker/wrapper swap that surfaces through the typed-shape
// lattice but not through the tuple-variant emission itself)
// surfaces here alongside the round-trip pin. Sibling-shape pin
// to `quote_form_sexp_shape_paired_with_as_quote_form_preserves_pre_lift_pairing_for_every_sexp`
// on the projection axis — this pin closes the same axis on the
// outer construct family.
let inner = Sexp::List(vec![Sexp::symbol("op"), Sexp::int(1)]);
let constructed: [(QuoteForm, Sexp); 4] = [
(QuoteForm::Quote, Sexp::quote(inner.clone())),
(QuoteForm::Quasiquote, Sexp::quasiquote(inner.clone())),
(QuoteForm::Unquote, Sexp::unquote(inner.clone())),
(
QuoteForm::UnquoteSplice,
Sexp::unquote_splice(inner.clone()),
),
];
for (qf, sexp) in &constructed {
assert_eq!(
sexp.shape(),
qf.sexp_shape(),
"Sexp::X_variant→shape drifted from QuoteForm::sexp_shape at {qf:?}",
);
}
}
// ── Sexp::list residual-axis typed-construct algebra ─────────────────
//
// `Sexp::list(items)` is the residual-axis section-for-retraction
// sibling of the pre-existing `Sexp::as_list` soft-projection — the
// (construct, project) algebra dual on the 2-of-12 residual carving of
// the [`SexpShape`] closed set now closes at ONE constructor + ONE
// projection on the outer [`Sexp`] algebra, symmetric with the atomic-
// payload carving's (six `Sexp::X_atom(payload)` constructors +
// `Sexp::as_atom` / `Sexp::as_atom_kind` projections) and the quote-
// family carving's (four `Sexp::X_variant(inner)` constructors +
// `Sexp::as_quote_form` / `Sexp::as_quote_form_marker` projections).
// [`Sexp::Nil`] is a unit variant with no payload — the residual-axis
// construct family closes at ONE constructor (the sole payload-bearing
// residual arm). Pin FIVE structural laws:
// (a) the canonical-tuple emission
// `Sexp::list(items) == Sexp::List(items.into_iter().collect())`
// across representative empty / single-element / multi-element /
// heterogeneous-inner samples — the typed constructor pairs
// section-for-retraction with the tuple-variant constructor;
// (b) the round-trip law
// `Sexp::list(items.clone()).as_list() == Some(items.as_slice())`
// — the (construct, soft-project) algebra dual closes on the
// outer [`Sexp`] algebra with the borrowed-slice cross-
// projection preserving identity;
// (c) the outer-shape law
// `Sexp::list(items).shape() == SexpShape::List` — the residual-
// arm outer-shape identity binds through the typed-shape
// lattice at ONE arm, symmetric with the quote-family
// construct family's `Sexp::X_variant(inner).shape() ==
// QuoteForm::X.sexp_shape()`;
// (d) the structural-kind law
// `Sexp::list(items).as_structural_kind() == Some(
// StructuralKind::List)` — the residual carving marker binds
// through the closed-set [`StructuralKind`] algebra at ONE
// arm, symmetric with the atomic-axis's
// `Sexp::X_atom(payload).as_atom_kind() == Some(AtomKind::X)`;
// (e) the input-shape flexibility
// `Sexp::list(&Vec<Sexp>)` / `Sexp::list([Sexp; N])` /
// `Sexp::list(iter::map(...))` all agree with the canonical
// tuple-variant emission — the `impl IntoIterator<Item = Sexp>`
// bound accepts every reasonable owned-sequence shape without a
// per-consumer `.collect::<Vec<Sexp>>()` coercion.
#[test]
fn sexp_list_constructor_emits_canonical_tuple_variant_across_representative_inputs() {
// STRUCTURAL CONSTRUCT CONTRACT: `Sexp::list(items)` emits
// `Sexp::List(items.into_iter().collect::<Vec<Sexp>>())` byte-
// for-byte across representative empty, single-element, multi-
// element, and heterogeneous-inner samples. A regression that
// drifts the body (e.g. wrapping items in an extra `Sexp::Nil`
// sentinel, deduplicating, filtering) surfaces here. Sibling-
// shape pin to the quote-family construct family's canonical-
// tuple-variant test posture
// (`sexp_quote_family_constructors_emit_canonical_tuple_variant_for_every_marker`).
let samples: [Vec<Sexp>; 5] = [
vec![],
vec![Sexp::symbol("only")],
vec![Sexp::symbol("op"), Sexp::int(1), Sexp::int(2)],
vec![
Sexp::Nil,
Sexp::keyword("k"),
Sexp::string("body"),
Sexp::boolean(true),
Sexp::List(vec![Sexp::symbol("nested")]),
],
vec![
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![
Sexp::symbol("template"),
Sexp::Unquote(Box::new(Sexp::symbol("var"))),
]))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
],
];
for items in &samples {
assert_eq!(
Sexp::list(items.clone()),
Sexp::List(items.clone()),
"Sexp::list drifted from canonical Sexp::List(_) tuple variant for {items:?}",
);
}
}
#[test]
fn sexp_list_constructor_round_trips_through_as_list() {
// ROUND-TRIP LAW (section-for-retraction on the residual axis):
// `Sexp::list(items.clone()).as_list() == Some(items.as_slice())`
// sweeps the same representative input matrix as the canonical-
// tuple pin — proves the (construct, soft-project) pair forms an
// `Iso(Vec<Sexp>, Sexp::List(Vec<Sexp>))` on the residual axis,
// symmetric with the quote-family axis's `Sexp::X_variant(inner)
// .as_quote_form() == Some((QuoteForm::X, &inner))` round-trip
// (pinned by `sexp_quote_family_constructors_round_trip_through_as_quote_form`).
// A regression that mis-implements `Sexp::list` (e.g. dropping
// items, cloning off-by-one) fails here on top of the canonical-
// tuple pin.
let samples: [Vec<Sexp>; 4] = [
vec![],
vec![Sexp::symbol("solo")],
vec![Sexp::symbol("op"), Sexp::int(1), Sexp::int(2)],
vec![
Sexp::Nil,
Sexp::List(vec![Sexp::symbol("nested"), Sexp::int(7)]),
Sexp::Quote(Box::new(Sexp::symbol("q"))),
],
];
for items in &samples {
let built = Sexp::list(items.clone());
assert_eq!(
built.as_list(),
Some(items.as_slice()),
"Sexp::list→as_list round-trip drifted for {items:?}",
);
}
}
#[test]
fn sexp_list_constructor_composes_with_shape_via_sexp_shape_list() {
// OUTER-SHAPE COMPOSITION LAW: every `Sexp::list(items)` output
// projects through `Sexp::shape` to `SexpShape::List` regardless
// of inner-item content — the (construct, outer-shape)
// composition binds through the typed-shape lattice's residual-
// arm at ONE arm. Sibling-shape pin to the quote-family construct
// family's outer-shape composition
// (`sexp_quote_family_constructors_compose_with_shape_via_quote_form_sexp_shape`).
// A regression that reroutes `Sexp::list` through another shape
// arm (e.g. wrapping in `Sexp::Quote` after a copy-edit that
// type-checks) surfaces here alongside the canonical-tuple pin.
let samples: [Vec<Sexp>; 4] = [
vec![],
vec![Sexp::symbol("only")],
vec![Sexp::int(1), Sexp::int(2), Sexp::int(3)],
vec![
Sexp::Nil,
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::List(vec![Sexp::symbol("nested")]),
],
];
for items in &samples {
assert_eq!(
Sexp::list(items.clone()).shape(),
SexpShape::List,
"Sexp::list→shape drifted from SexpShape::List for {items:?}",
);
}
}
#[test]
fn sexp_list_constructor_composes_with_as_structural_kind() {
// STRUCTURAL-KIND COMPOSITION LAW: every `Sexp::list(items)`
// output projects through `Sexp::as_structural_kind` to
// `Some(StructuralKind::List)` regardless of inner-item content
// — the residual carving marker binds through the closed-set
// `StructuralKind` algebra at ONE arm. Sibling-shape pin to the
// atomic-axis's `Sexp::X_atom(payload).as_atom_kind() ==
// Some(AtomKind::X)` marker composition. A regression that
// reroutes `Sexp::list` through a non-residual arm (e.g. a copy-
// edit that wraps items in `Sexp::Quote`) surfaces here through
// the returned marker no longer being `StructuralKind::List`.
let samples: [Vec<Sexp>; 4] = [
vec![],
vec![Sexp::symbol("only")],
vec![Sexp::keyword("k"), Sexp::string("v")],
vec![
Sexp::Nil,
Sexp::List(vec![Sexp::symbol("nested")]),
Sexp::Unquote(Box::new(Sexp::symbol("var"))),
],
];
for items in &samples {
assert_eq!(
Sexp::list(items.clone()).as_structural_kind(),
Some(StructuralKind::List),
"Sexp::list→as_structural_kind drifted from Some(StructuralKind::List) for {items:?}",
);
}
}
#[test]
fn sexp_list_constructor_accepts_diverse_intoiterator_input_shapes() {
// INPUT-SHAPE FLEXIBILITY: the `impl IntoIterator<Item = Sexp>`
// bound accepts every reasonable owned-sequence shape without a
// per-consumer `.collect::<Vec<Sexp>>()` coercion at the call
// site — pin that `Vec<Sexp>`, `[Sexp; N]` array, `iter::empty
// ::<Sexp>()`, and `.map(...)` iterator chains all reach the
// same canonical tuple-variant output. A regression that
// narrows the bound (e.g. taking `&[Sexp]` or `Vec<Sexp>` only)
// fails this pin. The IntoIterator bound is load-bearing for the
// ergonomy claim in the docstring — consumers threading a `.map`
// chain through the outer algebra must not need an intermediate
// `.collect()` before handing the result to `Sexp::list`.
let expected = Sexp::List(vec![
Sexp::symbol("a"),
Sexp::symbol("b"),
Sexp::symbol("c"),
]);
// Vec<Sexp> — the canonical owned-sequence shape.
assert_eq!(
Sexp::list(vec![
Sexp::symbol("a"),
Sexp::symbol("b"),
Sexp::symbol("c"),
]),
expected,
"Sexp::list drifted for Vec<Sexp> input",
);
// [Sexp; N] — array-literal shape (elements moved out of the
// fixed-size array via the `IntoIterator` impl on `[T; N]`).
assert_eq!(
Sexp::list([Sexp::symbol("a"), Sexp::symbol("b"), Sexp::symbol("c"),]),
expected,
"Sexp::list drifted for [Sexp; N] input",
);
// `iter::empty::<Sexp>()` — the zero-item iterator shape.
assert_eq!(
Sexp::list(std::iter::empty::<Sexp>()),
Sexp::List(vec![]),
"Sexp::list drifted for iter::empty input",
);
// `.map(...)` iterator chain — the composition shape the
// docstring's ergonomy claim rests on.
assert_eq!(
Sexp::list(["a", "b", "c"].iter().map(|s| Sexp::symbol(*s))),
expected,
"Sexp::list drifted for iterator-map chain input",
);
// `once(head).chain(tail)` — the head-then-rest shape a builder
// consuming `head_symbol` + the tail slice threads through.
assert_eq!(
Sexp::list(
std::iter::once(Sexp::symbol("a")).chain([Sexp::symbol("b"), Sexp::symbol("c")]),
),
expected,
"Sexp::list drifted for once+chain input",
);
}
// ── Sexp::call — call-form (symbol-headed list) construct ──────────
//
// `Sexp::call(head, args)` is the section-for-retraction dual of the
// soft-projection `Sexp::as_call() -> Option<(&str, &[Sexp])>` — it
// embeds a fresh `(head string, item sequence)` pair into a symbol-
// headed `Sexp::List` value at ONE site on the outer `Sexp` algebra,
// composing the atomic-payload construct family's `Sexp::symbol` (for
// the head position) with the residual-axis construct family's
// `Sexp::list` (for the list wrapper) via `std::iter::once(head_sexp)
// .chain(args)`. Pre-lift the composition lived inline at every
// consumer that built a `(defX …)` typed-domain call form, a
// macroexpander template head, or a synthetic dispatch form —
// `Sexp::List(vec![Sexp::symbol(head), args...])` or `Sexp::List(
// std::iter::once(Sexp::symbol(head)).chain(args).collect())` was the
// welded three-method open coding. Post-lift the closure binds at
// ONE typed-algebra method.
//
// These pins cover:
// (a) the composition law
// `Sexp::call(head, args) == Sexp::list(std::iter::once(
// Sexp::symbol(head)).chain(args))` — the constructor body is
// BY DEFINITION the two-method composition;
// (b) the round-trip law
// `Sexp::call(head, args.clone()).as_call() == Some((head,
// args.as_slice()))` — the (construct, project) call-form
// algebra dual closes at this pair, symmetric with the
// residual-axis's `Sexp::list(items.clone()).as_list() ==
// Some(items.as_slice())` round-trip;
// (c) the keyword-matched round-trip law
// `Sexp::call(head, args.clone()).as_call_to(head) == Some(
// args.as_slice())` — the keyword-typed projection recovers
// the args tail iff its argument matches the constructor's
// head;
// (d) the head-symbol composition law
// `Sexp::call(head, args).head_symbol() == Some(head)` — the
// head-position projection recovers the constructor's head
// byte-for-byte;
// (e) the outer-shape composition law
// `Sexp::call(head, args).shape() == SexpShape::List` — a
// call form is a list-shaped `Sexp`;
// (f) the structural-kind composition law
// `Sexp::call(head, args).as_structural_kind() == Some(
// StructuralKind::List)` — the residual carving marker binds
// through the closed-set `StructuralKind` algebra at ONE
// arm, symmetric with the residual-axis's `Sexp::list(items)
// .as_structural_kind() == Some(StructuralKind::List)` marker
// composition;
// (g) the input-shape flexibility
// `Sexp::call("h", Vec<Sexp>)` / `Sexp::call(String, [Sexp;
// N])` / `Sexp::call(&String, iter::map(...))` all agree with
// the canonical composition emission — the `impl Into<String>`
// head bound + `impl IntoIterator<Item = Sexp>` args bound
// accept every reasonable input shape without a per-consumer
// `.to_string()` / `.collect::<Vec<Sexp>>()` coercion.
#[test]
fn sexp_call_constructor_body_matches_canonical_two_method_composition_across_representative_inputs(
) {
// COMPOSITION LAW: `Sexp::call(head, args) == Sexp::list(
// std::iter::once(Sexp::symbol(head)).chain(args))` for every
// representative (empty-args, single-arg, multi-arg,
// heterogeneous-inner, quote-family-wrapping-inner) sample. A
// regression that drifts the body (e.g. a copy-edit that
// switches to `Sexp::keyword(head)` for the head position, or
// that reorders `head` and `args` in the chain) surfaces here
// BEFORE the projection pins fail. Sibling-shape pin to the
// residual-axis's canonical-composition test posture
// (`sexp_list_constructor_emits_canonical_tuple_variant_across_representative_inputs`).
let samples: [(&str, Vec<Sexp>); 5] = [
("defcompiler", vec![]),
("defpoint", vec![Sexp::symbol("obs")]),
(
"defpoint",
vec![
Sexp::symbol("obs"),
Sexp::keyword("class"),
Sexp::symbol("Gate"),
],
),
(
"defcheck",
vec![
Sexp::List(vec![Sexp::symbol("crd-in-sync")]),
Sexp::keyword("params"),
Sexp::int(42),
Sexp::string("body"),
Sexp::boolean(true),
],
),
(
"defalert-policy",
vec![
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![
Sexp::symbol("template"),
Sexp::Unquote(Box::new(Sexp::symbol("var"))),
]))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
],
),
];
for (head, args) in &samples {
let expected =
Sexp::list(std::iter::once(Sexp::symbol(*head)).chain(args.iter().cloned()));
assert_eq!(
Sexp::call(*head, args.clone()),
expected,
"Sexp::call drifted from Sexp::list(once(symbol(head)).chain(args)) for head={head:?} args={args:?}",
);
}
}
#[test]
fn sexp_call_constructor_round_trips_through_as_call() {
// ROUND-TRIP LAW (section-for-retraction with the call-form
// soft-projection): `Sexp::call(head, args.clone()).as_call()
// == Some((head, args.as_slice()))` sweeps the same
// representative input matrix as the composition-law pin —
// proves the (construct, soft-project) pair forms an
// `Iso((&str, Vec<Sexp>), symbol-headed Sexp::List)` on the
// call-form typed decomposition. Sibling-shape pin to the
// residual-axis's `Sexp::list(items.clone()).as_list() ==
// Some(items.as_slice())` round-trip
// (`sexp_list_constructor_round_trips_through_as_list`).
let samples: [(&str, Vec<Sexp>); 4] = [
("defcompiler", vec![]),
("defpoint", vec![Sexp::symbol("solo")]),
(
"defmonitor",
vec![Sexp::symbol("m"), Sexp::int(1), Sexp::int(2)],
),
(
"defnotify",
vec![
Sexp::Nil,
Sexp::List(vec![Sexp::symbol("nested"), Sexp::int(7)]),
Sexp::Quote(Box::new(Sexp::symbol("q"))),
],
),
];
for (head, args) in &samples {
let built = Sexp::call(*head, args.clone());
assert_eq!(
built.as_call(),
Some((*head, args.as_slice())),
"Sexp::call→as_call round-trip drifted for head={head:?} args={args:?}",
);
}
}
#[test]
fn sexp_call_constructor_round_trips_through_as_call_to_matching_keyword() {
// KEYWORD-MATCHED ROUND-TRIP LAW: `Sexp::call(head, args
// .clone()).as_call_to(head) == Some(args.as_slice())` for the
// head-matched keyword, and `.as_call_to(other)` returns `None`
// for every other keyword. Pins the (construct, keyword-typed-
// project) pair on the outer algebra — the same dispatch
// shape `compile_typed` / `compile_named_from_forms` route
// through post-macroexpansion.
let samples: [(&str, Vec<Sexp>); 4] = [
("defcompiler", vec![]),
("defpoint", vec![Sexp::symbol("obs")]),
("defmonitor", vec![Sexp::keyword("k"), Sexp::string("v")]),
(
"defalert-policy",
vec![Sexp::Nil, Sexp::List(vec![Sexp::symbol("body")])],
),
];
for (head, args) in &samples {
let built = Sexp::call(*head, args.clone());
assert_eq!(
built.as_call_to(head),
Some(args.as_slice()),
"Sexp::call→as_call_to(head) round-trip drifted for head={head:?} args={args:?}",
);
// Cross-keyword rejection: every DIFFERENT keyword misses.
let mismatched = format!("{head}-mismatch");
assert_eq!(
built.as_call_to(&mismatched),
None,
"Sexp::call→as_call_to(mismatch) leaked args for head={head:?}",
);
}
}
#[test]
fn sexp_call_constructor_composes_with_head_symbol_and_shape_and_structural_kind() {
// OUTER-ALGEBRA PROJECTION COMPOSITIONS: every `Sexp::call(head,
// args)` output projects through `head_symbol` /
// `shape` / `as_structural_kind` to the shape-invariants that
// pin the constructor's structural identity:
// * `head_symbol() == Some(head)` — the head-position
// projection recovers the constructor's head byte-for-byte;
// * `shape() == SexpShape::List` — a call form is a list-
// shaped `Sexp` on the residual carving;
// * `as_structural_kind() == Some(StructuralKind::List)` — the
// residual carving marker binds through the closed-set
// `StructuralKind` algebra at ONE arm.
// A regression that reroutes `Sexp::call` through a non-list
// arm (e.g. wrapping in `Sexp::Quote` after a copy-edit that
// type-checks) fails ALL THREE pins simultaneously. Sibling to
// the residual-axis's `Sexp::list` shape-composition pins
// (`sexp_list_constructor_composes_with_shape_via_sexp_shape_list`
// + `sexp_list_constructor_composes_with_as_structural_kind`).
let samples: [(&str, Vec<Sexp>); 4] = [
("head", vec![]),
("head", vec![Sexp::symbol("only")]),
(
"head",
vec![Sexp::keyword("k"), Sexp::string("v"), Sexp::boolean(false)],
),
(
"head",
vec![
Sexp::Nil,
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::List(vec![Sexp::symbol("nested")]),
],
),
];
for (head, args) in &samples {
let built = Sexp::call(*head, args.clone());
assert_eq!(
built.head_symbol(),
Some(*head),
"Sexp::call→head_symbol drifted from Some({head:?}) for args={args:?}",
);
assert_eq!(
built.shape(),
SexpShape::List,
"Sexp::call→shape drifted from SexpShape::List for head={head:?} args={args:?}",
);
assert_eq!(
built.as_structural_kind(),
Some(StructuralKind::List),
"Sexp::call→as_structural_kind drifted from Some(StructuralKind::List) for head={head:?} args={args:?}",
);
}
}
#[test]
fn sexp_call_constructor_accepts_diverse_head_and_arg_input_shapes() {
// INPUT-SHAPE FLEXIBILITY: the `impl Into<String>` head bound
// absorbs `&str` / `String` / `&String`, and the `impl
// IntoIterator<Item = Sexp>` args bound absorbs `Vec<Sexp>` /
// `[Sexp; N]` / `iter::empty()` / `.map(...)` chains — pin that
// all six representative input shapes reach the same canonical
// composition output. A regression that narrows either bound
// (e.g. requiring `String` on the head or `Vec<Sexp>` on the
// args) fails this pin. The two bounds are load-bearing for the
// ergonomy claim in the docstring — consumers threading a
// borrowed head + a `.map` chain must not need `.to_string()` /
// `.collect()` coercions before handing the pair to
// `Sexp::call`. Sibling to `Sexp::list`'s input-shape pin
// (`sexp_list_constructor_accepts_diverse_intoiterator_input_shapes`)
// and `Sexp::symbol`'s head-string absorption posture.
let expected = Sexp::List(vec![
Sexp::symbol("head"),
Sexp::symbol("a"),
Sexp::symbol("b"),
]);
// (&str, Vec<Sexp>) — the canonical borrowed-head + owned-args
// shape.
assert_eq!(
Sexp::call("head", vec![Sexp::symbol("a"), Sexp::symbol("b")]),
expected,
"Sexp::call drifted for (&str, Vec<Sexp>) input",
);
// (String, [Sexp; N]) — the owned-head + array-literal shape.
assert_eq!(
Sexp::call(String::from("head"), [Sexp::symbol("a"), Sexp::symbol("b")],),
expected,
"Sexp::call drifted for (String, [Sexp; N]) input",
);
// (&String, .map(...)) — the borrowed-owned-head + iterator-map
// chain shape.
let owned_head = String::from("head");
assert_eq!(
Sexp::call(&owned_head, ["a", "b"].iter().map(|s| Sexp::symbol(*s))),
expected,
"Sexp::call drifted for (&String, iter::map) input",
);
// (&str, iter::empty::<Sexp>()) — the zero-arg iterator shape,
// pinning the singleton-list emission (`(head)`) via the
// composition path.
assert_eq!(
Sexp::call("head", std::iter::empty::<Sexp>()),
Sexp::List(vec![Sexp::symbol("head")]),
"Sexp::call drifted for zero-arg iter::empty input",
);
// (&str, once(head_of_args).chain(tail_of_args)) — the head-
// then-rest args shape a builder decomposing an existing call
// form via `as_call` and re-emitting through this constructor
// threads through.
assert_eq!(
Sexp::call(
"head",
std::iter::once(Sexp::symbol("a")).chain([Sexp::symbol("b")]),
),
expected,
"Sexp::call drifted for (&str, once+chain) args input",
);
}
#[test]
fn sexp_call_constructor_body_matches_typed_composition_through_list_and_symbol() {
// EXPLICIT COMPOSITION-LAW PIN: `Sexp::call(head, args) ==
// Sexp::list(std::iter::once(Sexp::symbol(head)).chain(args))`
// BY DEFINITION — the constructor body IS this composition, and
// the pin exists so a regression that in-lines a hand-authored
// `Sexp::List(vec![Sexp::symbol(head), args...])` body (which
// would type-check and pass the projection round-trips) still
// surfaces here through the composition-path drift. This closes
// the "the constructor routes through the outer-algebra's
// atomic + residual construct families" invariant as a typed
// pin rather than a docstring claim.
let head = "defpoint";
let args = vec![
Sexp::symbol("obs"),
Sexp::keyword("class"),
Sexp::List(vec![Sexp::symbol("Gate"), Sexp::symbol("Observability")]),
];
assert_eq!(
Sexp::call(head, args.clone()),
Sexp::list(std::iter::once(Sexp::symbol(head)).chain(args.iter().cloned())),
"Sexp::call body drifted from the Sexp::list ∘ once(Sexp::symbol) ∘ chain composition for head={head:?}",
);
}
// ── Sexp::named_call — named-call-form (symbol-headed + NAME slot)
// construct ───────────────────────────────────────────────────────
//
// `Sexp::named_call(head, name, spec_args)` is the section-for-
// retraction dual of the soft-projection `Sexp::as_named_call_to(
// keyword) -> Option<Result<(&str, &[Sexp])>>` — it embeds a fresh
// `(head string, NAME string, spec args sequence)` triple into a
// symbol-headed `(head NAME spec_args…)` `Sexp::List` value at ONE
// site on the outer `Sexp` algebra, composing the call-form
// typed constructor `Sexp::call` (which itself composes the atomic
// `Sexp::symbol` head with the residual `Sexp::list` wrapper) with
// a NAME-slot `Sexp::symbol` embedding via `std::iter::once(
// Sexp::symbol(name)).chain(spec_args)`. Pre-lift the composition
// lived inline at every consumer that built a `(defX NAME …)`
// typed-domain named authoring form or a synthetic named-dispatch
// form — `Sexp::List(vec![Sexp::symbol(head), Sexp::symbol(name),
// spec_args...])` or `Sexp::call(head, std::iter::once(
// Sexp::symbol(name)).chain(spec_args))` was the welded quadruple
// open coding. Post-lift the closure binds at ONE typed-algebra
// method.
//
// These pins cover:
// (a) the composition law
// `Sexp::named_call(head, name, spec_args) == Sexp::call(
// head, std::iter::once(Sexp::symbol(name)).chain(spec_args))`
// — the constructor body is BY DEFINITION the two-method
// composition;
// (b) the round-trip law
// `Sexp::named_call(head, name, spec_args.clone())
// .as_named_call_to(head) == Some(Ok((name, spec_args
// .as_slice())))` — the (construct, named-project) named-
// call-form algebra dual closes at this pair, symmetric with
// the call-form's `Sexp::call(head, args.clone()).as_call()
// == Some((head, args.as_slice()))` round-trip;
// (c) the call-form projection composition
// `Sexp::named_call(head, name, spec_args)
// .as_call() == Some((head, [Sexp::symbol(name),
// spec_args…].as_slice()))` — the call-form soft-projection
// recovers `(head, [name, spec_args…])` with the NAME symbol
// as the first arg, threading the constructor's output
// through the encompassing call-form projection;
// (d) the keyword-matched round-trip law
// `Sexp::named_call(head, name, spec_args)
// .as_call_to(head) == Some([Sexp::symbol(name),
// spec_args…].as_slice())` — the keyword-typed projection
// recovers the NAME-headed args tail iff its argument
// matches the constructor's head;
// (e) the head-symbol composition law
// `Sexp::named_call(head, name, spec_args).head_symbol()
// == Some(head)` — the head-position projection recovers
// the constructor's head byte-for-byte;
// (f) the named-form gate composition law
// `crate::compile::split_name_slot(&Sexp::named_call(head,
// name, spec_args).as_call_to(head).unwrap(), head) == Ok((
// name, spec_args.as_slice()))` — the substrate's named-
// form arity + NAME-shape gate accepts every output of this
// constructor byte-for-byte, closing the section-for-
// retraction pair at the gate level as well as the
// projection level;
// (g) the outer-shape composition law
// `Sexp::named_call(head, name, spec_args).shape() ==
// SexpShape::List` and `.as_structural_kind() == Some(
// StructuralKind::List)` — the residual carving marker binds
// through the closed-set `StructuralKind` algebra at ONE
// arm, symmetric with `Sexp::call`'s residual-arm marker
// composition;
// (h) the input-shape flexibility
// `Sexp::named_call("h", "n", Vec<Sexp>)` / `Sexp::
// named_call(String, String, [Sexp; N])` / `Sexp::
// named_call(&str, &String, iter::map(...))` all agree with
// the canonical composition emission — the two `impl
// Into<String>` bounds + `impl IntoIterator<Item = Sexp>`
// args bound accept every reasonable input shape without a
// per-consumer `.to_string()` / `.collect::<Vec<Sexp>>()`
// coercion.
#[test]
fn sexp_named_call_constructor_body_matches_canonical_two_method_composition_across_representative_inputs(
) {
// COMPOSITION LAW: `Sexp::named_call(head, name, spec_args) ==
// Sexp::call(head, std::iter::once(Sexp::symbol(name)).chain(
// spec_args))` for every representative (empty-spec-args,
// single-spec-arg, multi-spec-arg, heterogeneous-inner,
// quote-family-wrapping-inner) sample. A regression that
// drifts the body (e.g. a copy-edit that switches to
// `Sexp::keyword(name)` for the NAME position, or that
// reorders `name` and `spec_args` in the chain) surfaces here
// BEFORE the projection pins fail. Sibling-shape pin to
// `Sexp::call`'s canonical-composition test posture.
let samples: [(&'static str, &'static str, Vec<Sexp>); 5] = [
("defcompiler", "solo", vec![]),
("defpoint", "obs", vec![Sexp::keyword("class")]),
(
"defmonitor",
"m",
vec![
Sexp::keyword("severity"),
Sexp::symbol("Warning"),
Sexp::keyword("threshold"),
Sexp::int(42),
],
),
(
"defcheck",
"coherent",
vec![
Sexp::List(vec![Sexp::symbol("crd-in-sync")]),
Sexp::string("body"),
Sexp::boolean(true),
],
),
(
"defalert-policy",
"outage",
vec![
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::Quasiquote(Box::new(Sexp::List(vec![
Sexp::symbol("template"),
Sexp::Unquote(Box::new(Sexp::symbol("var"))),
]))),
Sexp::UnquoteSplice(Box::new(Sexp::symbol("xs"))),
],
),
];
for (head, name, spec_args) in &samples {
let expected = Sexp::call(
*head,
std::iter::once(Sexp::symbol(*name)).chain(spec_args.iter().cloned()),
);
assert_eq!(
Sexp::named_call(*head, *name, spec_args.clone()),
expected,
"Sexp::named_call drifted from Sexp::call(head, once(symbol(name)).chain(spec_args)) for head={head:?} name={name:?} spec_args={spec_args:?}",
);
}
}
#[test]
fn sexp_named_call_constructor_round_trips_through_as_named_call_to() {
// ROUND-TRIP LAW (section-for-retraction with the named-form
// soft-projection): `Sexp::named_call(head, name, spec_args
// .clone()).as_named_call_to(head) == Some(Ok((name,
// spec_args.as_slice())))` sweeps the same representative
// input matrix — proves the (construct, named-project) pair
// forms an `Iso((&'static str, &str, Vec<Sexp>),
// (head-symbol-headed + NAME-symbol-second Sexp::List))` on
// the named-call-form typed decomposition. Sibling-shape pin
// to `Sexp::call`'s round-trip through `as_call` posture.
let samples: [(&'static str, &'static str, Vec<Sexp>); 4] = [
("defcompiler", "solo", vec![]),
("defpoint", "obs", vec![Sexp::keyword("class")]),
(
"defmonitor",
"m",
vec![Sexp::keyword("k"), Sexp::string("v")],
),
(
"defalert-policy",
"outage",
vec![Sexp::Nil, Sexp::List(vec![Sexp::symbol("body")])],
),
];
for (head, name, spec_args) in &samples {
let built = Sexp::named_call(*head, *name, spec_args.clone());
assert_eq!(
built.as_named_call_to(head).and_then(|res| res.ok()),
Some((*name, spec_args.as_slice())),
"Sexp::named_call→as_named_call_to round-trip drifted for head={head:?} name={name:?} spec_args={spec_args:?}",
);
}
}
#[test]
fn sexp_named_call_constructor_projects_through_as_call_with_name_first_arg() {
// CALL-FORM PROJECTION COMPOSITION: `Sexp::named_call(head,
// name, spec_args).as_call() == Some((head, [Sexp::symbol(
// name), spec_args…].as_slice()))` — the call-form soft-
// projection recovers `(head, [name, spec_args…])` with the
// NAME symbol as the first arg. Sibling-shape pin to the
// call-form encompassing algebra: the named-call constructor
// routes cleanly through the call-form projection AS A
// COMPOSITION.
let samples: [(&'static str, &'static str, Vec<Sexp>); 3] = [
("defcompiler", "solo", vec![]),
("defpoint", "obs", vec![Sexp::keyword("class")]),
(
"defmonitor",
"m",
vec![Sexp::keyword("threshold"), Sexp::int(42)],
),
];
for (head, name, spec_args) in &samples {
let built = Sexp::named_call(*head, *name, spec_args.clone());
let expected_args: Vec<Sexp> = std::iter::once(Sexp::symbol(*name))
.chain(spec_args.iter().cloned())
.collect();
assert_eq!(
built.as_call(),
Some((*head, expected_args.as_slice())),
"Sexp::named_call→as_call drifted for head={head:?} name={name:?} spec_args={spec_args:?}",
);
}
}
#[test]
fn sexp_named_call_constructor_round_trips_through_as_call_to_matching_keyword() {
// KEYWORD-MATCHED ROUND-TRIP LAW: `Sexp::named_call(head,
// name, spec_args.clone()).as_call_to(head) == Some([
// Sexp::symbol(name), spec_args…].as_slice())` for the head-
// matched keyword, and `.as_call_to(other) == None` for every
// other keyword. Pins the (construct, keyword-typed-project)
// pair on the outer algebra threading through the NAMED axis
// — the same dispatch shape `compile_named_from_forms` routes
// through post-macroexpansion.
let samples: [(&'static str, &'static str, Vec<Sexp>); 3] = [
("defcompiler", "solo", vec![]),
("defpoint", "obs", vec![Sexp::keyword("class")]),
(
"defmonitor",
"m",
vec![Sexp::keyword("k"), Sexp::string("v")],
),
];
for (head, name, spec_args) in &samples {
let built = Sexp::named_call(*head, *name, spec_args.clone());
let expected_args: Vec<Sexp> = std::iter::once(Sexp::symbol(*name))
.chain(spec_args.iter().cloned())
.collect();
assert_eq!(
built.as_call_to(head),
Some(expected_args.as_slice()),
"Sexp::named_call→as_call_to(head) round-trip drifted for head={head:?} name={name:?} spec_args={spec_args:?}",
);
// Cross-keyword rejection: every DIFFERENT keyword misses.
let mismatched = format!("{head}-mismatch");
assert_eq!(
built.as_call_to(&mismatched),
None,
"Sexp::named_call→as_call_to(mismatch) leaked args for head={head:?} name={name:?}",
);
}
}
#[test]
fn sexp_named_call_constructor_composes_with_head_symbol_and_shape_and_structural_kind() {
// OUTER-ALGEBRA PROJECTION COMPOSITIONS: every `Sexp::
// named_call(head, name, spec_args)` output projects through
// `head_symbol` / `shape` / `as_structural_kind` to the shape-
// invariants that pin the constructor's structural identity:
// * `head_symbol() == Some(head)` — the head-position
// projection recovers the constructor's head byte-for-byte;
// * `shape() == SexpShape::List` — a named call form is a
// list-shaped `Sexp` on the residual carving;
// * `as_structural_kind() == Some(StructuralKind::List)` —
// the residual carving marker binds through the closed-
// set `StructuralKind` algebra at ONE arm.
let samples: [(&'static str, &'static str, Vec<Sexp>); 3] = [
("head", "n", vec![]),
("head", "n", vec![Sexp::keyword("k"), Sexp::string("v")]),
(
"head",
"n",
vec![
Sexp::Nil,
Sexp::Quote(Box::new(Sexp::symbol("x"))),
Sexp::List(vec![Sexp::symbol("nested")]),
],
),
];
for (head, name, spec_args) in &samples {
let built = Sexp::named_call(*head, *name, spec_args.clone());
assert_eq!(
built.head_symbol(),
Some(*head),
"Sexp::named_call→head_symbol drifted from Some({head:?}) for name={name:?} spec_args={spec_args:?}",
);
assert_eq!(
built.shape(),
SexpShape::List,
"Sexp::named_call→shape drifted from SexpShape::List for head={head:?} name={name:?} spec_args={spec_args:?}",
);
assert_eq!(
built.as_structural_kind(),
Some(StructuralKind::List),
"Sexp::named_call→as_structural_kind drifted from Some(StructuralKind::List) for head={head:?} name={name:?} spec_args={spec_args:?}",
);
}
}
#[test]
fn sexp_named_call_constructor_output_passes_the_split_name_slot_gate() {
// NAMED-FORM GATE COMPOSITION LAW: `crate::compile::
// split_name_slot(&Sexp::named_call(head, name, spec_args)
// .as_call_to(head).unwrap(), head) == Ok((name, spec_args
// .as_slice()))` — the substrate's named-form arity + NAME-
// shape gate accepts every output of this constructor byte-
// for-byte, closing the section-for-retraction pair at the
// GATE level as well as the projection level. A regression
// that emits a value the gate rejects (e.g. a
// `NamedFormNonSymbolName` from a `Sexp::keyword(name)` NAME
// slot copy-edit) surfaces here even when the projection
// pins pass.
let samples: [(&'static str, &'static str, Vec<Sexp>); 4] = [
("defcompiler", "solo", vec![]),
("defpoint", "obs", vec![Sexp::keyword("class")]),
(
"defmonitor",
"m",
vec![Sexp::keyword("severity"), Sexp::symbol("Warning")],
),
(
"defalert-policy",
"outage",
vec![
Sexp::List(vec![Sexp::symbol("body")]),
Sexp::Quote(Box::new(Sexp::symbol("x"))),
],
),
];
for (head, name, spec_args) in &samples {
let built = Sexp::named_call(*head, *name, spec_args.clone());
let args_tail = built
.as_call_to(head)
.expect("Sexp::named_call output must pass Sexp::as_call_to(head)");
let gated = crate::compile::split_name_slot(args_tail, head)
.expect("Sexp::named_call output must pass split_name_slot");
assert_eq!(
gated,
(*name, spec_args.as_slice()),
"Sexp::named_call→split_name_slot round-trip drifted for head={head:?} name={name:?} spec_args={spec_args:?}",
);
}
}
#[test]
fn sexp_named_call_constructor_accepts_diverse_head_name_and_arg_input_shapes() {
// INPUT-SHAPE FLEXIBILITY: the two `impl Into<String>` bounds
// absorb `&str` / `String` / `&String` on both head + NAME
// positions, and the `impl IntoIterator<Item = Sexp>` spec-
// args bound absorbs `Vec<Sexp>` / `[Sexp; N]` / `iter::
// empty()` / `.map(...)` chains — pin that all five
// representative input shapes reach the same canonical
// composition output. A regression that narrows any bound
// fails this pin. Sibling to `Sexp::call`'s input-shape pin.
let expected = Sexp::List(vec![
Sexp::symbol("head"),
Sexp::symbol("name"),
Sexp::symbol("a"),
Sexp::symbol("b"),
]);
// (&str, &str, Vec<Sexp>) — the canonical borrowed shape.
assert_eq!(
Sexp::named_call("head", "name", vec![Sexp::symbol("a"), Sexp::symbol("b")]),
expected,
"Sexp::named_call drifted for (&str, &str, Vec<Sexp>) input",
);
// (String, String, [Sexp; N]) — the owned + array-literal
// shape.
assert_eq!(
Sexp::named_call(
String::from("head"),
String::from("name"),
[Sexp::symbol("a"), Sexp::symbol("b")],
),
expected,
"Sexp::named_call drifted for (String, String, [Sexp; N]) input",
);
// (&str, &String, .map(...)) — the borrowed-owned-name +
// iterator-map chain shape.
let owned_name = String::from("name");
assert_eq!(
Sexp::named_call(
"head",
&owned_name,
["a", "b"].iter().map(|s| Sexp::symbol(*s))
),
expected,
"Sexp::named_call drifted for (&str, &String, iter::map) input",
);
// (&str, &str, iter::empty::<Sexp>()) — the zero-spec-args
// iterator shape, pinning the two-element list emission
// (`(head name)`) via the composition path.
assert_eq!(
Sexp::named_call("head", "name", std::iter::empty::<Sexp>()),
Sexp::List(vec![Sexp::symbol("head"), Sexp::symbol("name")]),
"Sexp::named_call drifted for zero-spec-args iter::empty input",
);
// (&str, &str, once+chain) — the head-then-rest spec-args
// shape a builder decomposing an existing named call form
// via `as_named_call_to` and re-emitting through this
// constructor threads through.
assert_eq!(
Sexp::named_call(
"head",
"name",
std::iter::once(Sexp::symbol("a")).chain([Sexp::symbol("b")]),
),
expected,
"Sexp::named_call drifted for (&str, &str, once+chain) spec-args input",
);
}
#[test]
fn sexp_named_call_constructor_body_matches_typed_composition_through_call_and_symbol() {
// EXPLICIT COMPOSITION-LAW PIN: `Sexp::named_call(head, name,
// spec_args) == Sexp::call(head, std::iter::once(Sexp::symbol(
// name)).chain(spec_args))` BY DEFINITION — the constructor
// body IS this composition, and the pin exists so a
// regression that in-lines a hand-authored `Sexp::List(vec![
// Sexp::symbol(head), Sexp::symbol(name), spec_args...])`
// body (which would type-check and pass the projection round-
// trips) still surfaces here through the composition-path
// drift. Closes the "the constructor routes through
// `Sexp::call` + `Sexp::symbol`" invariant as a typed pin
// rather than a docstring claim.
let head = "defpoint";
let name = "observability-stack";
let spec_args = vec![
Sexp::keyword("class"),
Sexp::List(vec![Sexp::symbol("Gate"), Sexp::symbol("Observability")]),
];
assert_eq!(
Sexp::named_call(head, name, spec_args.clone()),
Sexp::call(
head,
std::iter::once(Sexp::symbol(name)).chain(spec_args.iter().cloned()),
),
"Sexp::named_call body drifted from the Sexp::call ∘ once(Sexp::symbol) ∘ chain composition for head={head:?} name={name:?}",
);
}
#[test]
fn sexp_quote_form_constructor_body_matches_quote_form_wrap_across_every_marker() {
// COMPOSITION-LAW PIN: `Sexp::quote_form(marker, inner) ==
// marker.wrap(inner)` for every `marker: QuoteForm` and every
// representative `inner: Sexp`. Sweeps `QuoteForm::ALL` × a
// representative gallery of inner bodies (atomic-payload,
// residual-Nil, residual-List, quote-family-nested,
// named-call-shaped) so a regression in the constructor body
// that inlined a per-variant match arm — e.g. `match marker {
// QuoteForm::Quote => Sexp::Quote(Box::new(inner)), … }` —
// that drifts one arm's tuple-variant target from the closed-
// set `QuoteForm::wrap` marker-to-wrapper mapping fails
// loudly at the first drifted variant. Pointer-inequality
// safe: `assert_eq!` compares by value, so the pin binds the
// structural composition path rather than any borrowed
// pointer identity.
let inners: Vec<Sexp> = vec![
Sexp::symbol("x"),
Sexp::keyword("k"),
Sexp::string("hello"),
Sexp::int(42),
Sexp::float(2.5),
Sexp::boolean(true),
Sexp::Nil,
Sexp::list(vec![Sexp::symbol("a"), Sexp::int(1)]),
Sexp::quote(Sexp::symbol("nested")),
Sexp::named_call(
"defpoint",
"observability-stack",
std::iter::empty::<Sexp>(),
),
];
for marker in QuoteForm::ALL {
for inner in &inners {
assert_eq!(
Sexp::quote_form(marker, inner.clone()),
marker.wrap(inner.clone()),
"Sexp::quote_form body drifted from QuoteForm::wrap composition at marker={marker:?} inner={inner:?}",
);
}
}
}
#[test]
fn sexp_quote_form_constructor_round_trips_through_as_quote_form_for_every_marker() {
// ROUND-TRIP LAW PIN (section-for-retraction with the outer-
// algebra soft-projection): for every `marker: QuoteForm` +
// representative `inner: Sexp`, `Sexp::quote_form(marker,
// inner.clone()).as_quote_form() == Some((marker, &inner))`.
// Proves the (construct, project) pair forms an isomorphism
// between (QuoteForm × Sexp) and the closed-set 4-of-12 quote-
// family carving of the outer `Sexp` algebra — a regression
// that emits a value the projection rejects (unreachable by
// the closed-set structure, since `QuoteForm::wrap` targets a
// quote-family arm exactly) or that drifts the marker
// recovered from the projection (e.g. swapping `Quote` ↔
// `Quasiquote` in the constructor's dispatch) fails loudly
// at the first drifted variant.
for marker in QuoteForm::ALL {
let inner = Sexp::List(vec![Sexp::keyword("body"), Sexp::string("data")]);
let wrapped = Sexp::quote_form(marker, inner.clone());
assert_eq!(
wrapped.as_quote_form(),
Some((marker, &inner)),
"Sexp::quote_form({marker:?}, _).as_quote_form() failed to round-trip — the (construct, project) pair on the outer algebra is not a section-for-retraction of Sexp::as_quote_form",
);
}
}
#[test]
fn sexp_quote_form_constructor_composes_with_as_quote_form_marker_and_shape() {
// MARKER-RECOVERING + OUTER-SHAPE COMPOSITION PIN: for every
// `marker: QuoteForm` + representative `inner: Sexp`, the
// constructor's output projects through the marker-only sibling
// `Sexp::as_quote_form_marker` back to the constructor's marker
// AND through the outer-shape projection `Sexp::shape` to the
// canonical `marker.sexp_shape()`. Pins the two independent
// projection compositions simultaneously so a regression that
// reroutes through a non-quote-family arm (which the outer-
// shape lattice would surface as `SexpShape::List` or
// `SexpShape::Nil`) fails BOTH pins at once.
for marker in QuoteForm::ALL {
let inner = Sexp::symbol("body");
let wrapped = Sexp::quote_form(marker, inner.clone());
assert_eq!(
wrapped.as_quote_form_marker(),
Some(marker),
"Sexp::quote_form({marker:?}, _).as_quote_form_marker() drifted from Some({marker:?})",
);
assert_eq!(
wrapped.shape(),
marker.sexp_shape(),
"Sexp::quote_form({marker:?}, _).shape() drifted from {marker:?}.sexp_shape()",
);
}
}
#[test]
fn sexp_quote_form_constructor_specializes_to_each_per_variant_sibling() {
// PER-VARIANT RESTRICTION LAW PIN: the four per-variant
// siblings ARE the marker-driven parent specialized on a
// compile-time-known marker — `Sexp::quote_form(QuoteForm::X,
// inner) == Sexp::x_variant(inner)` for every X ∈
// {Quote, Quasiquote, Unquote, UnquoteSplice}. Any regression
// that drifts the marker-driven parent from its per-variant
// siblings' single canonical composition site
// (`QuoteForm::X.wrap(inner)`) fails at the first drifted
// variant.
let inner = Sexp::symbol("body");
assert_eq!(
Sexp::quote_form(QuoteForm::Quote, inner.clone()),
Sexp::quote(inner.clone()),
"Sexp::quote_form(QuoteForm::Quote, _) drifted from Sexp::quote(_)",
);
assert_eq!(
Sexp::quote_form(QuoteForm::Quasiquote, inner.clone()),
Sexp::quasiquote(inner.clone()),
"Sexp::quote_form(QuoteForm::Quasiquote, _) drifted from Sexp::quasiquote(_)",
);
assert_eq!(
Sexp::quote_form(QuoteForm::Unquote, inner.clone()),
Sexp::unquote(inner.clone()),
"Sexp::quote_form(QuoteForm::Unquote, _) drifted from Sexp::unquote(_)",
);
assert_eq!(
Sexp::quote_form(QuoteForm::UnquoteSplice, inner.clone()),
Sexp::unquote_splice(inner),
"Sexp::quote_form(QuoteForm::UnquoteSplice, _) drifted from Sexp::unquote_splice(_)",
);
}
#[test]
fn sexp_quote_form_constructor_targets_matching_tuple_variant_for_every_marker() {
// TUPLE-VARIANT-TARGET PIN: `Sexp::quote_form(marker, inner)`
// must be structurally equal to `Sexp::X(Box::new(inner))` for
// the X matching the marker — pinned per variant against the
// hand-authored tuple-variant literal so a regression that
// reroutes the wrap through an off-by-one closed-set match
// (e.g. `QuoteForm::Quote → Sexp::Quasiquote`) surfaces at
// this shape pin even when the round-trip law happens to
// still project through the projection sibling (it wouldn't —
// but the pin gives a distinct, tuple-variant-anchored
// failure signature). Sibling-shape lift to the same-anchor
// pin the `QuoteForm::wrap` inner algebra already carries.
let inner = Sexp::string("payload");
assert_eq!(
Sexp::quote_form(QuoteForm::Quote, inner.clone()),
Sexp::Quote(Box::new(inner.clone())),
"Sexp::quote_form(QuoteForm::Quote, _) drifted from Sexp::Quote(Box::new(_)) canonical tuple-variant shape",
);
assert_eq!(
Sexp::quote_form(QuoteForm::Quasiquote, inner.clone()),
Sexp::Quasiquote(Box::new(inner.clone())),
"Sexp::quote_form(QuoteForm::Quasiquote, _) drifted from Sexp::Quasiquote(Box::new(_)) canonical tuple-variant shape",
);
assert_eq!(
Sexp::quote_form(QuoteForm::Unquote, inner.clone()),
Sexp::Unquote(Box::new(inner.clone())),
"Sexp::quote_form(QuoteForm::Unquote, _) drifted from Sexp::Unquote(Box::new(_)) canonical tuple-variant shape",
);
assert_eq!(
Sexp::quote_form(QuoteForm::UnquoteSplice, inner.clone()),
Sexp::UnquoteSplice(Box::new(inner)),
"Sexp::quote_form(QuoteForm::UnquoteSplice, _) drifted from Sexp::UnquoteSplice(Box::new(_)) canonical tuple-variant shape",
);
}
#[test]
fn sexp_unquote_form_constructor_body_matches_unquote_form_wrap_across_every_marker() {
// COMPOSITION-LAW PIN: `Sexp::unquote_form(marker, inner) ==
// marker.wrap(inner)` for every `marker: UnquoteForm` and every
// representative `inner: Sexp`. Sweeps `UnquoteForm::ALL` × a
// representative gallery of inner bodies (atomic-payload,
// residual-Nil, residual-List, quote-family-nested, unquote-
// subset-nested, named-call-shaped) so a regression that
// inlined a per-variant match arm — e.g. `match marker {
// UnquoteForm::Unquote => Sexp::Unquote(Box::new(inner)),
// UnquoteForm::Splice => Sexp::UnquoteSplice(Box::new(inner)) }`
// — that drifts one arm's tuple-variant target from the closed-
// set `UnquoteForm::wrap` marker-to-wrapper mapping fails
// loudly at the first drifted variant.
let inners: Vec<Sexp> = vec![
Sexp::symbol("x"),
Sexp::keyword("k"),
Sexp::string("hello"),
Sexp::int(42),
Sexp::float(2.5),
Sexp::boolean(true),
Sexp::Nil,
Sexp::list(vec![Sexp::symbol("a"), Sexp::int(1)]),
Sexp::quote(Sexp::symbol("nested")),
Sexp::unquote(Sexp::symbol("subnested")),
Sexp::named_call(
"defpoint",
"observability-stack",
std::iter::empty::<Sexp>(),
),
];
for marker in UnquoteForm::ALL {
for inner in &inners {
assert_eq!(
Sexp::unquote_form(marker, inner.clone()),
marker.wrap(inner.clone()),
"Sexp::unquote_form body drifted from UnquoteForm::wrap composition at marker={marker:?} inner={inner:?}",
);
}
}
}
#[test]
fn sexp_unquote_form_constructor_round_trips_through_as_unquote_for_every_marker() {
// ROUND-TRIP LAW PIN (section-for-retraction with the outer-
// algebra soft-projection): for every `marker: UnquoteForm` +
// representative `inner: Sexp`, `Sexp::unquote_form(marker,
// inner.clone()).as_unquote() == Some((marker, &inner))`.
// Proves the (construct, project) pair forms an isomorphism
// between (UnquoteForm × Sexp) and the closed-set 2-of-12
// template-substitution subset carving of the outer `Sexp`
// algebra — a regression that emits a value the projection
// rejects (e.g. drifting to a non-substitution quote-family
// arm like `Sexp::Quote`, which `as_unquote` filters out via
// `QuoteForm::as_unquote_form`) or that drifts the marker
// recovered from the projection (e.g. swapping `Unquote` ↔
// `Splice`) fails loudly at the first drifted variant.
for marker in UnquoteForm::ALL {
let inner = Sexp::List(vec![Sexp::keyword("body"), Sexp::string("data")]);
let wrapped = Sexp::unquote_form(marker, inner.clone());
assert_eq!(
wrapped.as_unquote(),
Some((marker, &inner)),
"Sexp::unquote_form({marker:?}, _).as_unquote() failed to round-trip — the (construct, project) pair on the outer algebra is not a section-for-retraction of Sexp::as_unquote",
);
}
}
#[test]
fn sexp_unquote_form_constructor_composes_with_as_unquote_form_and_shape() {
// MARKER-RECOVERING + OUTER-SHAPE COMPOSITION PIN: for every
// `marker: UnquoteForm` + representative `inner: Sexp`, the
// constructor's output projects through the marker-only sibling
// `Sexp::as_unquote_form` back to the constructor's marker AND
// through the outer-shape projection `Sexp::shape` to the
// canonical `marker.sexp_shape()`. Pins the two independent
// projection compositions simultaneously so a regression that
// reroutes through a non-substitution quote-family arm
// (`SexpShape::Quote` / `SexpShape::Quasiquote`) or through a
// non-quote-family arm (`SexpShape::List` / `SexpShape::Nil`)
// fails BOTH pins at once.
for marker in UnquoteForm::ALL {
let inner = Sexp::symbol("body");
let wrapped = Sexp::unquote_form(marker, inner.clone());
assert_eq!(
wrapped.as_unquote_form(),
Some(marker),
"Sexp::unquote_form({marker:?}, _).as_unquote_form() drifted from Some({marker:?})",
);
assert_eq!(
wrapped.shape(),
marker.sexp_shape(),
"Sexp::unquote_form({marker:?}, _).shape() drifted from {marker:?}.sexp_shape()",
);
}
}
#[test]
fn sexp_unquote_form_constructor_routes_through_superset_quote_form_via_to_quote_form() {
// SUPERSET-ROUTING COMPOSITION-LAW PIN: for every `marker:
// UnquoteForm` + representative `inner: Sexp`, `Sexp::unquote_form(
// marker, inner) == Sexp::quote_form(marker.to_quote_form(),
// inner)`. The subset-algebra construct routes through the
// SAME closed-set `QuoteForm::wrap` composition site the
// superset construct routes through — threaded via the typed
// 2-of-4 subset → superset projection `UnquoteForm::to_quote_form`.
// A regression that re-implements the subset construct on a
// parallel dispatch table (rather than composing through the
// superset construct's composition site) can still project
// through `as_unquote` correctly on the round-trip pin above,
// but will fail this pin because the constructed values compare
// equal only when both routes bind at the same closed-set
// `QuoteForm::wrap` arm. Structural sibling of the composition
// law `UnquoteForm::wrap` itself carries at ast.rs:2469 —
// `self.to_quote_form().wrap(inner)`.
for marker in UnquoteForm::ALL {
let inner = Sexp::List(vec![Sexp::symbol("outer"), Sexp::int(7)]);
assert_eq!(
Sexp::unquote_form(marker, inner.clone()),
Sexp::quote_form(marker.to_quote_form(), inner.clone()),
"Sexp::unquote_form({marker:?}, _) drifted from Sexp::quote_form({:?}, _) — subset-construct did not route through superset-construct via UnquoteForm::to_quote_form",
marker.to_quote_form(),
);
}
}
#[test]
fn sexp_unquote_form_constructor_specializes_to_each_per_variant_sibling() {
// PER-VARIANT RESTRICTION LAW PIN: the two per-variant siblings
// ARE the marker-driven parent specialized on a compile-time-
// known subset marker — `Sexp::unquote_form(UnquoteForm::X,
// inner) == Sexp::x_variant(inner)` for every X ∈ {Unquote,
// Splice}. Any regression that drifts the marker-driven parent
// from its per-variant siblings' single canonical composition
// site (`UnquoteForm::X.wrap(inner)` → `QuoteForm::X.wrap(inner)`)
// fails at the first drifted variant.
let inner = Sexp::symbol("body");
assert_eq!(
Sexp::unquote_form(UnquoteForm::Unquote, inner.clone()),
Sexp::unquote(inner.clone()),
"Sexp::unquote_form(UnquoteForm::Unquote, _) drifted from Sexp::unquote(_)",
);
assert_eq!(
Sexp::unquote_form(UnquoteForm::Splice, inner.clone()),
Sexp::unquote_splice(inner),
"Sexp::unquote_form(UnquoteForm::Splice, _) drifted from Sexp::unquote_splice(_)",
);
}
#[test]
fn sexp_unquote_form_constructor_targets_matching_tuple_variant_for_every_marker() {
// TUPLE-VARIANT-TARGET PIN: `Sexp::unquote_form(marker, inner)`
// must be structurally equal to `Sexp::X(Box::new(inner))` for
// the X matching the subset marker (`Unquote → Sexp::Unquote`,
// `Splice → Sexp::UnquoteSplice`) — pinned per variant against
// the hand-authored tuple-variant literal so a regression that
// reroutes the wrap through an off-by-one closed-set match
// (e.g. `UnquoteForm::Unquote → Sexp::UnquoteSplice`, or the
// subset→superset projection drifting `UnquoteForm::Unquote →
// QuoteForm::Quote` inside `to_quote_form`) surfaces at this
// shape pin with a distinct, tuple-variant-anchored failure
// signature. Sibling-shape lift to the same-anchor pin the
// `QuoteForm::wrap` inner algebra already carries on the
// superset 4-of-4 arms.
let inner = Sexp::string("payload");
assert_eq!(
Sexp::unquote_form(UnquoteForm::Unquote, inner.clone()),
Sexp::Unquote(Box::new(inner.clone())),
"Sexp::unquote_form(UnquoteForm::Unquote, _) drifted from Sexp::Unquote(Box::new(_)) canonical tuple-variant shape",
);
assert_eq!(
Sexp::unquote_form(UnquoteForm::Splice, inner.clone()),
Sexp::UnquoteSplice(Box::new(inner)),
"Sexp::unquote_form(UnquoteForm::Splice, _) drifted from Sexp::UnquoteSplice(Box::new(_)) canonical tuple-variant shape",
);
}
// ── `Atom::KEYWORD_MARKER` — the canonical `:` prefix routed through
// the four Keyword-round-trip sites (reader-entry classifier, Lisp
// canonical Display, JSON canonical projection, iac-forge canonical
// projection). Pins the constant value AND the four sites' composition
// through it so a regression that re-inlines any single site's byte
// literal drifts against these pins even when the rendered bytes still
// agree at that site.
#[test]
fn atom_keyword_marker_projects_canonical_colon_byte() {
assert_eq!(
Atom::KEYWORD_MARKER,
":",
"KEYWORD_MARKER byte drifted from the substrate-canonical `:` \
prefix — the reader-round-trip contract at Self::from_lexeme \
+ fmt::Display for Atom + Self::to_json + \
Self::to_iac_forge_sexpr all bind to this one constant.",
);
}
#[test]
fn atom_display_keyword_arm_routes_through_keyword_marker_constant() {
for name in ["parent", "class", "intent", "x", ""] {
let rendered = Atom::keyword(name).to_string();
let expected = format!("{}{name}", Atom::KEYWORD_MARKER);
assert_eq!(
rendered, expected,
"fmt::Display for Atom's Keyword arm drifted from the \
KEYWORD_MARKER composition at name={name:?}",
);
}
}
#[test]
fn atom_to_json_keyword_arm_routes_through_keyword_marker_constant() {
for name in ["parent", "class", "intent", "x", ""] {
let projected = Atom::keyword(name).to_json();
let expected = serde_json::Value::String(format!("{}{name}", Atom::KEYWORD_MARKER));
assert_eq!(
projected, expected,
"Atom::to_json's Keyword arm drifted from the \
KEYWORD_MARKER composition at name={name:?}",
);
}
}
#[test]
fn atom_from_lexeme_keyword_classifier_routes_through_keyword_marker_constant() {
for name in ["parent", "class", "intent", "x", ""] {
let lexeme = format!("{}{name}", Atom::KEYWORD_MARKER);
let classified = Atom::from_lexeme(&lexeme);
assert_eq!(
classified,
Atom::keyword(name),
"Atom::from_lexeme's Keyword classifier drifted from the \
KEYWORD_MARKER strip at lexeme={lexeme:?}",
);
}
}
#[test]
fn atom_keyword_marker_closes_reader_display_round_trip_for_every_name() {
// The load-bearing round-trip contract:
// Atom::from_lexeme(&Atom::keyword(name).to_string())
// == Atom::keyword(name)
// Both sides bind to Atom::KEYWORD_MARKER — the reader-entry
// classifier strips it via strip_prefix, the canonical-form
// Display re-emits it via write!. A future refactor that
// silently drifts ONE site's byte (e.g. by re-inlining `":"` at
// Display while migrating `strip_prefix` to a different byte)
// breaks THIS round-trip even when both bytes happen to agree on
// the surface — because the round-trip binds to the composition
// through the constant at BOTH endpoints.
for name in ["parent", "class", "intent", "x", "kebab-cased-name"] {
let a = Atom::keyword(name);
let round_tripped = Atom::from_lexeme(&a.to_string());
assert_eq!(
round_tripped, a,
"keyword round-trip through KEYWORD_MARKER drifted at \
name={name:?}",
);
}
}
// ── `Atom::KEYWORD_MARKER_LEAD` — the canonical `:` LEAD `char`
// of the `Atom::KEYWORD_MARKER` `&'static str` prefix, routed
// through the SEVEN test-surface sites that pre-lift each extracted
// the byte via `Atom::KEYWORD_MARKER.chars().next().expect(_)`
// (or `.unwrap()`) — the Keyword arm of the
// `Sexp::is_bare_atom_boundary` negative sweep AND the six cross-
// axis disjointness pins on the sibling marker-byte algebras
// (`SPLICE_DISCRIMINATOR`, `BOOL_LITERAL_LEAD`, `STR_DELIMITER`,
// `STR_ESCAPE_LEAD`, `LIST_OPEN` / `LIST_CLOSE`, `COMMENT_LEAD`,
// `COMMENT_TERM`). Sibling-shape tests to the `atom_bool_literal_lead_*`
// block below (Bool-family shared LEAD-byte axis) and the
// `atom_str_delimiter_*` / `atom_str_escape_lead_*` blocks below
// (Str-payload delimiter + escape-lead axes) — pins the SAME shape
// on the Keyword-prefix LEAD-byte axis of the closed-set outer
// [`Atom`] algebra.
#[test]
fn atom_keyword_marker_lead_projects_canonical_colon_char() {
// Pins the constant's exact `char` value so a typo (`';'`,
// `'.'`, `'!'`) or an accidental redefinition surfaces
// immediately. Sibling-shape pin to
// `atom_bool_literal_lead_projects_canonical_hash_char`
// (the Bool-family shared LEAD-byte axis) and
// `atom_str_delimiter_projects_canonical_double_quote_char`
// (the Str-payload delimiter axis) — pins the SAME shape on
// the Keyword-prefix LEAD-byte axis of the closed-set outer
// [`Atom`] algebra.
assert_eq!(
Atom::KEYWORD_MARKER_LEAD,
':',
"KEYWORD_MARKER_LEAD char drifted from the substrate- \
canonical `:` LEAD byte — the seven test-surface sites \
that pre-lift each extracted this byte from \
Atom::KEYWORD_MARKER via `.chars().next().expect(_)` all \
bind to this ONE constant.",
);
}
#[test]
fn atom_keyword_marker_lead_prefixes_keyword_marker() {
// STRUCTURAL ROUND-TRIP CONTRACT: the `&'static str` prefix
// `Atom::KEYWORD_MARKER` starts with the `char` LEAD byte
// `Atom::KEYWORD_MARKER_LEAD` — the projection law that binds
// the two typed constants on the outer [`Atom`] algebra. A
// regression that renames the `&'static str` (e.g. `"#:"` for
// a Racket-compat `#:name` keyword-arg port) OR the `char`
// (e.g. to `'.'` for a dotted-path prefix) without updating the
// other fails HERE — the structural invariant that
// `KEYWORD_MARKER_LEAD` IS the lead byte of `KEYWORD_MARKER`
// is what makes the seven consumer sites safe to route
// through the `char` constant instead of the `&'static str`
// projection. Sibling-shape pin to
// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`
// on the Bool-family axis: where that pin sweeps every `b:
// bool` spelling to prove BOTH spellings share the lead byte,
// this pin binds the one-char `KEYWORD_MARKER` prefix to its
// projected lead byte via a single `starts_with` call.
//
// Load-bearing: this pin IS the "the two typed constants
// project onto each other" invariant that lets the seven
// consumer sites bind to the `char` constant instead of the
// `.chars().next().expect(_)` chain on the `&'static str`.
assert!(
Atom::KEYWORD_MARKER.starts_with(Atom::KEYWORD_MARKER_LEAD),
"Atom::KEYWORD_MARKER `{}` does NOT start with \
Atom::KEYWORD_MARKER_LEAD `{:?}` — the two typed constants \
have drifted apart on the closed-set outer [`Atom`] \
algebra; the seven consumer sites that route through the \
`char` constant instead of the `&'static str` projection \
would silently disagree with the reader's actual `:foo` \
classification.",
Atom::KEYWORD_MARKER,
Atom::KEYWORD_MARKER_LEAD,
);
}
#[test]
fn atom_keyword_marker_lead_distinct_from_every_other_algebra_marker() {
// CROSS-AXIS DISJOINTNESS PIN: `Atom::KEYWORD_MARKER_LEAD`
// MUST NOT alias any sibling outer-marker `char` on the
// substrate's other closed-set algebras — the Str-payload
// delimiter (`Atom::STR_DELIMITER`), Str-payload escape lead
// (`Atom::STR_ESCAPE_LEAD`), Bool-family shared lead
// (`Atom::BOOL_LITERAL_LEAD`), the paired list delimiters
// (`Sexp::LIST_OPEN` / `Sexp::LIST_CLOSE`), the paired line-
// comment delimiters (`Sexp::COMMENT_LEAD` /
// `Sexp::COMMENT_TERM`), every `QuoteForm::lead_char`
// projection, AND `QuoteForm::SPLICE_DISCRIMINATOR`. A
// collision would silently break the reader's outer dispatch:
// a `:`-prefixed bare atom `:foo` would collide with whichever
// marker it aliased. Sibling-shape pin to
// `atom_bool_literal_lead_distinct_from_every_other_algebra_marker`
// (the Bool-family LEAD-byte axis) — pins the SAME shape at
// the Keyword-prefix LEAD-byte axis. A future outer-marker
// extension that collided with `':'` fails HERE at the cross-
// axis enumeration.
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
Atom::STR_DELIMITER,
"KEYWORD_MARKER_LEAD collides with STR_DELIMITER — a bare \
`:foo` would ambiguously begin a keyword AND open a \
string.",
);
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
Atom::STR_ESCAPE_LEAD,
"KEYWORD_MARKER_LEAD collides with STR_ESCAPE_LEAD — the \
reader's Str-escape lead byte would alias the Keyword- \
prefix lead byte.",
);
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
Atom::BOOL_LITERAL_LEAD,
"KEYWORD_MARKER_LEAD collides with BOOL_LITERAL_LEAD — a \
bare `:foo` would ambiguously begin a keyword AND \
classify as a Bool.",
);
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
Sexp::LIST_OPEN,
"KEYWORD_MARKER_LEAD collides with LIST_OPEN — a bare \
`:foo` would ambiguously begin a keyword AND open a list.",
);
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
Sexp::LIST_CLOSE,
"KEYWORD_MARKER_LEAD collides with LIST_CLOSE — a bare \
`:foo` would ambiguously begin a keyword AND close a list.",
);
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
Sexp::COMMENT_LEAD,
"KEYWORD_MARKER_LEAD collides with COMMENT_LEAD — a bare \
`:foo` would ambiguously begin a keyword AND begin a \
comment.",
);
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
Sexp::COMMENT_TERM,
"KEYWORD_MARKER_LEAD collides with COMMENT_TERM — the \
reader's line-comment discard loop would terminate on \
the SAME byte the from_lexeme keyword-prefix arm binds to.",
);
for qf in QuoteForm::ALL {
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
qf.lead_char(),
"KEYWORD_MARKER_LEAD collides with QuoteForm::{qf:?}'s \
lead_char — a bare `:foo` would ambiguously begin a \
keyword AND begin a quote-family prefix.",
);
}
assert_ne!(
Atom::KEYWORD_MARKER_LEAD,
QuoteForm::SPLICE_DISCRIMINATOR,
"KEYWORD_MARKER_LEAD collides with SPLICE_DISCRIMINATOR — \
the reader's `,@` splice-promotion peek byte would alias \
the Keyword-prefix lead byte.",
);
}
// ── `Atom::keyword_qualified` — the ONE projection composing
// `Atom::KEYWORD_MARKER` with a bare keyword name across the three
// canonical-rendering Keyword-arm sites (JSON, iac-forge, Lisp
// Display). Pins the composition + the round-trip law with
// `Atom::from_lexeme` + the path-uniformity at every routed site so
// a regression that re-inlines any single site's `format!("{}{s}",
// KEYWORD_MARKER)` composition drifts against these pins even when
// the rendered bytes still agree at that site.
#[test]
fn atom_keyword_qualified_composes_keyword_marker_with_bare_name() {
// BYTE-COMPOSITION CONTRACT: `Atom::keyword_qualified(name)`
// renders exactly `Atom::KEYWORD_MARKER ++ name` for every
// bare-name input — the ONE typed composition of the Keyword-
// prefix constant with a bare-name payload on the [`Atom`]
// algebra. Sibling-shape pin to
// `atom_bool_literal_projects_canonical_scheme_spellings`
// (the Bool-family canonical-rendering axis): where that pin
// sweeps the CLOSED `bool` domain to its canonical spellings,
// this pin sweeps a representative set of bare-name inputs
// (empty, single-char, dashed, dotted, unicode) through the
// Keyword-family projection to prove the composition holds
// uniformly over the open-set bare-name domain.
for name in [
"",
"x",
"class",
"parent",
"point-type",
"kebab-case-name",
"dotted.path",
"with_underscore",
"α",
] {
let expected = format!("{}{name}", Atom::KEYWORD_MARKER);
assert_eq!(
Atom::keyword_qualified(name),
expected,
"Atom::keyword_qualified({name:?}) drifted from the \
substrate-canonical composition \
`Atom::KEYWORD_MARKER ++ name` — the three canonical- \
rendering Keyword-arm sites (to_json, to_iac_forge_sexpr, \
Display) all bind to this ONE projection.",
);
}
}
#[test]
fn atom_keyword_qualified_starts_with_keyword_marker() {
// STRUCTURAL PREFIX CONTRACT: for every bare-name input,
// `Atom::keyword_qualified(name).starts_with(Atom::KEYWORD_MARKER)`.
// The projection MUST begin with the canonical
// [`Atom::KEYWORD_MARKER`] prefix so
// [`Atom::from_lexeme`]'s `s.strip_prefix(Self::KEYWORD_MARKER)`
// classifier gate matches every rendered qualified keyword.
// Sibling-shape pin to
// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`
// (the Bool-family shared-lead-byte axis): where that pin
// sweeps every `b: bool` to prove BOTH spellings share the
// lead byte, this pin sweeps every representative bare-name
// to prove EVERY qualified rendering starts with the shared
// Keyword-family prefix.
for name in ["", "x", "class", "parent", "point-type", "α"] {
let qualified = Atom::keyword_qualified(name);
assert!(
qualified.starts_with(Atom::KEYWORD_MARKER),
"Atom::keyword_qualified({name:?}) = {qualified:?} does \
NOT start with Atom::KEYWORD_MARKER `{}` — the \
projection has drifted from its structural prefix \
contract; Atom::from_lexeme's `strip_prefix` classifier \
gate would silently disagree with the rendered \
qualified keyword.",
Atom::KEYWORD_MARKER,
);
}
}
#[test]
fn atom_from_lexeme_inverts_keyword_qualified_on_bare_name() {
// ROUND-TRIP CONTRACT (typed-EXIT rendering ↔ typed-ENTRY
// classification): [`Atom::from_lexeme`] is the LEFT-inverse
// of [`Atom::keyword_qualified`] on the Keyword-payload
// subset — i.e. `Atom::from_lexeme(&Atom::keyword_qualified(n))
// == Atom::Keyword(n.to_owned())` for every bare `name` that
// does NOT itself parse as a Bool spelling, integer, or float
// (the four typed-entry classification arms preceding the
// KEYWORD_MARKER-prefix arm at `from_lexeme`).
//
// A regression that drifts EITHER the composition (this
// projection) OR the classification (from_lexeme's
// strip_prefix arm) surfaces at THIS pin rather than as a
// silent Keyword-round-trip drift at a downstream consumer.
// Sibling-shape pin to
// `atom_from_lexeme_round_trips_through_bool_literal_for_every_bool`
// (the Bool-family round-trip axis) — pins the SAME shape at
// the Keyword-family round-trip axis of the closed-set outer
// [`Atom`] algebra.
for name in [
"x",
"class",
"parent",
"point-type",
"kebab-case-name",
"dotted.path",
"with_underscore",
"α",
] {
let qualified = Atom::keyword_qualified(name);
let classified = Atom::from_lexeme(&qualified);
assert_eq!(
classified,
Atom::Keyword(name.to_owned()),
"Atom::from_lexeme({qualified:?}) drifted from \
Atom::Keyword({name:?}) — the round-trip law between \
Atom::keyword_qualified (typed-EXIT canonical \
rendering) and Atom::from_lexeme's strip_prefix arm \
(typed-ENTRY classification) has broken on the \
Keyword-family axis of the closed-set outer [`Atom`] \
algebra.",
);
}
}
#[test]
fn atom_display_keyword_arm_agrees_with_keyword_qualified_bytes() {
// DISPLAY BYTE-IDENTITY PIN: [`fmt::Display for Atom`]'s
// [`Atom::Keyword`] arm keeps its allocation-free
// `write!(f, "{}{s}", Self::KEYWORD_MARKER)` composition
// (Display is called at every canonical-rendering surface
// that composes via `format!("{sexp}")` — avoiding the
// allocation is load-bearing on tokenizer-adjacent hot paths
// like `checks.lisp`'s exhaustive `defcheck` rendering) but
// MUST produce byte-identical output to
// [`Atom::keyword_qualified`]. Otherwise the three canonical-
// rendering surfaces (Display, to_json, to_iac_forge_sexpr)
// would silently disagree on the qualified-keyword bytes even
// though two of the three route through the typed projection.
//
// Load-bearing: this pin IS the "Display's inline write! and
// the typed projection agree byte-for-byte" invariant that
// lets Display keep the zero-alloc path while to_json /
// to_iac_forge_sexpr collapse onto the ONE algebra site.
for name in [
"",
"x",
"class",
"parent",
"point-type",
"kebab-case-name",
"α",
] {
let atom = Atom::Keyword(name.to_owned());
let via_display = atom.to_string();
let via_projection = Atom::keyword_qualified(name);
assert_eq!(
via_display, via_projection,
"fmt::Display for Atom's Keyword arm drifted from \
Atom::keyword_qualified on name {name:?} — the \
write! path and the typed projection have disagreed \
on the qualified-keyword bytes.",
);
}
}
#[test]
fn atom_to_json_keyword_arm_routes_through_keyword_qualified() {
// PATH-UNIFORMITY GUARD: [`Atom::to_json`]'s [`Atom::Keyword`]
// arm's rendered String value MUST equal
// [`Atom::keyword_qualified`] on the same bare name — the
// FIRST of the two routed sites is bound to the typed
// projection. A regression that re-inlines the `format!("{}{s}",
// Self::KEYWORD_MARKER)` composition at this arm without
// updating the projection (or vice versa) fails HERE.
// Sibling-shape pin to
// `atom_to_iac_forge_sexpr_keyword_arm_routes_through_keyword_qualified`
// on the iac-forge canonical-attestation-form axis: where that
// pin binds the iac-forge arm's Symbol payload, this pin binds
// the JSON arm's String payload.
for name in ["", "x", "class", "parent", "α"] {
let atom = Atom::Keyword(name.to_owned());
let via_json = atom.to_json();
let expected = serde_json::Value::String(Atom::keyword_qualified(name));
assert_eq!(
via_json, expected,
"Atom::to_json's Keyword arm drifted from \
Atom::keyword_qualified on name {name:?} — the JSON \
canonical-rendering site has diverged from the typed \
algebra projection.",
);
}
}
// ── `Atom::bool_literal` — the ONE projection routing the closed-set
// `bool` domain through its canonical Scheme spelling across the two
// Bool-round-trip sites (reader-entry classifier, Lisp canonical
// Display). Pins the projection's spellings for BOTH bool values AND
// both sites' composition through it so a regression that re-inlines
// any single site's byte literal drifts against these pins even when
// the rendered bytes still agree at that site.
#[test]
fn atom_bool_literal_projects_canonical_scheme_spellings() {
assert_eq!(
Atom::bool_literal(true),
"#t",
"Atom::bool_literal(true) drifted from the substrate-canonical \
Scheme spelling `#t` — the reader-round-trip contract at \
Self::from_lexeme + fmt::Display for Atom both bind to this \
projection.",
);
assert_eq!(
Atom::bool_literal(false),
"#f",
"Atom::bool_literal(false) drifted from the substrate-canonical \
Scheme spelling `#f` — the reader-round-trip contract at \
Self::from_lexeme + fmt::Display for Atom both bind to this \
projection.",
);
}
#[test]
fn atom_bool_literal_partitions_the_closed_bool_domain_injectively() {
// Sanity pin on the projection's shape: the two spellings partition
// the closed-set `bool` domain injectively (`true` and `false` do
// NOT alias to the same byte) — otherwise `from_lexeme` on either
// spelling would classify to a single Bool variant, silently
// collapsing the typed distinction at the reader-entry boundary.
assert_ne!(
Atom::bool_literal(true),
Atom::bool_literal(false),
"Atom::bool_literal collapsed the closed-set `bool` domain — \
both bools projected to the same Scheme spelling, breaking \
the reader-entry classifier's injection property.",
);
}
#[test]
fn atom_display_bool_arm_routes_through_bool_literal_projection() {
for b in [true, false] {
let rendered = Atom::boolean(b).to_string();
let expected = Atom::bool_literal(b);
assert_eq!(
rendered, expected,
"fmt::Display for Atom's Bool arm drifted from the \
bool_literal composition at b={b:?}",
);
}
}
#[test]
fn atom_from_lexeme_bool_classifier_routes_through_bool_literal_projection() {
for b in [true, false] {
let lexeme = Atom::bool_literal(b);
let classified = Atom::from_lexeme(lexeme);
assert_eq!(
classified,
Atom::boolean(b),
"Atom::from_lexeme's Bool classifier drifted from the \
bool_literal composition at lexeme={lexeme:?}",
);
}
}
#[test]
fn atom_bool_literal_closes_reader_display_round_trip_for_both_variants() {
// The load-bearing round-trip contract:
// Atom::from_lexeme(&Atom::boolean(b).to_string())
// == Atom::boolean(b)
// Both sides bind to Atom::bool_literal — the reader-entry
// classifier gates on `s == Self::bool_literal(true|false)`, the
// canonical-form Display re-emits it via
// `f.write_str(Self::bool_literal(*b))`. A future refactor that
// silently drifts ONE site's byte (e.g. by re-inlining `"#t"` at
// Display while migrating the classifier gate to a different
// spelling) breaks THIS round-trip even when both bytes happen to
// agree on the surface — because the round-trip binds to the
// composition through the projection at BOTH endpoints.
for b in [true, false] {
let a = Atom::boolean(b);
let round_tripped = Atom::from_lexeme(&a.to_string());
assert_eq!(
round_tripped, a,
"bool round-trip through bool_literal drifted at b={b:?}",
);
}
}
#[test]
fn atom_true_literal_projects_canonical_pound_t_bytes() {
// Pins the exact `"#t"` bytes at the typed constant. A
// regression that drifts the constant (e.g. Common-Lisp-compat
// typo `"T"`, JSON-compat typo `"true"`, Racket-compat typo
// `"#true"`, or an accidental case swap `"#T"`) fails-loudly
// here. This is the single site the substrate's canonical-
// Scheme `true` spelling resolves to; every downstream consumer
// (`Atom::bool_literal`'s `true`-arm, `Atom::from_lexeme`'s
// reader-entry gate, `fmt::Display for Atom`'s `Bool(true)`
// arm, `Atom::BOOL_LITERALS[0]`) routes through this constant.
// Sibling posture to
// `macro_def_head_defmacro_keyword_projects_canonical_defmacro_bytes`
// on the head-keyword algebra.
assert_eq!(
Atom::TRUE_LITERAL,
"#t",
"Atom::TRUE_LITERAL drifted from the substrate-canonical \
Scheme spelling `#t` — the reader-entry classifier at \
Atom::from_lexeme + fmt::Display for Atom + \
Atom::bool_literal's true-arm ALL bind to this constant."
);
}
#[test]
fn atom_false_literal_projects_canonical_pound_f_bytes() {
// Pins the exact `"#f"` bytes at the typed constant. Peer of
// `atom_true_literal_projects_canonical_pound_t_bytes` on the
// `false` element of the closed `bool` domain.
assert_eq!(
Atom::FALSE_LITERAL,
"#f",
"Atom::FALSE_LITERAL drifted from the substrate-canonical \
Scheme spelling `#f` — the reader-entry classifier at \
Atom::from_lexeme + fmt::Display for Atom + \
Atom::bool_literal's false-arm ALL bind to this constant."
);
}
#[test]
fn atom_bool_literal_routes_through_typed_per_variant_constants() {
// PATH-UNIFORMITY: the inherent `Atom::bool_literal(b)` method
// MUST return the per-variant `pub const` byte-for-byte for
// each `b: bool`. A regression that reverts ONE arm to an
// inline `"#t"` / `"#f"` string literal (e.g. a merge-conflict
// resolution that picked the pre-lift form) silently
// reintroduces the ≥2 PRIME-DIRECTIVE trigger the lift
// resolved — this test catches that by pinning each arm's
// return value to the constant, so the two paths (inline vs.
// typed constant) cannot both hold. Sibling posture to
// `macro_def_head_keyword_method_routes_through_typed_constants`
// on the head-keyword algebra.
assert_eq!(
Atom::bool_literal(true),
Atom::TRUE_LITERAL,
"Atom::bool_literal(true) drifted from Atom::TRUE_LITERAL — \
the `true`-arm reverted to an inline literal"
);
assert_eq!(
Atom::bool_literal(false),
Atom::FALSE_LITERAL,
"Atom::bool_literal(false) drifted from Atom::FALSE_LITERAL \
— the `false`-arm reverted to an inline literal"
);
}
#[test]
fn atom_bool_literals_has_expected_cardinality() {
// Cardinality contract: `Self::BOOL_LITERALS.len() == 2` —
// pinned at the declaration site by rustc's forced-arity check
// on `[&'static str; 2]`. This test surfaces the arity as a
// fail-loud runtime pin so a future refactor that switches the
// array type to `&[&'static str]` (dropping the compile-time
// arity forcing) doesn't silently loosen the closed-set
// discipline the family relies on. The `N == 2` is pinned by
// the mathematics of the closed `bool` domain; a future tri-
// valued-logic extension surfaces at THIS pin. Sibling posture
// to `macro_def_head_keywords_has_expected_cardinality` on the
// head-keyword algebra AND to
// `macro_params_lambda_list_keywords_has_expected_cardinality`
// on the CL lambda-list-keyword family.
assert_eq!(
Atom::BOOL_LITERALS.len(),
2,
"Atom::BOOL_LITERALS cardinality drifted from 2 — the \
closed `bool` domain admits exactly two spellings by \
construction; a tri-valued extension surfaces here"
);
}
#[test]
fn atom_bool_literals_align_with_bool_literal_by_index() {
// ALIGNMENT CONTRACT: `Self::BOOL_LITERALS[i] ==
// Self::bool_literal([true, false][i])` element-wise. The
// `[true, false]` sweep order is the canonical declaration
// order every existing sibling test in the crate uses; a
// regression that reorders ONE array without reordering the
// other silently misaligns every `zip([true, false],
// Self::BOOL_LITERALS)` consumer (LSP completion providers,
// metric-label emitters, coverage reporters). Sibling posture
// to `macro_def_head_keywords_align_with_all_by_index` on the
// head-keyword algebra.
for (i, b) in [true, false].iter().enumerate() {
assert_eq!(
Atom::BOOL_LITERALS[i],
Atom::bool_literal(*b),
"Atom::BOOL_LITERALS[{i}] `{kw}` drifted from \
Atom::bool_literal({b:?}) `{via_variant}` — the \
canonical declaration order of the ALL array and the \
bool_literal projection must match element-wise",
kw = Atom::BOOL_LITERALS[i],
via_variant = Atom::bool_literal(*b),
);
}
}
#[test]
fn atom_bool_literals_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: the two `&'static str` spellings on
// the bool-spelling algebra MUST differ so the reader-entry
// classifier's `s == Self::bool_literal(true|false)` cascade
// cannot route both bools through the same arm — otherwise
// `from_lexeme` on either spelling would classify to a single
// Bool variant, silently collapsing the typed distinction at
// the reader-entry boundary. Family-wide sweep over
// `BOOL_LITERALS × BOOL_LITERALS` — supersedes any single
// per-pair assertion and picks up new spellings mechanically
// (should the closed `bool` domain ever extend). Sibling
// posture to `macro_def_head_keywords_pairwise_distinct` on the
// head-keyword algebra AND to
// `atom_bool_literal_partitions_the_closed_bool_domain_injectively`
// on the direct-projection axis.
for (i, a) in Atom::BOOL_LITERALS.iter().enumerate() {
for (j, b) in Atom::BOOL_LITERALS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"Atom::BOOL_LITERALS[{i}] `{a}` collides with \
Atom::BOOL_LITERALS[{j}] `{b}` — the reader-entry \
classifier's cascade would route two bools through \
the same arm"
);
}
}
}
#[test]
fn atom_bool_literals_all_route_through_bool_literal_leading_byte() {
// Structural round-trip pin composed with the algebra's
// `Atom::BOOL_LITERAL_LEAD` axis peer: every entry of
// `Self::BOOL_LITERALS` MUST start with `Self::BOOL_LITERAL_LEAD`.
// The lead-byte-prefixes-spelling law from
// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`
// sweeps [true, false] through `bool_literal`; THIS test
// sweeps the same invariant over the `BOOL_LITERALS` array
// directly, catching a regression where a per-role constant
// drifts from the shared lead byte (e.g. `FALSE_LITERAL` set
// to `"~f"` while `bool_literal(false)` still returns
// `FALSE_LITERAL`, which would preserve the projection
// contract but break the lead-byte contract). Sibling posture
// to `macro_def_head_keywords_all_round_trip_through_from_str`
// on the head-keyword algebra.
for kw in Atom::BOOL_LITERALS {
assert!(
kw.starts_with(Atom::BOOL_LITERAL_LEAD),
"Atom::BOOL_LITERALS entry `{kw}` does NOT start with \
Atom::BOOL_LITERAL_LEAD ({lead:?}) — the per-role \
constant drifted from the shared lead byte",
lead = Atom::BOOL_LITERAL_LEAD,
);
}
}
// ── `Atom::BOOL_LITERAL_LEAD` — the canonical `'#'` char shared
// across BOTH `Atom::bool_literal` spellings (`"#t"` for `true`,
// `"#f"` for `false`). Sibling-shape tests to the
// `atom_bool_literal_*` block above (the two-char spelling axis
// of the Bool payload) — where those pins bind the two-char
// Scheme spelling of each `bool` payload, THESE tests bind the
// ONE shared lead byte of the two spellings onto the closed-set
// outer [`Atom`] algebra so a hash-prefix reader-family
// extension (`#\char`, `#(vector)`, `#|block-comment|#`, `#;
// datum-comment`) lands at ONE constant on the algebra.
#[test]
fn atom_bool_literal_lead_projects_canonical_hash_char() {
// Pins the constant's exact `char` value so a typo (`'#'`
// vs. `'$'`, `'@'`, or `'!'`) or an accidental redefinition
// surfaces immediately. Sibling-shape pin to
// `atom_str_delimiter_projects_canonical_double_quote_char`
// (Str-delimiter axis) and
// `atom_str_escape_lead_projects_canonical_backslash_char`
// (Str-escape-lead axis) — pins the SAME shape on the
// Bool-family lead-byte axis of the closed-set [`Atom`]
// algebra.
assert_eq!(
Atom::BOOL_LITERAL_LEAD,
'#',
"BOOL_LITERAL_LEAD char drifted from the substrate-\
canonical `#` Bool-family lead byte — the disjointness \
contract at is_bare_atom_boundary's negative sweep AND \
the QuoteForm::SPLICE_DISCRIMINATOR non-collision pin \
both bind to this ONE constant.",
);
}
#[test]
fn atom_bool_literal_lead_prefixes_every_bool_literal_spelling() {
// Structural round-trip pin — the (BOOL_LITERAL_LEAD,
// bool_literal spelling) pairing binds at ONE algebra layer:
// for every `b: bool`, `Atom::bool_literal(b)` MUST start
// with `Atom::BOOL_LITERAL_LEAD`. A regression that drifts
// EITHER the constant OR the two `bool_literal` arms
// surfaces here rather than at a silent bool-family reader
// drift where `#t` / `#f` classify as `Atom::Symbol` instead
// of `Atom::Bool`.
//
// Load-bearing across both `b: bool` values because the
// structural invariant IS "both spellings share the lead
// byte" — sweeps the closed `bool` domain so a hypothetical
// regression that renamed ONE spelling only (e.g. moved
// `"#f"` to `"~f"`) fails at THIS pin even though the
// constant AND the sibling spelling both agreed.
//
// Sibling-shape peer of
// `atom_bool_literal_closes_reader_display_round_trip_for_both_variants`
// one axis over: that test binds the (spelling, typed Bool
// variant) round-trip through the reader/Display; THIS test
// binds the (lead byte, spelling) prefix invariant at the
// atomic-algebra layer directly.
for b in [true, false] {
let spelling = Atom::bool_literal(b);
assert!(
spelling.starts_with(Atom::BOOL_LITERAL_LEAD),
"Atom::bool_literal({b:?}) = {spelling:?} does NOT \
start with BOOL_LITERAL_LEAD ({:?}) — the structural \
invariant \"both bool_literal spellings share the \
lead byte\" broke at b={b:?}",
Atom::BOOL_LITERAL_LEAD,
);
}
}
#[test]
fn atom_bool_literal_lead_distinct_from_every_other_algebra_marker() {
// Cross-axis disjointness pin: BOOL_LITERAL_LEAD's byte MUST
// NOT alias any other closed-set outer-marker byte the
// reader's tokenizer specialises on — otherwise a bare `#t`
// / `#f` lexeme would ambiguously route through the
// colliding arm AND the bool classifier. Sibling-shape pin
// to `sexp_comment_term_distinct_from_every_non_whitespace_algebra_marker`
// (COMMENT_TERM axis) — enumerates every closed-set outer-
// marker char AND asserts non-collision on the Bool-family
// lead-byte axis.
//
// The enumerated set spans THREE type namespaces and every
// canonical reader byte the substrate exposes:
// * `Sexp::LIST_OPEN` / `LIST_CLOSE` / `COMMENT_LEAD` /
// `COMMENT_TERM` — outer-structural + reader-discard
// * `Atom::STR_DELIMITER` / `STR_ESCAPE_LEAD` — atomic-
// payload delimiter + escape lead
// * `Atom::KEYWORD_MARKER`'s lead byte — atomic-payload
// prefix marker
// * every `QuoteForm::lead_char` projection AND
// `QuoteForm::SPLICE_DISCRIMINATOR` — homoiconic
// prefix + splice-discriminator
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
Sexp::LIST_OPEN,
"BOOL_LITERAL_LEAD collides with LIST_OPEN — a bare `#t` \
would ambiguously open a list AND classify as a Bool.",
);
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
Sexp::LIST_CLOSE,
"BOOL_LITERAL_LEAD collides with LIST_CLOSE — a bare `#t` \
would ambiguously close a list AND classify as a Bool.",
);
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
Sexp::COMMENT_LEAD,
"BOOL_LITERAL_LEAD collides with COMMENT_LEAD — a bare \
`#t` would ambiguously open a line comment AND classify \
as a Bool.",
);
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
Sexp::COMMENT_TERM,
"BOOL_LITERAL_LEAD collides with COMMENT_TERM — the \
reader's line-comment discard-loop terminator would \
alias the Bool-family lead byte.",
);
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
Atom::STR_DELIMITER,
"BOOL_LITERAL_LEAD collides with STR_DELIMITER — a bare \
`#t` would ambiguously open a string AND classify as a \
Bool.",
);
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
Atom::STR_ESCAPE_LEAD,
"BOOL_LITERAL_LEAD collides with STR_ESCAPE_LEAD — the \
reader's Str-escape lead byte would alias the Bool-\
family lead byte.",
);
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
Atom::KEYWORD_MARKER_LEAD,
"BOOL_LITERAL_LEAD collides with KEYWORD_MARKER_LEAD — a \
bare `#t` would ambiguously begin a keyword AND classify \
as a Bool.",
);
for qf in QuoteForm::ALL {
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
qf.lead_char(),
"BOOL_LITERAL_LEAD collides with QuoteForm::{qf:?}'s \
lead_char — a bare `#t` would ambiguously begin a \
quote-family prefix AND classify as a Bool.",
);
}
assert_ne!(
Atom::BOOL_LITERAL_LEAD,
QuoteForm::SPLICE_DISCRIMINATOR,
"BOOL_LITERAL_LEAD collides with SPLICE_DISCRIMINATOR — \
the reader's `,@` splice-promotion peek byte would alias \
the Bool-family lead byte.",
);
}
// ── `Atom::STR_DELIMITER` — the canonical `"` char routed through
// the four Str-round-trip sites inside `crate::reader::tokenize`
// (string-opening arm, escape-handler self-escape mapping, string-
// closing arm, bare-atom terminator disjunct). Pins the constant
// value AND the composition against a byte-identical drift at any
// one of the four sites. Sibling-shape tests to the
// `atom_keyword_marker_*` block above (Keyword prefix axis) and
// the `atom_bool_literal_*` block above (Bool spelling axis).
#[test]
fn atom_str_delimiter_projects_canonical_double_quote_char() {
// Pins the constant's exact `char` value so a typo (`'\''`,
// `'\`'`, `'#'`) or an accidental redefinition surfaces
// immediately. Sibling-shape pin to
// `atom_keyword_marker_projects_canonical_colon_byte` (the
// Keyword prefix axis) and
// `atom_bool_literal_projects_canonical_scheme_spellings`
// (the Bool spelling axis) — pins the SAME shape on the
// Str-delimiter axis of the closed-set [`Atom`] algebra.
assert_eq!(
Atom::STR_DELIMITER,
'"',
"STR_DELIMITER char drifted from the substrate-canonical `\"` \
delimiter — the reader-round-trip contract at \
crate::reader::tokenize (string-opening arm, escape-handler \
self-escape, string-closing arm, bare-atom terminator \
disjunct) all bind to this ONE constant.",
);
}
#[test]
fn atom_str_delimiter_distinct_from_every_other_atom_marker() {
// Cross-axis disjointness pin: the Str-delimiter byte
// (`Atom::STR_DELIMITER`) must NOT alias the Keyword-marker
// prefix byte (`Atom::KEYWORD_MARKER`) or the two Bool-
// literal spellings (`Atom::bool_literal(true|false)`) —
// otherwise a bare `:foo` or `#t` lexeme starting with the
// Str-delimiter would ambiguously route through the reader's
// `Token::Str` branch AND the `Token::Atom` classifier's
// Keyword / Bool arms in `Atom::from_lexeme`. Guards the
// structural disjointness of the atomic-payload marker
// family on the closed-set [`Atom`] algebra so a future
// marker-swap that accidentally collides two axes surfaces
// at this pin rather than as a silent reader misclassification.
//
// `KEYWORD_MARKER` is `":"` (single-char) — its LEAD `char`
// lives at `Atom::KEYWORD_MARKER_LEAD` on the closed-set outer
// [`Atom`] algebra AND MUST differ from `STR_DELIMITER`'s
// (`'"'`) so `:foo` never opens a string. The two
// `bool_literal` spellings (`"#t"`, `"#f"`) begin with `'#'` —
// a two-char prefix distinct from the single `'"'`
// STR_DELIMITER — so a bare `#t` never opens a string either.
// Pin the byte-level disjointness directly here so any future
// refactor that swaps a marker to collide with STR_DELIMITER
// fails loudly.
assert_ne!(
Atom::STR_DELIMITER,
Atom::KEYWORD_MARKER_LEAD,
"STR_DELIMITER and KEYWORD_MARKER_LEAD share a byte — a \
bare `{}foo` lexeme would ambiguously open a string AND \
begin a keyword classification.",
Atom::KEYWORD_MARKER,
);
for b in [true, false] {
assert!(
!Atom::bool_literal(b).starts_with(Atom::STR_DELIMITER),
"bool_literal({b:?}) begins with STR_DELIMITER — a bare \
`{}` lexeme would ambiguously open a string AND classify \
as a Bool.",
Atom::bool_literal(b),
);
}
}
#[test]
fn atom_str_delimiter_closes_reader_display_round_trip_for_escape_free_str_payloads() {
// Load-bearing round-trip contract for the reader's four
// Str-round-trip sites — the reader's string-opening AND
// string-closing arms both bind to `Atom::STR_DELIMITER`, so
// wrapping an escape-free payload in the constant's byte on
// both sides recovers the SAME `Atom::string(s)` value the
// typed constructor produces. A regression that drifts ONE
// of the two arms (e.g. re-inlines `'"'` at the opener while
// migrating the closer to a different delimiter) breaks the
// opener-must-match-closer contract even when the byte-value
// at the drifted site still agrees at the surface, because
// this round-trip binds to the constant at BOTH endpoints.
//
// Escape-free payload sweep — the reader's escape-handler
// arm's self-escape (`\"` → `"`) is pinned separately at
// `reader_str_escape_self_escape_arm_routes_through_atom_str_delimiter`
// in `crate::reader::tests`; here we sweep the payloads that
// do NOT hit the escape-handler branch so the opener/closer
// pairing is isolated as the load-bearing composition.
for payload in ["hello", "", "foo bar", "kw", "seph.1", "42"] {
let source = format!("{}{payload}{}", Atom::STR_DELIMITER, Atom::STR_DELIMITER,);
let forms = crate::reader::read(&source).unwrap_or_else(|e| {
panic!(
"reader rejected `{source}` composed from \
Atom::STR_DELIMITER at payload={payload:?}: {e}"
)
});
assert_eq!(
forms.len(),
1,
"STR_DELIMITER-wrapped payload {payload:?} must read as \
exactly one form, got {forms:?}",
);
assert_eq!(
forms[0],
Sexp::Atom(Atom::string(payload)),
"STR_DELIMITER-wrapped payload {payload:?} drifted from \
the Sexp::Atom(Atom::string(_)) typed-constructor shape",
);
}
}
// ── `Atom::STR_ESCAPE_LEAD` — the canonical `\` char routed
// through the TWO Str-escape-lead round-trip sites inside
// `crate::reader::tokenize` (escape-handler outer arm's escape-lead
// pattern, escape-handler's self-escape arm's pattern + value pair).
// Pins the constant value AND the composition against a byte-
// identical drift at either site. Sibling-shape peer of the
// `atom_str_delimiter_*` block above on the Str-payload delimiter
// axis — where those pin the OPENER/CLOSER byte's four round-trip
// sites, these pin the ESCAPE-LEAD byte's two round-trip sites.
// The two constants together span the reader's `Token::Str`
// tokenization boundary.
#[test]
fn atom_str_escape_lead_projects_canonical_backslash_char() {
// Pins the constant's exact `char` value so a typo (`'/'`,
// `'|'`, `'^'`) or an accidental redefinition surfaces
// immediately. Sibling-shape pin to
// `atom_str_delimiter_projects_canonical_double_quote_char`
// — pins the SAME shape on the Str-escape-lead axis of the
// closed-set [`Atom`] algebra.
assert_eq!(
Atom::STR_ESCAPE_LEAD,
'\\',
"STR_ESCAPE_LEAD char drifted from the substrate-canonical \
`\\` escape lead — the reader-round-trip contract at \
crate::reader::tokenize (escape-handler outer arm, escape-\
handler self-escape arm's pattern + value pair) all bind \
to this ONE constant.",
);
}
#[test]
fn atom_str_escape_lead_distinct_from_every_other_atom_marker() {
// Cross-axis disjointness pin: the Str-escape-lead byte
// (`Atom::STR_ESCAPE_LEAD`) must NOT alias the Str-delimiter
// (`Atom::STR_DELIMITER`), Keyword-marker prefix
// (`Atom::KEYWORD_MARKER`), or Bool-literal spellings
// (`Atom::bool_literal(true|false)`) — otherwise the reader's
// escape-lead outer arm would ambiguously route the alias
// byte through the escape-handler branch AND the alias's
// corresponding classifier arm. Guards the structural
// disjointness of the atomic-payload marker family on the
// closed-set [`Atom`] algebra so a future marker-swap that
// accidentally collides two axes surfaces at this pin rather
// than as a silent reader misclassification.
//
// In particular: `STR_ESCAPE_LEAD` (`'\\'`) MUST differ from
// `STR_DELIMITER` (`'"'`) so that the reader's `Token::Str`
// accumulation loop's inner branch dispatch (escape-lead
// outer arm vs string-closing arm vs passthrough) remains
// structurally disjoint — collapsing the two would make the
// opener/closer AND the escape-lead the SAME byte, breaking
// both dispatch axes at once.
assert_ne!(
Atom::STR_ESCAPE_LEAD,
Atom::STR_DELIMITER,
"STR_ESCAPE_LEAD and STR_DELIMITER share a byte — the \
reader's Token::Str inner loop's escape-lead outer arm \
would ambiguously route through the string-closing arm.",
);
assert_ne!(
Atom::STR_ESCAPE_LEAD,
Atom::KEYWORD_MARKER_LEAD,
"STR_ESCAPE_LEAD and KEYWORD_MARKER_LEAD share a byte — a \
bare `{}foo` lexeme would ambiguously match the escape- \
lead AND begin a keyword classification.",
Atom::KEYWORD_MARKER,
);
for b in [true, false] {
assert!(
!Atom::bool_literal(b).starts_with(Atom::STR_ESCAPE_LEAD),
"bool_literal({b:?}) begins with STR_ESCAPE_LEAD — a bare \
`{}` lexeme would ambiguously match the escape-lead AND \
classify as a Bool.",
Atom::bool_literal(b),
);
}
}
#[test]
fn atom_str_escape_lead_closes_reader_self_escape_round_trip_for_backslash_payload() {
// Load-bearing round-trip contract for the reader's two
// Str-escape-lead round-trip sites — the reader's escape-lead
// outer arm AND the escape-handler's self-escape arm both bind
// to `Atom::STR_ESCAPE_LEAD`, so wrapping the constant's byte
// TWICE (i.e. the two-byte `\\` sequence) between two
// `STR_DELIMITER` bytes recovers a Str payload holding ONE
// `\` byte through the reader. A regression that drifts EITHER
// of the two arms (outer arm's pattern OR self-escape arm's
// pattern + value) fails HERE — even when the byte-value at
// the drifted site still agrees at the surface — because the
// round-trip binds to the constant at BOTH sites.
//
// Sibling-shape pin to
// `atom_str_delimiter_closes_reader_display_round_trip_for_escape_free_str_payloads`
// (the Str-payload delimiter axis's opener/closer round-trip)
// — where that pin sweeps escape-FREE payloads through the
// opener/closer pair, this pin exercises the SINGLE escape-lead
// self-escape composition end-to-end.
let source = format!(
"{}{}{}{}",
Atom::STR_DELIMITER,
Atom::STR_ESCAPE_LEAD,
Atom::STR_ESCAPE_LEAD,
Atom::STR_DELIMITER,
);
let forms = crate::reader::read(&source).unwrap_or_else(|e| {
panic!(
"reader rejected `{source}` composed from \
STR_DELIMITER + STR_ESCAPE_LEAD self-escape: {e}"
)
});
assert_eq!(
forms.len(),
1,
"STR_ESCAPE_LEAD-self-escape source must read as exactly one \
form, got {forms:?}",
);
assert_eq!(
forms[0],
Sexp::Atom(Atom::string(Atom::STR_ESCAPE_LEAD.to_string())),
"STR_ESCAPE_LEAD self-escape drifted from the \
Sexp::Atom(Atom::string(str_escape_lead)) typed-constructor \
shape — the reader's escape-lead outer arm OR the escape-\
handler's self-escape arm's pattern + value pair drifted \
from the Atom::STR_ESCAPE_LEAD constant",
);
}
// ── `Atom::decode_str_escape` — the ONE typed Str-escape decode
// projection on the closed-set [`Atom`] algebra. Pins the six-arm
// decode table (three named-escape arms `'n' / 't' / 'r'`, two
// pattern-equals-value self-escape arms on
// [`Atom::STR_DELIMITER`] + [`Atom::STR_ESCAPE_LEAD`], one
// passthrough `other`) AND the reader-level composition through
// [`crate::reader::tokenize`]'s escape-handler branch. Sibling-shape
// peer of the `atom_str_escape_lead_*` block above on the same
// Str-payload tokenization boundary: where those pin the
// ESCAPE-LEAD byte's two round-trip sites, these pin the escape
// TABLE's decode arms end-to-end.
#[test]
fn atom_decode_str_escape_named_escape_arms_project_canonical_c0_control_bytes() {
// NAMED-ESCAPE CONTRACT: the three canonical whitespace-
// shorthand arms map each ASCII letter to its corresponding
// C0 control byte. Pins the ONE typed projection's arms so a
// regression that swaps ONE arm's decoded byte (e.g. drifts
// `'n' → '\r'`, breaking the substrate's canonical newline
// shorthand) surfaces at this pin rather than at some
// downstream Str-payload round-trip.
assert_eq!(
Atom::decode_str_escape(Atom::NEWLINE_ESCAPE_SOURCE),
Atom::NEWLINE_ESCAPE_DECODED,
"decode_str_escape(NEWLINE_ESCAPE_SOURCE) drifted from the \
substrate-canonical newline (`\\n`) shorthand — the reader's \
escape-handler branch's `'n' → '\\n'` arm binds to THIS \
projection.",
);
assert_eq!(
Atom::decode_str_escape(Atom::TAB_ESCAPE_SOURCE),
Atom::TAB_ESCAPE_DECODED,
"decode_str_escape(TAB_ESCAPE_SOURCE) drifted from the \
substrate-canonical tab (`\\t`) shorthand.",
);
assert_eq!(
Atom::decode_str_escape(Atom::CARRIAGE_RETURN_ESCAPE_SOURCE),
Atom::CARRIAGE_RETURN_ESCAPE_DECODED,
"decode_str_escape(CARRIAGE_RETURN_ESCAPE_SOURCE) drifted from \
the substrate-canonical carriage-return (`\\r`) shorthand.",
);
}
#[test]
fn atom_decode_str_escape_self_escape_arms_route_through_atom_algebra_constants() {
// SELF-ESCAPE CONTRACT: the two pattern-equals-value arms in
// the escape table bind through the closed-set [`Atom`]
// algebra constants at BOTH pattern AND value. Pin that
// decoding the delimiter byte OR the escape-lead byte from
// its escaped form recovers the SAME algebra constant — a
// delimiter-swap on the algebra propagates through pattern
// AND value at ONE site (the `decode_str_escape` match arm)
// rather than as scattered inline byte literals. Sibling-
// shape pin to
// `reader_str_escape_self_escape_arm_routes_through_atom_str_delimiter`
// AND
// `reader_str_escape_lead_outer_arm_and_self_escape_arm_route_through_atom_str_escape_lead`
// — where those anchor the reader's inner-loop dispatch to
// the constants, this anchors the algebra-level projection's
// pattern-equals-value arms to the SAME constants so the
// reader-round-trip through `decode_str_escape` cannot drift
// if the constants ever change.
assert_eq!(
Atom::decode_str_escape(Atom::STR_DELIMITER),
Atom::STR_DELIMITER,
"decode_str_escape(STR_DELIMITER) drifted from the self-\
escape identity on the Str-payload delimiter axis — the \
`\\\"` sequence must decode to the STR_DELIMITER byte.",
);
assert_eq!(
Atom::decode_str_escape(Atom::STR_ESCAPE_LEAD),
Atom::STR_ESCAPE_LEAD,
"decode_str_escape(STR_ESCAPE_LEAD) drifted from the self-\
escape identity on the Str-payload escape-lead axis — \
the `\\\\` sequence must decode to the STR_ESCAPE_LEAD \
byte.",
);
}
#[test]
fn atom_decode_str_escape_passthrough_arm_returns_source_byte_unchanged_for_non_named_chars() {
// PASSTHROUGH CONTRACT: every `esc` NOT bound by the five
// typed arms (three named + two self-escape) decodes to
// itself. Pins the total-function property of the projection
// — every `char` maps to exactly one decoded `char`, and the
// decode is identity outside the closed-set table. A
// regression that stripped the `other => other` fallthrough
// (e.g. swapped it for a diagnostic path or a `Result` return
// shape) surfaces at this pin. Sweep a representative
// cross-section of ASCII printable + non-ASCII payload bytes
// that MUST NOT alias any of the five typed arms — the
// reader's pre-lift six-arm table pushed each of these
// through unchanged, and the typed projection must preserve
// that identity end-to-end.
for esc in ['a', 'z', '0', '9', '!', '/', '<', '≠', 'π', '🌱'] {
// Cross-arm disjointness precondition — none of the swept
// chars may alias the five typed arms; otherwise the sweep
// conflates passthrough with a typed decode and no longer
// pins the fallthrough identity.
assert!(
!Atom::NAMED_ESCAPE_TABLE.iter().any(|&(src, _)| src == esc)
&& !Atom::SELF_ESCAPE_TABLE.contains(&esc),
"passthrough sweep char `{esc}` aliases a typed \
escape-table arm — the sweep no longer pins the \
`other => other` fallthrough",
);
assert_eq!(
Atom::decode_str_escape(esc),
esc,
"decode_str_escape({esc:?}) drifted from the passthrough \
identity — every non-named-escape byte must decode to \
itself so the reader's `\\{esc}` sequence yields the \
payload byte `{esc}`.",
);
}
}
#[test]
fn atom_named_escape_per_role_constants_pin_canonical_bytes() {
// PER-ROLE CANONICAL-BYTE PIN: each of the six per-role
// `pub const`s carries its exact substrate-canonical byte.
// A regression that swaps a SOURCE letter (e.g. drifts
// `NEWLINE_ESCAPE_SOURCE` from `'n'` to `'N'`) or a DECODED
// C0 control (e.g. drifts `TAB_ESCAPE_DECODED` from `'\t'`
// to `'\0'`) surfaces at this pin before the round-trip
// sweep below has a chance to conflate the two. Sibling
// shape to `atom_str_delimiter_projects_canonical_double_quote_char`
// on the same closed-set [`Atom`] algebra.
assert_eq!(
Atom::NEWLINE_ESCAPE_SOURCE,
'n',
"NEWLINE_ESCAPE_SOURCE drifted from the substrate-canonical `n` letter.",
);
assert_eq!(
Atom::NEWLINE_ESCAPE_DECODED,
'\n',
"NEWLINE_ESCAPE_DECODED drifted from the substrate-canonical `\\n` C0 control byte.",
);
assert_eq!(
Atom::TAB_ESCAPE_SOURCE,
't',
"TAB_ESCAPE_SOURCE drifted from the substrate-canonical `t` letter.",
);
assert_eq!(
Atom::TAB_ESCAPE_DECODED,
'\t',
"TAB_ESCAPE_DECODED drifted from the substrate-canonical `\\t` C0 control byte.",
);
assert_eq!(
Atom::CARRIAGE_RETURN_ESCAPE_SOURCE,
'r',
"CARRIAGE_RETURN_ESCAPE_SOURCE drifted from the substrate-canonical `r` letter.",
);
assert_eq!(
Atom::CARRIAGE_RETURN_ESCAPE_DECODED,
'\r',
"CARRIAGE_RETURN_ESCAPE_DECODED drifted from the substrate-canonical `\\r` C0 control byte.",
);
}
#[test]
fn atom_named_escape_table_composes_from_per_role_constants_in_declaration_order() {
// COMPOSITION LAW: the ALL array's rows are exactly the
// per-role (SOURCE, DECODED) pairings in canonical
// declaration order. Pins the composition at ONE site so a
// reorder of ONE row without reordering the per-role
// `pub const`s silently misaligns every consumer that sweeps
// the array by index. Sibling posture to
// `quote_form_iac_forge_tags_align_with_all_by_index` on the
// outer-tokenizer quote-family axis.
assert_eq!(
Atom::NAMED_ESCAPE_TABLE,
[
(Atom::NEWLINE_ESCAPE_SOURCE, Atom::NEWLINE_ESCAPE_DECODED),
(Atom::TAB_ESCAPE_SOURCE, Atom::TAB_ESCAPE_DECODED),
(
Atom::CARRIAGE_RETURN_ESCAPE_SOURCE,
Atom::CARRIAGE_RETURN_ESCAPE_DECODED,
),
],
"NAMED_ESCAPE_TABLE drifted from its per-role (SOURCE, \
DECODED) `pub const` composition in canonical declaration \
order (newline / tab / carriage-return).",
);
}
#[test]
fn atom_named_escape_table_has_expected_cardinality() {
// ARITY PIN: the forced-arity `[(char, char); 3]` shape
// survives at runtime. Pins the closed-set size against a
// refactor that loosens the array's type to
// `&'static [(char, char)]` or `Vec<(char, char)>` (which
// would drop the compile-time arity forcing rustc bakes
// into `[T; N]` declarations). Sibling posture to
// `quote_form_iac_forge_tags_has_expected_cardinality` on
// the outer-tokenizer quote-family axis.
assert_eq!(
Atom::NAMED_ESCAPE_TABLE.len(),
3,
"NAMED_ESCAPE_TABLE cardinality drifted from the \
substrate-canonical THREE named-escape arms (newline / \
tab / carriage-return).",
);
}
#[test]
fn atom_named_escape_table_sources_pairwise_distinct() {
// SOURCE DISJOINTNESS: every SOURCE char in the array is
// distinct from every other SOURCE. A regression that
// aliased two source letters (e.g. drifts
// `TAB_ESCAPE_SOURCE` to `'n'`, colliding with
// `NEWLINE_ESCAPE_SOURCE`) would silently route two escape
// sequences through the first-matching decoded byte in
// `decode_str_escape`'s match. Pin the closed-set injective
// shape on the SOURCE axis. Sibling posture to
// `quote_form_iac_forge_tags_pairwise_distinct` on the outer
// quote-family axis.
let sources: Vec<char> = Atom::NAMED_ESCAPE_TABLE
.iter()
.map(|&(src, _)| src)
.collect();
for i in 0..sources.len() {
for j in (i + 1)..sources.len() {
assert_ne!(
sources[i], sources[j],
"NAMED_ESCAPE_TABLE SOURCE chars at indices {i} and {j} \
alias — every named-escape arm must specialize on a \
distinct SOURCE letter.",
);
}
}
}
#[test]
fn atom_named_escape_table_decoded_pairwise_distinct() {
// DECODED DISJOINTNESS: every DECODED byte in the array is
// distinct from every other DECODED byte. A regression that
// aliased two decoded bytes (e.g. drifts
// `TAB_ESCAPE_DECODED` to `'\n'`, colliding with
// `NEWLINE_ESCAPE_DECODED`) would silently collapse two
// canonical whitespace shorthands to the same emitted byte
// — a `\t` in a Str payload would decode to a newline.
// Sibling posture to the SOURCE-axis disjointness pin above.
let decoded: Vec<char> = Atom::NAMED_ESCAPE_TABLE
.iter()
.map(|&(_, dec)| dec)
.collect();
for i in 0..decoded.len() {
for j in (i + 1)..decoded.len() {
assert_ne!(
decoded[i], decoded[j],
"NAMED_ESCAPE_TABLE DECODED bytes at indices {i} and {j} \
alias — every named-escape arm must emit a distinct \
DECODED byte.",
);
}
}
}
#[test]
fn atom_named_escape_table_pattern_distinct_from_value_per_row() {
// PATTERN-DISTINCT-FROM-VALUE INVARIANT: every named-escape
// row's SOURCE differs from its DECODED byte. This is the
// structural axis that distinguishes the three named-escape
// rows from the two pattern-EQUALS-value self-escape arms
// (`STR_DELIMITER → STR_DELIMITER`,
// `STR_ESCAPE_LEAD → STR_ESCAPE_LEAD`) EXCLUDED from this
// array by design. A regression that drifted a named row
// into pattern-equals-value (e.g. `TAB_ESCAPE_DECODED = 't'`)
// silently promoted it to a passthrough and lost the
// canonical whitespace shorthand — pinned HERE at the
// typed-algebra level.
for (i, &(src, dec)) in Atom::NAMED_ESCAPE_TABLE.iter().enumerate() {
assert_ne!(
src, dec,
"NAMED_ESCAPE_TABLE row {i} pattern-EQUALS-value — the \
named-escape rows are structurally pattern-DISTINCT; \
the two pattern-equals-value arms live at \
STR_DELIMITER / STR_ESCAPE_LEAD one axis over.",
);
}
}
#[test]
fn atom_named_escape_table_disjoint_from_self_escape_algebra_constants() {
// CROSS-AXIS DISJOINTNESS: no SOURCE or DECODED byte in the
// named-escape table aliases either of the two self-escape
// algebra constants (`Self::STR_DELIMITER`,
// `Self::STR_ESCAPE_LEAD`). A regression that drifted ONE
// named-escape SOURCE to `'\\'` (colliding with
// `STR_ESCAPE_LEAD`) or ONE DECODED to `'"'` (colliding
// with `STR_DELIMITER`) would silently reshuffle the
// decode-arm dispatch order in `decode_str_escape` (the
// named arm would fire before the self-escape arm, or vice
// versa). Pins the two escape-family axes as structurally
// disjoint sub-vocabularies of the Str-payload tokenization
// boundary.
for (i, &(src, dec)) in Atom::NAMED_ESCAPE_TABLE.iter().enumerate() {
assert_ne!(
src,
Atom::STR_DELIMITER,
"NAMED_ESCAPE_TABLE row {i} SOURCE aliases STR_DELIMITER",
);
assert_ne!(
src,
Atom::STR_ESCAPE_LEAD,
"NAMED_ESCAPE_TABLE row {i} SOURCE aliases STR_ESCAPE_LEAD",
);
assert_ne!(
dec,
Atom::STR_DELIMITER,
"NAMED_ESCAPE_TABLE row {i} DECODED aliases STR_DELIMITER",
);
assert_ne!(
dec,
Atom::STR_ESCAPE_LEAD,
"NAMED_ESCAPE_TABLE row {i} DECODED aliases STR_ESCAPE_LEAD",
);
}
}
#[test]
fn atom_decode_str_escape_routes_through_named_escape_table_for_every_row() {
// PATH-UNIFORMITY PIN: `decode_str_escape` returns the
// DECODED byte of every `NAMED_ESCAPE_TABLE` row when called
// with that row's SOURCE. Path-uniformity contract between
// the projection method and the closed-set algebra — a
// regression that reverted `decode_str_escape`'s named arms
// to inline `'n' => '\n'` literals AND drifted the SOURCE
// per-role `pub const` (or vice versa) fails HERE at the
// first mismatched row rather than at a distant Str-payload
// round-trip. Sibling posture to
// `quote_form_iac_forge_tag_routes_through_typed_per_role_constants`
// on the outer-tokenizer quote-family axis.
for (i, &(src, dec)) in Atom::NAMED_ESCAPE_TABLE.iter().enumerate() {
assert_eq!(
Atom::decode_str_escape(src),
dec,
"decode_str_escape drifted from NAMED_ESCAPE_TABLE row {i} \
— the projection's named-escape arm must route through \
the per-role (SOURCE, DECODED) `pub const` pairing.",
);
}
}
#[test]
fn atom_self_escape_table_composes_from_algebra_constants_in_declaration_order() {
// COMPOSITION LAW: the ALL array's rows are the two closed-set
// [`Atom`] algebra constants in canonical declaration order
// ([`Atom::STR_DELIMITER`], [`Atom::STR_ESCAPE_LEAD`]) matching
// `decode_str_escape`'s match-arm order. Pins the composition
// at ONE site so a reorder of ONE row without reordering the
// constants silently misaligns every consumer that sweeps the
// array by index. Sibling posture to
// `atom_named_escape_table_composes_from_per_role_constants_in_declaration_order`
// one axis over.
assert_eq!(
Atom::SELF_ESCAPE_TABLE,
[Atom::STR_DELIMITER, Atom::STR_ESCAPE_LEAD],
"SELF_ESCAPE_TABLE drifted from its algebra-constant \
composition in canonical declaration order \
(STR_DELIMITER / STR_ESCAPE_LEAD).",
);
}
#[test]
fn atom_self_escape_table_has_expected_cardinality() {
// ARITY PIN: the forced-arity `[char; 2]` shape survives at
// runtime. Pins the closed-set size against a refactor that
// loosens the array's type to `&'static [char]` or
// `Vec<char>` (which would drop the compile-time arity
// forcing rustc bakes into `[T; N]` declarations). Sibling
// posture to `atom_named_escape_table_has_expected_cardinality`
// on the peer pattern-DISTINCT-from-value sub-vocabulary.
assert_eq!(
Atom::SELF_ESCAPE_TABLE.len(),
2,
"SELF_ESCAPE_TABLE cardinality drifted from the substrate-\
canonical TWO self-escape arms (STR_DELIMITER / \
STR_ESCAPE_LEAD).",
);
}
#[test]
fn atom_self_escape_table_pairwise_distinct() {
// DISJOINTNESS: every byte in the array is distinct from every
// other byte. A regression that aliased the two self-escape
// bytes (e.g. adopting `'"'` as ALSO the escape lead in a
// hypothetical smart-quote reader mode) would silently collapse
// the two pattern-EQUALS-value arms of `decode_str_escape` to
// one and lose the ability to escape one delimiter without
// shadowing the other. Sibling posture to
// `atom_named_escape_table_sources_pairwise_distinct` on the
// peer sub-vocabulary.
for i in 0..Atom::SELF_ESCAPE_TABLE.len() {
for j in (i + 1)..Atom::SELF_ESCAPE_TABLE.len() {
assert_ne!(
Atom::SELF_ESCAPE_TABLE[i],
Atom::SELF_ESCAPE_TABLE[j],
"SELF_ESCAPE_TABLE bytes at indices {i} and {j} \
alias — every self-escape arm must specialize on \
a distinct byte.",
);
}
}
}
#[test]
fn atom_self_escape_table_disjoint_from_named_escape_table() {
// CROSS-AXIS DISJOINTNESS: no byte in the self-escape table
// aliases any SOURCE or DECODED byte in the named-escape
// table. A regression that drifted a self-escape byte into
// the named vocabulary (e.g. adopted `'n'` as an additional
// self-escaping delimiter) OR a named byte into the self
// vocabulary would reshuffle the decode-arm dispatch order in
// `decode_str_escape` — the two sub-vocabularies must remain
// structurally disjoint sub-tables of the FIVE non-passthrough
// arms. Sibling posture (inverse direction) to
// `atom_named_escape_table_disjoint_from_self_escape_algebra_constants`
// — where that pin sweeps from the named side outward, this
// sweeps from the self side outward; both pin the same
// cross-axis disjointness invariant.
for (i, &self_byte) in Atom::SELF_ESCAPE_TABLE.iter().enumerate() {
for (j, &(src, dec)) in Atom::NAMED_ESCAPE_TABLE.iter().enumerate() {
assert_ne!(
self_byte, src,
"SELF_ESCAPE_TABLE row {i} aliases NAMED_ESCAPE_TABLE \
row {j} SOURCE — the pattern-EQUALS-value and \
pattern-DISTINCT-from-value sub-vocabularies must \
remain disjoint.",
);
assert_ne!(
self_byte, dec,
"SELF_ESCAPE_TABLE row {i} aliases NAMED_ESCAPE_TABLE \
row {j} DECODED — the pattern-EQUALS-value and \
pattern-DISTINCT-from-value sub-vocabularies must \
remain disjoint.",
);
}
}
}
#[test]
fn atom_decode_str_escape_routes_through_self_escape_table_for_every_row() {
// PATH-UNIFORMITY PIN: `decode_str_escape` returns the SAME
// byte for every `SELF_ESCAPE_TABLE` row — the pattern-EQUALS-
// value invariant is exercised on every row. A regression
// that reverted `decode_str_escape`'s two self-escape arms to
// inline `'"' => '"'` / `'\\' => '\\'` literals AND drifted
// one of the two constants (or vice versa) fails HERE at the
// first mismatched row rather than at a downstream Str-payload
// round-trip. Sibling posture to
// `atom_decode_str_escape_routes_through_named_escape_table_for_every_row`
// — where that pin exercises the pattern-DISTINCT-from-value
// path-uniformity contract on the peer sub-vocabulary, this
// pins the pattern-EQUALS-value axis on the self-escape
// sub-vocabulary.
for (i, &esc) in Atom::SELF_ESCAPE_TABLE.iter().enumerate() {
assert_eq!(
Atom::decode_str_escape(esc),
esc,
"decode_str_escape drifted from SELF_ESCAPE_TABLE row \
{i} — the projection's self-escape arm must map \
pattern to the SAME byte (definitional identity).",
);
}
}
#[test]
fn atom_named_and_self_escape_tables_span_the_five_non_passthrough_arms() {
// TOTAL-DECODE PIN: the two sub-vocabulary ALL arrays
// together account for exactly the FIVE non-passthrough arms
// of [`Atom::decode_str_escape`]. Pins the closed-set
// decomposition against a refactor that adds a sixth typed
// arm to `decode_str_escape` without extending one of the
// ALL arrays (which would leak a stale byte through
// `other => other` at the sweep sites). The three named arms
// + two self arms = five typed arms; the sixth branch is the
// `other => other` passthrough at the algebra's projection.
assert_eq!(
Atom::NAMED_ESCAPE_TABLE.len() + Atom::SELF_ESCAPE_TABLE.len(),
5,
"NAMED_ESCAPE_TABLE + SELF_ESCAPE_TABLE cardinality drifted \
from the substrate-canonical FIVE non-passthrough arms of \
Atom::decode_str_escape.",
);
}
// ── `Atom::ESCAPE_SOURCES` — the closed-set forced-arity ALL array
// over every escape-SOURCE byte `Atom::decode_str_escape` has a
// non-passthrough arm for. Cross-sub-vocabulary SPAN peer of
// `NAMED_ESCAPE_TABLE` (three pattern-DISTINCT-from-value rows'
// SOURCE column) + `SELF_ESCAPE_TABLE` (two pattern-EQUALS-value
// rows) at ONE typed `[char; 5]` on the SAME closed-set [`Atom`]
// algebra. The pins below anchor (a) the SPAN composition against
// the two peer sub-vocabulary arrays' SOURCE columns in canonical
// declaration order, (b) the forced-arity cardinality against a
// refactor that loosens the array to `&[char]`, (c) pairwise
// disjointness inherited from the two peer sub-vocabularies' own
// pairwise disjointness + cross-sub-vocabulary disjointness, (d)
// the "every row hits a non-passthrough arm" closure identity
// against a refactor that added a stale ESCAPE_SOURCES row without
// extending `decode_str_escape`, and (e) the load-bearing partition
// NAMED-source-column prefix / SELF-source-column suffix that the
// declaration order encodes for consumers that walk the array by
// index. Sibling-shape to the composition-pin block above for
// `SELF_ESCAPE_TABLE` — those pins bind the peer sub-vocabulary at
// the same closed-set algebra; this block binds the SPAN of the
// two sub-vocabularies at ONE array up.
#[test]
fn atom_escape_sources_composes_from_named_and_self_escape_sub_vocabularies_in_declaration_order(
) {
// COMPOSITION LAW: the ALL array's rows are (NAMED_ESCAPE_TABLE
// SOURCE column, then SELF_ESCAPE_TABLE rows) in canonical
// declaration order matching `decode_str_escape`'s match-arm
// order. Pins the SPAN composition at ONE site so a reorder
// that broke the (named prefix, self suffix) partition (e.g.
// interleaving the two sub-vocabularies' rows, sorting
// alphabetically) silently misaligns every consumer that
// sweeps the array by index. Sibling-shape pin to
// `atom_self_escape_table_composes_from_algebra_constants_in_declaration_order`
// one axis over on the peer sub-vocabulary at
// `Atom::SELF_ESCAPE_TABLE`, and to
// `atom_named_escape_table_composes_from_per_role_constants_in_declaration_order`
// on the SOURCE column of the other peer sub-vocabulary at
// `Atom::NAMED_ESCAPE_TABLE`.
assert_eq!(
Atom::ESCAPE_SOURCES,
[
Atom::NAMED_ESCAPE_TABLE[0].0,
Atom::NAMED_ESCAPE_TABLE[1].0,
Atom::NAMED_ESCAPE_TABLE[2].0,
Atom::SELF_ESCAPE_TABLE[0],
Atom::SELF_ESCAPE_TABLE[1],
],
"ESCAPE_SOURCES composition drifted from the canonical \
(NAMED SOURCE column, then SELF rows) SPAN in declaration \
order — the SPAN lift must route through the two peer \
sub-vocabulary arrays' rows in the exact order \
decode_str_escape's match arms fire on them.",
);
}
#[test]
fn atom_escape_sources_has_expected_cardinality() {
// ARITY PIN: the forced-arity `[char; 5]` shape survives at
// runtime AND matches the two peer sub-vocabularies' summed
// cardinality. Pins the closed-set size against a refactor
// that loosens the array's type to `&'static [char]` or
// `Vec<char>` (which would drop the compile-time arity
// forcing rustc bakes into `[T; N]` declarations) AND against
// a refactor that drifted this array's arity without extending
// one of the two peer sub-vocabularies (which would silently
// desynchronize the SPAN identity from its two source arrays).
// Sibling posture to
// `atom_named_and_self_escape_tables_span_the_five_non_passthrough_arms`
// — where that pin binds the summed cardinality at ONE
// assert_eq!, this pin binds the SPAN's OWN cardinality at
// the ALL array level so a future refactor that added a
// NAMED_ESCAPE_TABLE row without extending ESCAPE_SOURCES
// fails HERE at the paired-length equality rather than at a
// distant sweep site.
assert_eq!(
Atom::ESCAPE_SOURCES.len(),
5,
"ESCAPE_SOURCES cardinality drifted from the substrate-\
canonical FIVE non-passthrough arms of \
Atom::decode_str_escape.",
);
assert_eq!(
Atom::ESCAPE_SOURCES.len(),
Atom::NAMED_ESCAPE_TABLE.len() + Atom::SELF_ESCAPE_TABLE.len(),
"ESCAPE_SOURCES cardinality drifted from the SUM of the two \
peer sub-vocabulary arrays' cardinalities — the SPAN \
identity is broken.",
);
}
#[test]
fn atom_escape_sources_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every row is distinct from every
// other row. The closed-set SPAN inherits pairwise
// disjointness from the two peer sub-vocabularies (each
// pinned pairwise distinct at their own sibling tests) PLUS
// the cross-sub-vocabulary disjointness pinned by
// `atom_self_escape_table_disjoint_from_named_escape_table` —
// this test closes the disjointness contract at the SPAN
// level so a future refactor that added a sixth arm whose
// SOURCE aliased an existing row surfaces HERE rather than
// at a distant reader round-trip. Sibling posture to
// `atom_self_escape_table_pairwise_distinct` +
// `atom_named_escape_table_sources_pairwise_distinct` on the
// two peer sub-vocabularies.
for i in 0..Atom::ESCAPE_SOURCES.len() {
for j in (i + 1)..Atom::ESCAPE_SOURCES.len() {
assert_ne!(
Atom::ESCAPE_SOURCES[i],
Atom::ESCAPE_SOURCES[j],
"ESCAPE_SOURCES bytes at indices {i} and {j} alias \
— every non-passthrough arm must specialize on a \
distinct SOURCE byte.",
);
}
}
}
#[test]
fn atom_escape_sources_partitions_into_named_source_prefix_and_self_source_suffix() {
// PARTITION PIN: the SPAN's canonical declaration order
// encodes a (named prefix, self suffix) partition —
// `ESCAPE_SOURCES[0..3]` IS `NAMED_ESCAPE_TABLE`'s SOURCE
// column, `ESCAPE_SOURCES[3..5]` IS `SELF_ESCAPE_TABLE`. Pin
// the partition at the index level so a reorder that broke
// the sub-vocabulary boundary (e.g. moved `STR_DELIMITER` to
// index 2 to sort alphabetically, or interleaved a self row
// between two named rows) fails HERE rather than as silent
// drift where consumers that walk the array by index would
// route the wrong sub-vocabulary's row through the wrong
// downstream handler.
for (i, &(src, _)) in Atom::NAMED_ESCAPE_TABLE.iter().enumerate() {
assert_eq!(
Atom::ESCAPE_SOURCES[i],
src,
"ESCAPE_SOURCES[{i}] ({}) drifted from \
NAMED_ESCAPE_TABLE[{i}].0 ({src}) — the named-prefix \
partition is broken.",
Atom::ESCAPE_SOURCES[i],
);
}
for (i, &self_byte) in Atom::SELF_ESCAPE_TABLE.iter().enumerate() {
let span_index = Atom::NAMED_ESCAPE_TABLE.len() + i;
assert_eq!(
Atom::ESCAPE_SOURCES[span_index],
self_byte,
"ESCAPE_SOURCES[{span_index}] ({}) drifted from \
SELF_ESCAPE_TABLE[{i}] ({self_byte}) — the self-suffix \
partition is broken.",
Atom::ESCAPE_SOURCES[span_index],
);
}
}
#[test]
fn atom_escape_sources_every_row_projects_through_a_non_passthrough_arm_of_decode_str_escape() {
// NON-PASSTHROUGH-CLOSURE CONTRACT: every row of
// `ESCAPE_SOURCES` MUST project through a NON-passthrough arm
// of `decode_str_escape` — the SPAN is definitionally the set
// of SOURCE bytes for which `decode_str_escape` has a typed
// arm. Pin the closure structurally so a refactor that added
// an `ESCAPE_SOURCES` row without extending
// `decode_str_escape`'s match (or vice versa) surfaces HERE at
// the first drifted row rather than at a distant sweep-site
// regression. The row projects through a non-passthrough arm
// iff EITHER (a) it's a `NAMED_ESCAPE_TABLE` SOURCE and
// `decode_str_escape` returns the paired DECODED byte
// (`decode(src) != src`), OR (b) it's a `SELF_ESCAPE_TABLE`
// row and `decode_str_escape` returns the SAME byte
// (`decode(esc) == esc` by definitional identity — the arm
// exists AND fires, but the projection is pattern-EQUALS-
// value). Both arm-kinds are non-passthrough because they
// have a TYPED arm in the match; the `other => other`
// passthrough only fires for chars NOT in the SPAN. Pin the
// dispatch identity by checking each row lives in exactly ONE
// of the two peer sub-vocabularies.
for (i, &esc) in Atom::ESCAPE_SOURCES.iter().enumerate() {
let in_named = Atom::NAMED_ESCAPE_TABLE.iter().any(|&(src, _)| src == esc);
let in_self = Atom::SELF_ESCAPE_TABLE.contains(&esc);
assert!(
in_named ^ in_self,
"ESCAPE_SOURCES[{i}] ({esc:?}) must belong to EXACTLY \
ONE peer sub-vocabulary (in_named={in_named}, \
in_self={in_self}) — the SPAN identity requires each \
row to fire a typed non-passthrough arm on either \
the pattern-DISTINCT-from-value axis (NAMED) OR the \
pattern-EQUALS-value axis (SELF), never both, never \
neither.",
);
// Consistency check: the arm's projection must agree with
// the row's sub-vocabulary identity. NAMED rows project to
// the paired DECODED byte (which the pairwise-distinct pin
// guarantees differs from SOURCE); SELF rows project to
// the row byte itself.
let decoded = Atom::decode_str_escape(esc);
if in_named {
assert_ne!(
decoded, esc,
"ESCAPE_SOURCES[{i}] ({esc:?}) is a NAMED SOURCE — \
decode_str_escape MUST project to the paired \
DECODED byte (distinct from SOURCE) but returned \
{decoded:?}.",
);
} else {
assert_eq!(
decoded, esc,
"ESCAPE_SOURCES[{i}] ({esc:?}) is a SELF row — \
decode_str_escape MUST project to the same byte \
(pattern-EQUALS-value by definitional identity) \
but returned {decoded:?}.",
);
}
}
}
#[test]
fn atom_decode_str_escape_composes_end_to_end_through_reader_for_every_named_arm() {
// END-TO-END COMPOSITION CONTRACT: pin that every typed
// escape-table arm — the three named-escape arms + the two
// pattern-equals-value self-escape arms + a representative
// passthrough — decodes through the reader's full
// escape-handler pipeline via ONE
// `Atom::decode_str_escape(esc)` call. Wrap each `esc` in a
// STR_DELIMITER-wrapped, STR_ESCAPE_LEAD-led source, run it
// through [`crate::reader::read`], and assert the resulting
// Str payload equals `decode_str_escape(esc).to_string()`.
// A regression that re-inlined the reader's table (e.g.
// reverted the escape-handler branch to per-arm literals AND
// added a sixth named-escape arm to
// [`Atom::decode_str_escape`] without updating the reader)
// fails HERE at the first arm whose decode diverges.
//
// Sibling-shape pin to
// `atom_str_escape_lead_closes_reader_self_escape_round_trip_for_backslash_payload`
// — where that pin exercises the SINGLE self-escape arm on
// the escape-lead axis end-to-end, this sweep exercises the
// FULL closed-set table on the same axis.
// Pre-lift the (NAMED_ESCAPE_TABLE.iter().map(|&(src, _)| src)
// .chain(SELF_ESCAPE_TABLE.iter().copied())) runtime iterator
// chain reassembled the FIVE non-passthrough source bytes at
// this callsite; post-lift the SPAN binds at ONE forced-arity
// `Atom::ESCAPE_SOURCES: [char; 5]` on the closed-set [`Atom`]
// algebra so the sweep iterates the typed ALL array directly.
// The trailing `'x'` is a representative PASSTHROUGH byte
// (deliberately NOT in `ESCAPE_SOURCES`) — the sweep exercises
// BOTH the non-passthrough closed set AND the passthrough
// default-arm through the same reader pipeline in ONE loop.
let escs: Vec<char> = Atom::ESCAPE_SOURCES
.iter()
.copied()
.chain(std::iter::once('x'))
.collect();
for esc in escs {
let source = format!(
"{}{}{}{}",
Atom::STR_DELIMITER,
Atom::STR_ESCAPE_LEAD,
esc,
Atom::STR_DELIMITER,
);
let forms = crate::reader::read(&source).unwrap_or_else(|e| {
panic!(
"reader rejected `{source}` composed from \
STR_DELIMITER + STR_ESCAPE_LEAD + `{esc}`: {e}"
)
});
assert_eq!(
forms.len(),
1,
"escape sweep for `{esc}` must read as exactly one form, \
got {forms:?}",
);
let decoded = Atom::decode_str_escape(esc);
assert_eq!(
forms[0],
Sexp::Atom(Atom::string(decoded.to_string())),
"escape sweep for `{esc}` drifted from \
Sexp::Atom(Atom::string(decode_str_escape({esc:?}) = \
{decoded:?}).to_string()) — the reader's escape-handler \
branch OR Atom::decode_str_escape drifted from the ONE \
shared closed-set escape-table projection",
);
}
}
// ── `Atom::ESCAPE_DECODED` — the closed-set forced-arity ALL array
// over every DECODED byte `Atom::decode_str_escape` can emit from a
// non-passthrough arm. Column-dual peer of `Atom::ESCAPE_SOURCES` at
// the SAME `[char; 5]` shape on the SAME closed-set [`Atom`] algebra:
// together the two arrays close the (SOURCE, DECODED) cross-product
// of `decode_str_escape`'s non-passthrough arm-set at two byte-
// identical `[char; 5]` shapes. Cross-sub-vocabulary SPAN peer of
// `NAMED_ESCAPE_TABLE` (three pattern-DISTINCT-from-value rows'
// DECODED column) + `SELF_ESCAPE_TABLE` (two pattern-EQUALS-value
// rows whose DECODED column is definitionally the row byte itself)
// at ONE typed `[char; 5]` on the SAME closed-set [`Atom`] algebra.
// The pins below anchor (a) the SPAN composition against the two
// peer sub-vocabulary arrays' DECODED columns in canonical
// declaration order, (b) the forced-arity cardinality against a
// refactor that loosens the array to `&[char]`, (c) pairwise
// disjointness on the DECODED column, (d) the load-bearing
// partition NAMED-decoded-column prefix / SELF-decoded-column suffix
// that the declaration order encodes for consumers that walk the
// array by index, and (e) the column-dual POINTWISE projection
// identity that pins `ESCAPE_DECODED[i] ==
// decode_str_escape(ESCAPE_SOURCES[i])` for every index — the
// NEW load-bearing invariant this SPAN adds on top of `ESCAPE_SOURCES`.
#[test]
fn atom_escape_decoded_composes_from_named_and_self_escape_sub_vocabularies_in_declaration_order(
) {
// COMPOSITION LAW: the ALL array's rows are (NAMED_ESCAPE_TABLE
// DECODED column, then SELF_ESCAPE_TABLE rows) in canonical
// declaration order matching `decode_str_escape`'s match-arm
// order. Pins the SPAN composition at ONE site so a reorder
// that broke the (named prefix, self suffix) partition (e.g.
// interleaving the two sub-vocabularies' rows, sorting by C0
// byte value) silently misaligns every consumer that sweeps the
// array by index. Sibling-shape pin to
// `atom_escape_sources_composes_from_named_and_self_escape_sub_vocabularies_in_declaration_order`
// one column over on the peer SOURCE-column SPAN at
// `Atom::ESCAPE_SOURCES`.
assert_eq!(
Atom::ESCAPE_DECODED,
[
Atom::NAMED_ESCAPE_TABLE[0].1,
Atom::NAMED_ESCAPE_TABLE[1].1,
Atom::NAMED_ESCAPE_TABLE[2].1,
Atom::SELF_ESCAPE_TABLE[0],
Atom::SELF_ESCAPE_TABLE[1],
],
"ESCAPE_DECODED composition drifted from the canonical \
(NAMED DECODED column, then SELF rows) SPAN in declaration \
order — the SPAN lift must route through the two peer \
sub-vocabulary arrays' rows in the exact order \
decode_str_escape's match arms fire on them.",
);
}
#[test]
fn atom_escape_decoded_has_expected_cardinality() {
// ARITY PIN: the forced-arity `[char; 5]` shape survives at
// runtime AND matches the two peer sub-vocabularies' summed
// cardinality AND matches the column-dual peer
// `ESCAPE_SOURCES`'s arity. Pins the closed-set size against a
// refactor that loosens the array's type to `&'static [char]`
// or `Vec<char>` (which would drop the compile-time arity
// forcing rustc bakes into `[T; N]` declarations) AND against a
// refactor that drifted this array's arity without extending
// one of the two peer sub-vocabularies (which would silently
// desynchronize the SPAN identity from its two source arrays)
// AND against a refactor that broke the column-dual shape
// symmetry with `ESCAPE_SOURCES`. Sibling posture to
// `atom_escape_sources_has_expected_cardinality` on the peer
// SOURCE-column SPAN.
assert_eq!(
Atom::ESCAPE_DECODED.len(),
5,
"ESCAPE_DECODED cardinality drifted from the substrate-\
canonical FIVE non-passthrough arms of \
Atom::decode_str_escape.",
);
assert_eq!(
Atom::ESCAPE_DECODED.len(),
Atom::NAMED_ESCAPE_TABLE.len() + Atom::SELF_ESCAPE_TABLE.len(),
"ESCAPE_DECODED cardinality drifted from the SUM of the two \
peer sub-vocabulary arrays' cardinalities — the SPAN \
identity is broken.",
);
assert_eq!(
Atom::ESCAPE_DECODED.len(),
Atom::ESCAPE_SOURCES.len(),
"ESCAPE_DECODED cardinality drifted from the column-dual peer \
ESCAPE_SOURCES's cardinality — the column-dual shape \
symmetry `[char; 5]` × `[char; 5]` on decode_str_escape's \
non-passthrough arm-set is broken.",
);
}
#[test]
fn atom_escape_decoded_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: every row is distinct from every
// other row. On the DECODED column this is TIGHTER than on
// the SOURCE column: the NAMED sub-vocabulary's DECODED rows
// are C0 control bytes (`'\n'`, `'\t'`, `'\r'` — bytes 0x0A,
// 0x09, 0x0D) and the SELF sub-vocabulary's rows are printable
// ASCII bytes (`'"'`, `'\\'` — bytes 0x22, 0x5C), so no
// NAMED-DECODED byte can alias a SELF byte by byte-class
// disjointness. This test closes the disjointness contract at
// the SPAN level so a future refactor that added a sixth arm
// whose DECODED aliased an existing row (e.g. drifted
// TAB_ESCAPE_DECODED from `'\t'` to `'\n'`, collapsing two
// arms onto the same DECODED byte) surfaces HERE rather than
// at a distant reader round-trip. Sibling posture to
// `atom_escape_sources_pairwise_distinct` on the peer
// SOURCE-column SPAN.
for i in 0..Atom::ESCAPE_DECODED.len() {
for j in (i + 1)..Atom::ESCAPE_DECODED.len() {
assert_ne!(
Atom::ESCAPE_DECODED[i],
Atom::ESCAPE_DECODED[j],
"ESCAPE_DECODED bytes at indices {i} and {j} alias \
— every non-passthrough arm must emit a distinct \
DECODED byte.",
);
}
}
}
#[test]
fn atom_escape_decoded_partitions_into_named_decoded_prefix_and_self_decoded_suffix() {
// PARTITION PIN: the SPAN's canonical declaration order
// encodes a (named prefix, self suffix) partition —
// `ESCAPE_DECODED[0..3]` IS `NAMED_ESCAPE_TABLE`'s DECODED
// column, `ESCAPE_DECODED[3..5]` IS `SELF_ESCAPE_TABLE` (the
// SELF sub-vocabulary's DECODED column IS its row column by
// pattern-EQUALS-value identity). Pin the partition at the
// index level so a reorder that broke the sub-vocabulary
// boundary (e.g. moved a SELF row to index 2 to sort by C0
// byte value, or interleaved a self row between two named
// rows) fails HERE rather than as silent drift where consumers
// that walk the array by index would route the wrong
// sub-vocabulary's row through the wrong downstream handler.
// Sibling-shape pin to
// `atom_escape_sources_partitions_into_named_source_prefix_and_self_source_suffix`
// one column over on the peer SOURCE-column SPAN.
for (i, &(_, dec)) in Atom::NAMED_ESCAPE_TABLE.iter().enumerate() {
assert_eq!(
Atom::ESCAPE_DECODED[i],
dec,
"ESCAPE_DECODED[{i}] ({}) drifted from \
NAMED_ESCAPE_TABLE[{i}].1 ({dec}) — the named-decoded-\
prefix partition is broken.",
Atom::ESCAPE_DECODED[i],
);
}
for (i, &self_byte) in Atom::SELF_ESCAPE_TABLE.iter().enumerate() {
let span_index = Atom::NAMED_ESCAPE_TABLE.len() + i;
assert_eq!(
Atom::ESCAPE_DECODED[span_index],
self_byte,
"ESCAPE_DECODED[{span_index}] ({}) drifted from \
SELF_ESCAPE_TABLE[{i}] ({self_byte}) — the self-decoded-\
suffix partition is broken (SELF rows are pattern-\
EQUALS-value so DECODED == SOURCE by definitional \
identity).",
Atom::ESCAPE_DECODED[span_index],
);
}
}
#[test]
fn atom_escape_decoded_projects_pointwise_from_escape_sources_through_decode_str_escape() {
// COLUMN-DUAL POINTWISE PROJECTION LAW: the two forced-arity
// `[char; 5]` peer arrays [`Atom::ESCAPE_SOURCES`] +
// [`Atom::ESCAPE_DECODED`] are the SOURCE column and DECODED
// column of `decode_str_escape`'s non-passthrough arm-set — for
// every index `i` in `0..5`,
// `ESCAPE_DECODED[i] == Atom::decode_str_escape(
// ESCAPE_SOURCES[i])`. This is the NEW load-bearing invariant
// this SPAN adds on top of `ESCAPE_SOURCES`: the column-dual
// pointwise projection identity that pins the two `[char; 5]`
// arrays as the two columns of the SAME arm-set at the SAME
// row-order at rustc time. Pin the projection identity
// structurally so a refactor that drifted either array's
// declaration order OR drifted `decode_str_escape`'s match-arm
// ordering surfaces HERE at the first drifted index rather
// than at a distant sweep site. A regression that swapped
// (e.g.) rows 3 and 4 in `ESCAPE_DECODED` without swapping
// them in `ESCAPE_SOURCES` (or vice versa) would silently
// collapse the column-dual identity; this pin catches the
// divergence at the first drifted index.
for (i, &src) in Atom::ESCAPE_SOURCES.iter().enumerate() {
let expected = Atom::decode_str_escape(src);
assert_eq!(
Atom::ESCAPE_DECODED[i],
expected,
"ESCAPE_DECODED[{i}] ({}) drifted from \
decode_str_escape(ESCAPE_SOURCES[{i}] = {src:?}) = \
{expected:?} — the column-dual pointwise projection \
law from ESCAPE_SOURCES onto ESCAPE_DECODED through \
decode_str_escape is broken at index {i}.",
Atom::ESCAPE_DECODED[i],
);
}
}
// ── `Atom::ESCAPE_TABLE` — the paired-column SPAN closing BOTH
// columns of `decode_str_escape`'s FIVE non-passthrough arms at
// ONE typed forced-arity `[(char, char); 5]` on the closed-set
// [`Atom`] algebra. Peer-collapse of the two column-dual
// `[char; 5]` peer arrays `Atom::ESCAPE_SOURCES` and
// `Atom::ESCAPE_DECODED` at the paired-shape level. Tests pin
// (a) the pointwise composition law `ESCAPE_TABLE[i] ==
// (ESCAPE_SOURCES[i], ESCAPE_DECODED[i])`, (b) the forced-arity
// `[(char, char); 5]` shape, (c) the sub-vocabulary partition into
// NAMED-paired prefix + SELF-reshape suffix (the SELF sub-
// vocabulary's rows re-shape from `char` to `(row, row)` via the
// definitional-identity collapse), (d) the pattern-classification
// partition where NAMED rows carry `row.0 != row.1` and SELF rows
// carry `row.0 == row.1`, and (e) the pointwise projection law
// `decode_str_escape(row.0) == row.1` for every row.
#[test]
fn atom_escape_table_composes_pointwise_from_escape_sources_and_escape_decoded_column_duals() {
// POINTWISE COMPOSITION LAW: the paired-column SPAN's rows are
// the two column-dual peer arrays zipped pointwise — for every
// index `i` in `0..5`, `ESCAPE_TABLE[i] ==
// (ESCAPE_SOURCES[i], ESCAPE_DECODED[i])`. This is the load-
// bearing pointwise identity carrying the two-column
// composition relation between the paired SPAN and its two
// column-dual peer SPANs. A refactor that drifted any of the
// three arrays' declaration orders OR drifted
// `decode_str_escape`'s match-arm ordering surfaces HERE at
// the first drifted index rather than at a distant sweep site.
// Sibling-shape pin to
// `atom_escape_decoded_projects_pointwise_from_escape_sources_through_decode_str_escape`
// one composition layer up: where that pin binds the DECODED-
// column SPAN to the SOURCE-column SPAN through
// `decode_str_escape`, this pin binds the paired-column SPAN
// to the two column-dual peer SPANs through pointwise
// composition.
assert_eq!(Atom::ESCAPE_TABLE.len(), Atom::ESCAPE_SOURCES.len());
assert_eq!(Atom::ESCAPE_TABLE.len(), Atom::ESCAPE_DECODED.len());
for (i, &(src, decoded)) in Atom::ESCAPE_TABLE.iter().enumerate() {
assert_eq!(
src,
Atom::ESCAPE_SOURCES[i],
"ESCAPE_TABLE[{i}].0 ({src:?}) drifted from \
ESCAPE_SOURCES[{i}] ({:?}) — the paired-column SPAN's \
SOURCE-column projection is broken at index {i}.",
Atom::ESCAPE_SOURCES[i],
);
assert_eq!(
decoded,
Atom::ESCAPE_DECODED[i],
"ESCAPE_TABLE[{i}].1 ({decoded:?}) drifted from \
ESCAPE_DECODED[{i}] ({:?}) — the paired-column SPAN's \
DECODED-column projection is broken at index {i}.",
Atom::ESCAPE_DECODED[i],
);
}
}
#[test]
fn atom_escape_table_has_expected_cardinality() {
// ARITY PIN: the forced-arity `[(char, char); 5]` shape
// survives at runtime AND matches the two column-dual peer
// arrays' arities AND matches the summed cardinality of the
// two sub-vocabulary arrays. Pins the closed-set size against
// a refactor that loosens the array's type to
// `&'static [(char, char)]` or `Vec<(char, char)>` (which
// would drop the compile-time arity forcing rustc bakes into
// `[T; N]` declarations) AND against a refactor that drifted
// this array's arity without extending one of the two peer
// column-dual arrays or one of the two peer sub-vocabulary
// arrays. Sibling posture to
// `atom_escape_sources_has_expected_cardinality` +
// `atom_escape_decoded_has_expected_cardinality` on the two
// column-dual peer SPANs.
assert_eq!(
Atom::ESCAPE_TABLE.len(),
5,
"ESCAPE_TABLE cardinality drifted from the substrate-\
canonical FIVE non-passthrough arms of \
Atom::decode_str_escape.",
);
assert_eq!(
Atom::ESCAPE_TABLE.len(),
Atom::ESCAPE_SOURCES.len(),
"ESCAPE_TABLE cardinality drifted from the column-dual \
peer ESCAPE_SOURCES's cardinality — the paired-column \
shape symmetry `[(char, char); 5]` × `[char; 5]` on \
decode_str_escape's non-passthrough arm-set is broken on \
the SOURCE column.",
);
assert_eq!(
Atom::ESCAPE_TABLE.len(),
Atom::ESCAPE_DECODED.len(),
"ESCAPE_TABLE cardinality drifted from the column-dual \
peer ESCAPE_DECODED's cardinality — the paired-column \
shape symmetry `[(char, char); 5]` × `[char; 5]` on \
decode_str_escape's non-passthrough arm-set is broken on \
the DECODED column.",
);
assert_eq!(
Atom::ESCAPE_TABLE.len(),
Atom::NAMED_ESCAPE_TABLE.len() + Atom::SELF_ESCAPE_TABLE.len(),
"ESCAPE_TABLE cardinality drifted from the SUM of the two \
peer sub-vocabulary arrays' cardinalities — the paired-\
column SPAN identity is broken.",
);
}
#[test]
fn atom_escape_table_partitions_into_named_paired_prefix_and_self_reshape_suffix() {
// SUB-VOCABULARY PARTITION LAW: `ESCAPE_TABLE[0..3]` IS the
// NAMED_ESCAPE_TABLE (pattern-DISTINCT-from-value sub-
// vocabulary at its native paired shape passes through
// identically); `ESCAPE_TABLE[3..5]` re-shapes the SELF_ESCAPE_TABLE
// rows from `char` to `(row, row)` via the definitional-
// identity collapse (pattern-EQUALS-value sub-vocabulary). The
// index-level partition pin binds every consumer walking the
// paired-column SPAN by index to the (named-paired prefix,
// self-reshape suffix) partition at rustc time. Sibling
// posture to
// `atom_escape_sources_partitions_into_named_source_prefix_and_self_source_suffix`
// + `atom_escape_decoded_partitions_into_named_decoded_prefix_and_self_decoded_suffix`
// on the two column-dual peer SPANs.
assert_eq!(
&Atom::ESCAPE_TABLE[0..3],
&Atom::NAMED_ESCAPE_TABLE[..],
"ESCAPE_TABLE named-paired prefix drifted from \
NAMED_ESCAPE_TABLE — the sub-vocabulary partition is \
broken.",
);
for (self_index, &row) in Atom::SELF_ESCAPE_TABLE.iter().enumerate() {
let span_index = Atom::NAMED_ESCAPE_TABLE.len() + self_index;
assert_eq!(
Atom::ESCAPE_TABLE[span_index],
(row, row),
"ESCAPE_TABLE[{span_index}] ({:?}) drifted from the \
SELF-reshape suffix pair (SELF_ESCAPE_TABLE[{self_index}], \
SELF_ESCAPE_TABLE[{self_index}]) = ({row:?}, \
{row:?}) — the pattern-EQUALS-value definitional-\
identity reshape is broken.",
Atom::ESCAPE_TABLE[span_index],
);
}
}
#[test]
fn atom_escape_table_named_prefix_is_pattern_distinct_and_self_suffix_is_pattern_equals() {
// PATTERN-CLASSIFICATION PARTITION LAW: the paired-column
// SPAN's rows encode their sub-vocabulary identity in the
// per-row per-column identity relation — NAMED rows (indices
// 0..3) carry `row.0 != row.1` (pattern-DISTINCT-from-value),
// SELF rows (indices 3..5) carry `row.0 == row.1` (pattern-
// EQUALS-value). A consumer classifying an escape arm reads
// the sub-vocabulary off `row.0 == row.1` rather than off an
// index range or a separate tag — the classification IS the
// pair's per-column identity relation. Pins the load-bearing
// structural invariant that the paired-column SPAN encodes
// both sub-vocabularies AT the paired shape.
for i in 0..Atom::NAMED_ESCAPE_TABLE.len() {
let (src, decoded) = Atom::ESCAPE_TABLE[i];
assert_ne!(
src, decoded,
"ESCAPE_TABLE[{i}] ({src:?}, {decoded:?}) is in the \
NAMED prefix but its per-column identity relation \
collapsed to `src == decoded` — the pattern-DISTINCT-\
from-value classification is broken.",
);
}
for self_index in 0..Atom::SELF_ESCAPE_TABLE.len() {
let span_index = Atom::NAMED_ESCAPE_TABLE.len() + self_index;
let (src, decoded) = Atom::ESCAPE_TABLE[span_index];
assert_eq!(
src, decoded,
"ESCAPE_TABLE[{span_index}] ({src:?}, {decoded:?}) is \
in the SELF suffix but its per-column identity \
relation split to `src != decoded` — the pattern-\
EQUALS-value definitional-identity classification is \
broken.",
);
}
}
#[test]
fn atom_escape_table_every_row_projects_through_decode_str_escape_pointwise() {
// POINTWISE PROJECTION LAW: for every `(src, decoded)` row in
// ESCAPE_TABLE, `Atom::decode_str_escape(src) == decoded`. The
// paired-column SPAN closes the (input, output) cross-product
// of `decode_str_escape`'s non-passthrough arm-set at ONE typed
// array so a refactor that drifted the arm-set (swapped rows
// in ESCAPE_TABLE without swapping them in `decode_str_escape`
// or vice versa) surfaces HERE at the first drifted pair
// rather than at a distant sweep site. Sibling-shape pin to
// `atom_escape_decoded_projects_pointwise_from_escape_sources_through_decode_str_escape`
// one composition layer over: where that pin binds the two
// column-dual peer SPANs through `decode_str_escape`, this pin
// binds the paired-column SPAN's per-row `(src, decoded)`
// shape to `decode_str_escape`'s projection at the row level.
for (i, &(src, decoded)) in Atom::ESCAPE_TABLE.iter().enumerate() {
let projected = Atom::decode_str_escape(src);
assert_eq!(
projected, decoded,
"ESCAPE_TABLE[{i}] = ({src:?}, {decoded:?}) drifted \
from Atom::decode_str_escape({src:?}) = {projected:?} \
— the paired-column SPAN's per-row projection law is \
broken at index {i}.",
);
}
}
#[test]
fn atom_escape_table_sources_and_decoded_columns_pairwise_distinct() {
// COLUMN-WISE PAIRWISE DISJOINTNESS: the paired-column SPAN's
// SOURCE column AND DECODED column are each pairwise distinct.
// Inherited disjointness from the two column-dual peer
// `[char; 5]` SPANs already pinned at
// `atom_escape_sources_pairwise_distinct` +
// `atom_escape_decoded_pairwise_distinct`, but pinned HERE at
// the paired-array level so a refactor that drifted the paired
// SPAN's declaration order (collapsing two arms onto the same
// SOURCE or DECODED byte) surfaces at this test rather than
// at a distant sweep site. Sibling posture to the two column-
// dual peer SPANs' pairwise-distinctness tests.
for i in 0..Atom::ESCAPE_TABLE.len() {
for j in (i + 1)..Atom::ESCAPE_TABLE.len() {
assert_ne!(
Atom::ESCAPE_TABLE[i].0,
Atom::ESCAPE_TABLE[j].0,
"ESCAPE_TABLE SOURCE column collision: \
ESCAPE_TABLE[{i}].0 and ESCAPE_TABLE[{j}].0 are \
both {:?} — the paired-column SPAN's SOURCE \
column pairwise disjointness is broken.",
Atom::ESCAPE_TABLE[i].0,
);
assert_ne!(
Atom::ESCAPE_TABLE[i].1,
Atom::ESCAPE_TABLE[j].1,
"ESCAPE_TABLE DECODED column collision: \
ESCAPE_TABLE[{i}].1 and ESCAPE_TABLE[{j}].1 are \
both {:?} — the paired-column SPAN's DECODED \
column pairwise disjointness is broken.",
Atom::ESCAPE_TABLE[i].1,
);
}
}
}
// ── `Sexp::LIST_OPEN` / `Sexp::LIST_CLOSE` — the paired canonical
// `(` / `)` chars routed through the FOUR outer-structural round-
// trip sites: two `crate::reader::tokenize` outer-dispatch arms
// (`Token::LParen`, `Token::RParen`), two bare-atom terminator
// disjuncts (`|| ch == LIST_OPEN` / `|| ch == LIST_CLOSE`), and
// two `fmt::Display for Sexp` arms (`Self::List(_)` opener +
// closer AND `Self::Nil` two-char `()`). Sibling-shape tests to
// the `atom_str_delimiter_*` block above (Str-payload delimiter
// axis), lifted onto the outer-structural [`Sexp`] algebra.
#[test]
fn sexp_list_open_projects_canonical_open_paren_char() {
// Pins the constant's exact `char` value so a typo (`'['`,
// `'{'`, `';'`) or an accidental redefinition surfaces
// immediately. Sibling-shape pin to
// `atom_str_delimiter_projects_canonical_double_quote_char`
// (the Str-payload delimiter axis) — pins the SAME shape on
// the outer list-opener axis of the closed-set outer [`Sexp`]
// algebra.
assert_eq!(
Sexp::LIST_OPEN,
'(',
"LIST_OPEN char drifted from the substrate-canonical `(` \
opener — the reader-round-trip contract at \
crate::reader::tokenize (Token::LParen outer arm, bare-\
atom terminator disjunct) AND fmt::Display for Sexp \
(Self::List(_) opener, Self::Nil two-char left) all bind \
to this ONE constant.",
);
}
#[test]
fn sexp_list_close_projects_canonical_close_paren_char() {
// Pins the constant's exact `char` value so a typo (`']'`,
// `'}'`, `';'`) or an accidental redefinition surfaces
// immediately. Section-for-retraction sibling pin of the
// opener above; the paired-delimiter round-trip contract
// holds iff both constants pin their canonical bytes here.
assert_eq!(
Sexp::LIST_CLOSE,
')',
"LIST_CLOSE char drifted from the substrate-canonical `)` \
closer — the reader-round-trip contract at \
crate::reader::tokenize (Token::RParen outer arm, bare-\
atom terminator disjunct) AND fmt::Display for Sexp \
(Self::List(_) closer, Self::Nil two-char right) all \
bind to this ONE constant.",
);
}
#[test]
fn sexp_list_delimiters_distinct_from_every_other_algebra_marker() {
// Cross-axis disjointness pin: neither `Sexp::LIST_OPEN` nor
// `Sexp::LIST_CLOSE` may alias any sibling outer-marker
// char on the substrate's other closed-set algebras — the
// Str-payload delimiter (`Atom::STR_DELIMITER`), the
// Keyword-marker prefix (`Atom::KEYWORD_MARKER`), the two
// Bool-literal spellings (`Atom::bool_literal(true|false)`),
// AND every quote-family lead char
// (`QuoteForm::lead_char(qf)` for each `qf` in
// `QuoteForm::ALL`). Otherwise a bare `(`/`)`-starting lexeme
// would ambiguously route through TWO outer-dispatch arms in
// `crate::reader::tokenize`. Guards the paired disjointness
// across the substrate's outer-marker axes so a future
// refactor that swaps a marker to collide with either list
// delimiter surfaces at this pin rather than as a silent
// reader misclassification.
//
// First: opener/closer disjoint from each other — pairs
// MUST be structurally distinct.
assert_ne!(
Sexp::LIST_OPEN,
Sexp::LIST_CLOSE,
"LIST_OPEN and LIST_CLOSE share a byte — the paired-\
delimiter contract would collapse.",
);
// Second: opener/closer disjoint from Str-delimiter.
assert_ne!(
Sexp::LIST_OPEN,
Atom::STR_DELIMITER,
"LIST_OPEN and STR_DELIMITER share a byte — a bare `{}foo` \
lexeme would ambiguously begin a list AND open a string.",
Atom::STR_DELIMITER,
);
assert_ne!(
Sexp::LIST_CLOSE,
Atom::STR_DELIMITER,
"LIST_CLOSE and STR_DELIMITER share a byte — a bare `{}foo` \
lexeme would ambiguously close a list AND open a string.",
Atom::STR_DELIMITER,
);
// Third: opener/closer disjoint from KEYWORD_MARKER's LEAD
// `char` (single-char `":"` on the outer axis) — the
// `Atom::KEYWORD_MARKER` `&'static str`'s projected lead byte
// lives at `Atom::KEYWORD_MARKER_LEAD` on the closed-set
// outer [`Atom`] algebra.
assert_ne!(
Sexp::LIST_OPEN,
Atom::KEYWORD_MARKER_LEAD,
"LIST_OPEN and KEYWORD_MARKER_LEAD share a byte — a bare \
`{}foo` lexeme would ambiguously begin a list AND begin \
a keyword.",
Atom::KEYWORD_MARKER_LEAD,
);
assert_ne!(
Sexp::LIST_CLOSE,
Atom::KEYWORD_MARKER_LEAD,
"LIST_CLOSE and KEYWORD_MARKER_LEAD share a byte — a bare \
`{}foo` lexeme would ambiguously close a list AND begin \
a keyword.",
Atom::KEYWORD_MARKER_LEAD,
);
// Fourth: opener/closer disjoint from every Bool-literal
// spelling's first char (`'#'` for both `"#t"` / `"#f"`).
for b in [true, false] {
let lead = Atom::bool_literal(b)
.chars()
.next()
.expect("bool_literal must be non-empty");
assert_ne!(
Sexp::LIST_OPEN,
lead,
"LIST_OPEN and bool_literal({b:?}) share a lead byte — a \
bare `{lead}...` lexeme would ambiguously begin a list \
AND classify as a Bool.",
);
assert_ne!(
Sexp::LIST_CLOSE,
lead,
"LIST_CLOSE and bool_literal({b:?}) share a lead byte — a \
bare `{lead}...` lexeme would ambiguously close a list \
AND classify as a Bool.",
);
}
// Fifth: opener/closer disjoint from every quote-family
// lead char (`'\''`, `` '`' ``, `','` — three distinct lead
// chars across the four `QuoteForm` variants). The reader's
// outer-dispatch orders the quote-family arm BEFORE the
// list-delimiter arms, so a collision here would silently
// route `(`/`)` through the quote-family branch.
for qf in QuoteForm::ALL {
assert_ne!(
Sexp::LIST_OPEN,
qf.lead_char(),
"LIST_OPEN and QuoteForm::{qf:?}::lead_char share a byte — \
a bare `(...)` list would silently route through the \
quote-family outer-dispatch arm.",
);
assert_ne!(
Sexp::LIST_CLOSE,
qf.lead_char(),
"LIST_CLOSE and QuoteForm::{qf:?}::lead_char share a byte — \
a bare `(...)` list-closer would silently route through \
the quote-family outer-dispatch arm.",
);
}
}
#[test]
fn sexp_display_nil_arm_binds_to_both_list_delimiter_constants() {
// NIL DISPLAY CONTRACT: pin that `format!("{}", Sexp::Nil)`
// produces the two-char rendering composed of BOTH typed
// delimiters — `LIST_OPEN` followed by `LIST_CLOSE`. Pre-lift
// this arm carried the two bytes inline as ONE `"()"` string
// literal; post-lift each byte binds to its typed constant,
// so a delimiter swap flips both the opener AND the closer in
// lockstep at the typed algebra rather than at this arm's
// inline literal. A regression that re-inlines the two bytes
// OR drifts ONE of the two typed-constant bindings fails
// loudly at this composition pin.
let rendered = format!("{}", Sexp::Nil);
let expected: String = Sexp::LIST_DELIMITERS.iter().collect();
assert_eq!(
rendered, expected,
"Sexp::Nil Display drifted from the [LIST_OPEN, LIST_CLOSE] \
composition — the two-char `()` rendering must be the \
string composed of the two typed constants in order.",
);
// Cross-check against the bare byte-string to catch a
// regression that silently swaps the two constants' values.
assert_eq!(
rendered, "()",
"Sexp::Nil Display drifted from the canonical `()` two-char \
rendering — a typed-constant swap would produce e.g. `)(` \
which passes the `[LIST_OPEN, LIST_CLOSE]` compose test \
but fails this hard-coded reference check.",
);
}
#[test]
fn sexp_display_list_arms_bind_to_sexp_list_delimiter_constants() {
// LIST DISPLAY CONTRACT: pin that `format!("{}", Sexp::List(_))`
// opens with `LIST_OPEN`, closes with `LIST_CLOSE`, and
// interleaves the children through the arm's ` `-separator
// loop. Sweeps a representative small list plus the singleton
// list plus the empty list — the empty list is IMPORTANT
// because `Sexp::List(vec![])` is a distinct `Sexp` shape from
// `Sexp::Nil`, and both must render as `()` through the outer
// algebra (the reader's `()` source produces `Sexp::List(vec![])`
// — see the `read` pipeline in `crate::reader`). A regression
// that drifts either arm's binding surfaces here.
for list in [
Sexp::List(vec![]),
Sexp::List(vec![Sexp::symbol("x")]),
Sexp::List(vec![Sexp::symbol("a"), Sexp::symbol("b")]),
Sexp::List(vec![Sexp::int(1), Sexp::int(2), Sexp::int(3)]),
] {
let rendered = format!("{list}");
let first = rendered
.chars()
.next()
.unwrap_or_else(|| panic!("empty rendering for {list:?}"));
let last = rendered
.chars()
.last()
.unwrap_or_else(|| panic!("empty rendering for {list:?}"));
assert_eq!(
first,
Sexp::LIST_OPEN,
"List Display opener drifted from LIST_OPEN for {list:?}: \
got {rendered:?}",
);
assert_eq!(
last,
Sexp::LIST_CLOSE,
"List Display closer drifted from LIST_CLOSE for {list:?}: \
got {rendered:?}",
);
}
}
#[test]
fn sexp_list_delimiters_close_reader_display_round_trip_for_lists_of_atoms() {
// Load-bearing round-trip contract for the four outer-
// structural sites — the reader's `Token::LParen` /
// `Token::RParen` outer-dispatch arms both bind to
// `Sexp::LIST_OPEN` / `Sexp::LIST_CLOSE`, AND the Display
// impl's `Self::List(_)` arms bind to the SAME two constants,
// so wrapping a sequence of atom lexemes in the constants on
// both sides recovers a `Sexp::List(_)` shape that
// round-trips through Display and the reader without drift.
// A regression that swaps ONE of the four arms (e.g.
// re-inlines `'('` at the reader opener while migrating the
// Display opener to a different delimiter) breaks the
// opener-must-match-closer contract across two files.
for children in [
vec![],
vec![Sexp::symbol("foo")],
vec![Sexp::symbol("a"), Sexp::symbol("b"), Sexp::int(42)],
] {
let original = Sexp::List(children);
let rendered = format!("{original}");
let reread = crate::reader::read(&rendered).unwrap_or_else(|e| {
panic!(
"reader rejected Display-rendered list `{rendered}` \
for `{original:?}`: {e}"
)
});
assert_eq!(
reread.len(),
1,
"Display-rendered list `{rendered}` must read as exactly \
one form, got {reread:?}",
);
assert_eq!(
reread[0], original,
"read(display(list)) drifted from list for {original:?} \
— rendered={rendered:?} reread={reread:?}",
);
}
}
#[test]
fn sexp_list_delimiters_composes_from_algebra_constants_in_declaration_order() {
// FAMILY COMPOSITION LAW: pin that the ALL array's rows are the
// two paired-delimiter algebra constants (`Self::LIST_OPEN`,
// `Self::LIST_CLOSE`) in canonical declaration order matching
// the substrate-canonical (opener, closer) pair shape every
// consumer expects. A reorder of ONE row without reordering
// the underlying algebra constants silently misaligns every
// index-sweep consumer (`Nil` Display's `.iter().collect()`
// routing, a hypothetical `Sexp::LIST_DELIMITERS[0]` opener
// lookup, the sub-vocabulary sweep at
// `is_bare_atom_boundary`). Sibling-shape pin to
// `atom_self_escape_table_composes_from_algebra_constants_in_declaration_order`
// on the peer `[char; 2]` sub-vocabulary at
// [`Atom::SELF_ESCAPE_TABLE`].
assert_eq!(
Sexp::LIST_DELIMITERS,
[Sexp::LIST_OPEN, Sexp::LIST_CLOSE],
"LIST_DELIMITERS composition drifted from the canonical \
(LIST_OPEN, LIST_CLOSE) pair — the paired-delimiter \
sub-vocabulary lift must route through the two typed \
algebra constants in that order.",
);
}
#[test]
fn sexp_list_delimiters_has_expected_cardinality() {
// CARDINALITY PIN: `[char; 2]` at rustc — this assert pins the
// runtime observable so a refactor that loosens the array's
// type to `&[char]` (dropping the compile-time arity forcing)
// fails HERE at the runtime cardinality assertion rather than
// silently allowing a third or absent row. Sibling-shape pin
// to `atom_self_escape_table_has_expected_cardinality`.
assert_eq!(
Sexp::LIST_DELIMITERS.len(),
2,
"LIST_DELIMITERS cardinality drifted from 2 — the paired \
(opener, closer) sub-vocabulary MUST be exactly two rows.",
);
}
#[test]
fn sexp_list_delimiters_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: the two paired-delimiter rows MUST NOT
// alias (a hypothetical `[` opener + `[` closer degenerate
// list-mode would silently collapse the paired-delimiter
// contract and lose the ability to bracket a well-formed list
// — the reader's `Token::LParen` and `Token::RParen` arms
// would collide at the same byte). Sibling-shape pin to
// `atom_self_escape_table_pairwise_distinct` on the peer
// `[char; 2]` sub-vocabulary at [`Atom::SELF_ESCAPE_TABLE`].
for (i, a) in Sexp::LIST_DELIMITERS.iter().enumerate() {
for (j, b) in Sexp::LIST_DELIMITERS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"LIST_DELIMITERS rows [{i}] and [{j}] share a byte \
({a:?} == {b:?}) — the paired-delimiter contract \
would collapse.",
);
}
}
}
#[test]
fn sexp_list_delimiters_disjoint_from_str_delimiter() {
// CROSS-AXIS DISJOINTNESS (Str-delimiter): no row of
// `LIST_DELIMITERS` may alias `Atom::STR_DELIMITER` — otherwise
// the reader's `Token::LParen` / `Token::RParen` outer-dispatch
// arms would collide with `Token::Str`'s opener/closer arm at
// the same byte. Sibling-shape pin to
// `atom_named_escape_table_disjoint_from_self_escape_algebra_constants`:
// both close the cross-sub-vocabulary disjointness contract at
// the ALL-array level rather than as an inline disjunction per
// consumer.
for (i, ch) in Sexp::LIST_DELIMITERS.iter().enumerate() {
assert_ne!(
*ch,
Atom::STR_DELIMITER,
"LIST_DELIMITERS[{i}] ({ch:?}) aliases Atom::STR_DELIMITER \
({:?}) — the reader's list-delimiter arm would collide \
with the Str-payload delimiter arm at the same byte.",
Atom::STR_DELIMITER,
);
}
}
#[test]
fn sexp_list_delimiters_disjoint_from_comment_lead() {
// CROSS-AXIS DISJOINTNESS (comment lead): no row of
// `LIST_DELIMITERS` may alias `Sexp::COMMENT_LEAD` — otherwise
// the reader's list-delimiter arm would collide with the
// line-comment discard arm at the same byte. Closes the
// structural coherence contract between the outer-structural
// list-delimiter sub-vocabulary and the reader-discard
// sub-vocabulary on the SAME closed-set outer [`Sexp`]
// algebra.
for (i, ch) in Sexp::LIST_DELIMITERS.iter().enumerate() {
assert_ne!(
*ch,
Sexp::COMMENT_LEAD,
"LIST_DELIMITERS[{i}] ({ch:?}) aliases Sexp::COMMENT_LEAD \
({:?}) — the reader's list-delimiter arm would collide \
with the line-comment lead arm at the same byte.",
Sexp::COMMENT_LEAD,
);
}
}
#[test]
fn sexp_is_bare_atom_boundary_routes_through_list_delimiters_for_every_row() {
// PATH-UNIFORMITY PIN: every row of `LIST_DELIMITERS` MUST
// classify as a bare-atom boundary via
// `Sexp::is_bare_atom_boundary`. A regression that reverted the
// projection's list-delimiter disjunct to two inline
// `|| ch == Self::LIST_OPEN || ch == Self::LIST_CLOSE`
// enumerations AND drifted one of the two constants (or vice
// versa) fails HERE at the first mismatched row rather than at
// a distant tokenize-round-trip. Sibling-shape pin to
// `atom_decode_str_escape_routes_through_self_escape_table_for_every_row`
// on the peer `[char; 2]` sub-vocabulary at
// [`Atom::SELF_ESCAPE_TABLE`].
for (i, ch) in Sexp::LIST_DELIMITERS.iter().enumerate() {
assert!(
Sexp::is_bare_atom_boundary(*ch),
"LIST_DELIMITERS[{i}] ({ch:?}) does NOT classify as a \
bare-atom boundary via Sexp::is_bare_atom_boundary — \
the paired-delimiter sub-vocabulary sweep drifted from \
the reader's outer-dispatch arm-set.",
);
}
}
// ── `Sexp::COMMENT_LEAD` — the canonical `;` char routed through
// the reader's TWO comment-boundary sites: the outer-dispatch arm
// that begins a line-comment run AND the bare-atom terminator
// disjunct that breaks a `Token::Atom` accumulator on this byte.
// Sibling-shape tests to the `sexp_list_open_close` block above
// (outer-structural paired-delimiter axis), lifted onto the reader-
// discard axis of the closed-set outer [`Sexp`] algebra.
#[test]
fn sexp_comment_lead_projects_canonical_semicolon_char() {
// Pins the constant's exact `char` value so a typo (`'#'`,
// `'!'`, `':'`) or an accidental redefinition surfaces
// immediately. Sibling-shape pin to
// `sexp_list_open_projects_canonical_open_paren_char` on the
// outer-structural axis — pins the SAME shape on the reader-
// discard axis of the closed-set outer [`Sexp`] algebra.
assert_eq!(
Sexp::COMMENT_LEAD,
';',
"COMMENT_LEAD char drifted from the substrate-canonical `;` \
line-comment lead — the reader-discard contract at \
crate::reader::tokenize (line-comment outer arm, bare-atom \
terminator disjunct) binds to this ONE constant.",
);
}
#[test]
fn sexp_comment_lead_distinct_from_every_other_algebra_marker() {
// Cross-axis disjointness pin: `Sexp::COMMENT_LEAD` may NOT
// alias any sibling outer-marker char on the substrate's other
// closed-set algebras — the paired list delimiters
// (`Sexp::LIST_OPEN` / `Sexp::LIST_CLOSE`), the Str-payload
// delimiter (`Atom::STR_DELIMITER`), the Keyword-marker prefix
// (`Atom::KEYWORD_MARKER`'s lead byte), the two Bool-literal
// spellings' lead byte (`Atom::bool_literal(true|false)`'s first
// char), AND every quote-family lead char
// (`QuoteForm::lead_char(qf)` for each `qf` in `QuoteForm::ALL`).
// Otherwise a bare `;`-starting lexeme would ambiguously route
// through the line-comment arm AND a sibling algebra's arm in
// `crate::reader::tokenize`. Guards the paired disjointness
// across the substrate's outer-marker axes so a future refactor
// that swaps a marker to collide with the comment lead surfaces
// at this pin rather than as a silent reader misclassification.
assert_ne!(
Sexp::COMMENT_LEAD,
Sexp::LIST_OPEN,
"COMMENT_LEAD and LIST_OPEN share a byte — a bare `{}foo` \
lexeme would ambiguously begin a list AND begin a comment.",
Sexp::LIST_OPEN,
);
assert_ne!(
Sexp::COMMENT_LEAD,
Sexp::LIST_CLOSE,
"COMMENT_LEAD and LIST_CLOSE share a byte — a bare `{}foo` \
lexeme would ambiguously close a list AND begin a comment.",
Sexp::LIST_CLOSE,
);
assert_ne!(
Sexp::COMMENT_LEAD,
Atom::STR_DELIMITER,
"COMMENT_LEAD and STR_DELIMITER share a byte — a bare `{}foo` \
lexeme would ambiguously begin a comment AND open a string.",
Atom::STR_DELIMITER,
);
assert_ne!(
Sexp::COMMENT_LEAD,
Atom::KEYWORD_MARKER_LEAD,
"COMMENT_LEAD and KEYWORD_MARKER_LEAD share a byte — a bare \
`{lead}foo` lexeme would ambiguously begin a comment AND \
begin a keyword.",
lead = Atom::KEYWORD_MARKER_LEAD,
);
for b in [true, false] {
let lead = Atom::bool_literal(b)
.chars()
.next()
.expect("bool_literal must be non-empty");
assert_ne!(
Sexp::COMMENT_LEAD,
lead,
"COMMENT_LEAD and bool_literal({b:?}) share a lead byte — a \
bare `{lead}...` lexeme would ambiguously begin a comment \
AND classify as a Bool.",
);
}
for qf in QuoteForm::ALL {
assert_ne!(
Sexp::COMMENT_LEAD,
qf.lead_char(),
"COMMENT_LEAD and QuoteForm::{qf:?}::lead_char share a byte — \
a bare `;`-starting source would silently route through the \
quote-family outer-dispatch arm.",
);
}
}
// ── `Sexp::COMMENT_TERM` — the canonical `\n` char that terminates
// a line-comment run in the reader's tokenizer. Section-for-retraction
// sibling of `Sexp::COMMENT_LEAD` on the reader-discard axis; paired
// opener/terminator peer of `Sexp::LIST_OPEN` / `Sexp::LIST_CLOSE`
// on the outer-structural axis. The pins below anchor the constant's
// exact byte AND its cross-axis disjointness against every
// non-whitespace closed-set outer-marker char.
#[test]
fn sexp_comment_term_projects_canonical_line_feed_char() {
// Pins the constant's exact `char` value so a typo (`'\r'`,
// `'\0'`, a display-glyph substitution) or an accidental
// redefinition surfaces immediately. Sibling-shape pin to
// `sexp_comment_lead_projects_canonical_semicolon_char` on the
// reader-discard axis — pins the SAME shape at the terminator
// side of the (COMMENT_LEAD, COMMENT_TERM) paired-delimiter
// algebra on the closed-set outer [`Sexp`] algebra.
assert_eq!(
Sexp::COMMENT_TERM,
'\n',
"COMMENT_TERM char drifted from the substrate-canonical `\\n` \
line-feed byte — the reader-discard contract at \
crate::reader::tokenize's line-comment discard loop binds \
to this ONE constant.",
);
}
#[test]
fn sexp_comment_term_is_whitespace_family_char() {
// WHITESPACE-FAMILY PIN: the line-comment terminator MUST be a
// whitespace char. The reader's outer-match's `ws if
// ws.is_whitespace()` arm absorbs any lingering COMMENT_TERM
// byte after the discard loop terminates on it — a regression
// that repointed COMMENT_TERM at a NON-whitespace byte would
// BOTH break the discard loop's semantics AND leak the byte
// into the token stream as an outer-dispatch dispatch (either a
// specific arm firing on it, or the bare-atom accumulator
// consuming it). Pin the property structurally so a byte swap
// that lost whitespace-family membership surfaces here rather
// than as a downstream tokenizer misclassification.
assert!(
Sexp::COMMENT_TERM.is_whitespace(),
"COMMENT_TERM `{:?}` is NOT a whitespace char — the reader's \
outer-match whitespace arm would fail to absorb it AND the \
line-comment discard loop's terminator would leak the byte \
into the token stream.",
Sexp::COMMENT_TERM,
);
}
#[test]
fn sexp_comment_term_distinct_from_every_non_whitespace_algebra_marker() {
// Cross-axis disjointness pin: `Sexp::COMMENT_TERM` may NOT
// alias any NON-whitespace sibling outer-marker char on the
// substrate's other closed-set algebras — the paired list
// delimiters (`Sexp::LIST_OPEN` / `Sexp::LIST_CLOSE`), the
// line-comment lead (`Sexp::COMMENT_LEAD`), the Str-payload
// delimiter + escape-lead (`Atom::STR_DELIMITER` /
// `Atom::STR_ESCAPE_LEAD`), the Keyword-marker prefix
// (`Atom::KEYWORD_MARKER`'s lead byte), the two Bool-literal
// spellings' lead byte (`Atom::bool_literal(true|false)`'s
// first char), AND every quote-family lead char
// (`QuoteForm::lead_char(qf)` for each `qf` in `QuoteForm::ALL`).
// The disjointness contract EXCLUDES the whitespace-family
// axis — the terminator's role IS to be whitespace-family, so
// the outer-match's `ws if ws.is_whitespace()` arm absorbs it
// by design (see `sexp_comment_term_is_whitespace_family_char`
// above). Sibling-shape pin to
// `sexp_comment_lead_distinct_from_every_other_algebra_marker`
// on the lead side of the paired-delimiter algebra — pins the
// SAME shape at the terminator side.
assert_ne!(
Sexp::COMMENT_TERM,
Sexp::LIST_OPEN,
"COMMENT_TERM and LIST_OPEN share a byte — the reader's \
line-comment discard loop would terminate on the SAME byte \
the outer-dispatch's list-opening arm binds to.",
);
assert_ne!(
Sexp::COMMENT_TERM,
Sexp::LIST_CLOSE,
"COMMENT_TERM and LIST_CLOSE share a byte — the reader's \
line-comment discard loop would terminate on the SAME byte \
the outer-dispatch's list-closing arm binds to.",
);
assert_ne!(
Sexp::COMMENT_TERM,
Sexp::COMMENT_LEAD,
"COMMENT_TERM and COMMENT_LEAD share a byte — a bare \
`{lead}{lead}` two-char source would AMBIGUOUSLY begin AND \
terminate the SAME comment run at the SAME byte, collapsing \
the paired-delimiter algebra onto ONE char.",
lead = Sexp::COMMENT_LEAD,
);
assert_ne!(
Sexp::COMMENT_TERM,
Atom::STR_DELIMITER,
"COMMENT_TERM and STR_DELIMITER share a byte — the reader's \
line-comment discard loop would terminate on the SAME byte \
the outer-dispatch's string-opening arm binds to.",
);
assert_ne!(
Sexp::COMMENT_TERM,
Atom::STR_ESCAPE_LEAD,
"COMMENT_TERM and STR_ESCAPE_LEAD share a byte — the reader's \
line-comment discard loop would terminate on the SAME byte \
the Str-payload's escape-handler outer arm binds to.",
);
assert_ne!(
Sexp::COMMENT_TERM,
Atom::KEYWORD_MARKER_LEAD,
"COMMENT_TERM and KEYWORD_MARKER_LEAD share a byte — the \
reader's line-comment discard loop would terminate on the \
SAME byte the from_lexeme keyword-prefix arm binds to.",
);
for b in [true, false] {
let lead = Atom::bool_literal(b)
.chars()
.next()
.expect("bool_literal must be non-empty");
assert_ne!(
Sexp::COMMENT_TERM,
lead,
"COMMENT_TERM and bool_literal({b:?}) share a lead byte — \
the reader's line-comment discard loop would terminate \
on the SAME byte the from_lexeme bool-literal arm binds \
to.",
);
}
for qf in QuoteForm::ALL {
assert_ne!(
Sexp::COMMENT_TERM,
qf.lead_char(),
"COMMENT_TERM and QuoteForm::{qf:?}::lead_char share a \
byte — the reader's line-comment discard loop would \
terminate on the SAME byte the quote-family outer- \
dispatch arm binds to.",
);
}
}
// ── `Sexp::COMMENT_DELIMITERS` — the paired (opener, terminator)
// reader-discard sub-vocabulary on the closed-set outer [`Sexp`]
// algebra. Sibling-shape tests to the `sexp_list_delimiters_*` block
// above (outer-structural paired-delimiter axis), lifted onto the
// reader-discard axis of the SAME algebra at the SAME `[char; 2]`
// shape.
#[test]
fn sexp_comment_delimiters_composes_from_algebra_constants_in_declaration_order() {
// FAMILY COMPOSITION LAW: pin that the ALL array's rows are the
// two paired reader-discard algebra constants
// (`Self::COMMENT_LEAD`, `Self::COMMENT_TERM`) in canonical
// (opener, terminator) declaration order matching the
// substrate-canonical paired-role shape every consumer expects.
// A reorder of ONE row without reordering the underlying
// algebra constants silently misaligns every index-sweep
// consumer (a hypothetical `Sexp::COMMENT_DELIMITERS[0]` opener
// lookup, an LSP span-highlighter that renders the (opener,
// terminator) span as-is, the metric label-set generator that
// walks the array). Sibling-shape pin to
// `sexp_list_delimiters_composes_from_algebra_constants_in_declaration_order`
// on the outer-structural axis; both close the (opener,
// closer_or_terminator) pair contract at ONE typed ALL array.
assert_eq!(
Sexp::COMMENT_DELIMITERS,
[Sexp::COMMENT_LEAD, Sexp::COMMENT_TERM],
"COMMENT_DELIMITERS composition drifted from the canonical \
(COMMENT_LEAD, COMMENT_TERM) pair — the paired-discard \
sub-vocabulary lift must route through the two typed \
algebra constants in that order.",
);
}
#[test]
fn sexp_comment_delimiters_has_expected_cardinality() {
// CARDINALITY PIN: `[char; 2]` at rustc — this assert pins the
// runtime observable so a refactor that loosens the array's
// type to `&[char]` (dropping the compile-time arity forcing)
// fails HERE at the runtime cardinality assertion rather than
// silently allowing a third or absent row. Sibling-shape pin
// to `sexp_list_delimiters_has_expected_cardinality` on the
// outer-structural axis.
assert_eq!(
Sexp::COMMENT_DELIMITERS.len(),
2,
"COMMENT_DELIMITERS cardinality drifted from 2 — the paired \
(opener, terminator) reader-discard sub-vocabulary MUST be \
exactly two rows.",
);
}
#[test]
fn sexp_comment_delimiters_pairwise_distinct() {
// PAIRWISE DISJOINTNESS: the two paired reader-discard rows
// MUST NOT alias (a hypothetical degenerate `;` opener + `;`
// terminator convention would collapse the paired-delimiter
// contract — the discard loop's terminator check `ch ==
// Sexp::COMMENT_TERM` inside a run led by `Sexp::COMMENT_LEAD`
// would fire on the very byte that opened the run, breaking
// the loop after zero characters and leaving the actual comment
// body in the token stream). Sibling-shape pin to
// `sexp_list_delimiters_pairwise_distinct` on the outer-
// structural axis; both close the pairwise-distinctness
// contract at the ALL-array level rather than at an inline
// `assert_ne!(LEAD, TERM)` per consumer.
for (i, a) in Sexp::COMMENT_DELIMITERS.iter().enumerate() {
for (j, b) in Sexp::COMMENT_DELIMITERS.iter().enumerate() {
if i == j {
continue;
}
assert_ne!(
a, b,
"COMMENT_DELIMITERS rows [{i}] and [{j}] share a byte \
({a:?} == {b:?}) — the paired-discard contract \
would collapse.",
);
}
}
}
#[test]
fn sexp_comment_delimiters_lead_row_is_bare_atom_boundary() {
// PATH-UNIFORMITY PIN (LEAD row, non-whitespace): the [0] row
// (`Sexp::COMMENT_LEAD`, `;`) MUST classify as a bare-atom
// boundary via `Sexp::is_bare_atom_boundary` — the reader's
// outer-dispatch cascade has a DEDICATED line-comment arm
// keyed on this byte, so the projection's disjunction
// enumerates it. A regression that dropped the LEAD from
// `is_bare_atom_boundary`'s disjunction OR that pointed
// `COMMENT_DELIMITERS[0]` at a byte the projection doesn't
// recognize as a boundary fails HERE rather than at a distant
// tokenize-round-trip. Sibling-shape pin to
// `sexp_is_bare_atom_boundary_routes_through_list_delimiters_for_every_row`
// — the LIST_DELIMITERS peer sweeps BOTH rows through the
// predicate; this pin sweeps ONLY the LEAD row (index 0),
// because the TERM row (index 1) classifies through the
// whitespace-family axis, NOT the bare-atom-boundary predicate
// directly.
assert!(
Sexp::is_bare_atom_boundary(Sexp::COMMENT_DELIMITERS[0]),
"COMMENT_DELIMITERS[0] ({:?}) does NOT classify as a \
bare-atom boundary via Sexp::is_bare_atom_boundary — the \
reader-discard opener row drifted from the reader's \
outer-dispatch arm-set.",
Sexp::COMMENT_DELIMITERS[0],
);
}
#[test]
fn sexp_comment_delimiters_term_row_is_whitespace_family_char() {
// PATH-UNIFORMITY PIN (TERM row, whitespace): the [1] row
// (`Sexp::COMMENT_TERM`, `'\n'`) MUST classify as a whitespace
// char via `char::is_whitespace` — the reader's line-comment
// discard loop consumes bytes up to and including the FIRST
// COMMENT_TERM, then hands control back to the outer-dispatch's
// `ws if ws.is_whitespace()` arm which absorbs any lingering
// COMMENT_TERM byte cleanly. A regression that repointed
// `COMMENT_DELIMITERS[1]` at a NON-whitespace byte (e.g. a `#`
// reader-macro-lead) would break the post-discard hand-off:
// the reader would either loop indefinitely on the byte or
// silently tokenize it into the next Token::Atom. Pinning the
// whitespace-family membership at the array's TERM row keeps
// the outer-dispatch's cascading arm-set structurally coherent
// through the ALL array. Sibling-shape pin to
// `sexp_comment_term_is_whitespace_family_char` above; that
// pin binds the whitespace-family membership to the
// `Self::COMMENT_TERM` constant directly, this pin binds it to
// the ALL array's [1] row so any override of the TERM row via
// a refactored `pub const` misalignment surfaces HERE too.
assert!(
Sexp::COMMENT_DELIMITERS[1].is_whitespace(),
"COMMENT_DELIMITERS[1] ({:?}) does NOT classify as a \
whitespace char via char::is_whitespace — the reader's \
line-comment discard loop's post-loop hand-off to the \
outer-dispatch's whitespace arm would break at the \
non-whitespace terminator.",
Sexp::COMMENT_DELIMITERS[1],
);
}
#[test]
fn sexp_comment_delimiters_disjoint_from_list_delimiters() {
// CROSS-AXIS DISJOINTNESS (same-algebra): no row of
// `COMMENT_DELIMITERS` may alias any row of
// `LIST_DELIMITERS` — the reader-discard axis and the
// outer-structural list-delimiter axis partition their
// respective bytes disjointly on the SAME closed-set outer
// [`Sexp`] algebra. Otherwise the reader's dedicated line-
// comment arm would collide with the `Token::LParen` /
// `Token::RParen` arms at the same byte, silently reclassifying
// a bare `(` or `)` as a comment lead or vice versa. Sibling-
// shape pin to `sexp_list_delimiters_disjoint_from_comment_lead`
// above (the outer-structural axis's mirror pin against the
// LEAD row); this pin closes the FULL 2×2 cross-axis
// disjointness contract rather than only the LEAD row against
// both LIST rows.
for (i, ch) in Sexp::COMMENT_DELIMITERS.iter().enumerate() {
for (j, other) in Sexp::LIST_DELIMITERS.iter().enumerate() {
assert_ne!(
*ch, *other,
"COMMENT_DELIMITERS[{i}] ({ch:?}) aliases \
LIST_DELIMITERS[{j}] ({other:?}) — the reader- \
discard axis and the outer-structural list- \
delimiter axis share a byte, silently reclassifying \
the shared byte at the reader's outer dispatch.",
);
}
}
}
#[test]
fn sexp_comment_delimiters_disjoint_from_str_delimiter() {
// CROSS-ALGEBRA DISJOINTNESS (Str-delimiter): no row of
// `COMMENT_DELIMITERS` may alias `Atom::STR_DELIMITER` —
// otherwise the reader's line-comment discard arm would
// collide with `Token::Str`'s opener/closer arm at the same
// byte. The disjointness contract binds ACROSS the two closed-
// set algebras (outer [`Sexp`] discard vocabulary vs. inner
// [`Atom`] Str-payload vocabulary), matching the sibling-shape
// pin `sexp_list_delimiters_disjoint_from_str_delimiter` on
// the outer-structural axis of the SAME [`Sexp`] algebra.
for (i, ch) in Sexp::COMMENT_DELIMITERS.iter().enumerate() {
assert_ne!(
*ch,
Atom::STR_DELIMITER,
"COMMENT_DELIMITERS[{i}] ({ch:?}) aliases \
Atom::STR_DELIMITER ({:?}) — the reader's line- \
comment discard arm would collide with the Str-payload \
delimiter arm at the same byte across the two closed- \
set algebras.",
Atom::STR_DELIMITER,
);
}
}
// ── `Sexp::is_bare_atom_boundary` — the ONE typed projection on the
// outer [`Sexp`] algebra that names the SIX-fold outer-dispatch
// category-leading char disjunction. The exhaustive pin below
// anchors each of the six categories AS a positive arm AND the
// load-bearing substrate marker LEAD bytes (`:` / `#` / `@`) AS
// negative arms — the three lead bytes are first-char classifiers
// for bare-atom payload families (Keyword / Bool / splice second-
// char), NOT outer-dispatch category-leading chars, and a
// regression that promoted any to a boundary would break their
// tokenization. The composition end-to-end pin (in reader tests)
// sweeps every boundary char through the bare-atom accumulator and
// asserts the atom terminates at exactly the boundary byte.
#[test]
fn sexp_is_bare_atom_boundary_matches_outer_dispatch_arm_set_exhaustively() {
// OUTER-DISPATCH COHERENCE PIN: the SIX outer-dispatch category-
// leading char families the reader's tokenizer specialises on
// MUST ALL classify as boundaries; no other char (bare-atom
// chars) may classify as one. This test enumerates the FULL
// outer-dispatch arm-set as a typed table AND sweeps a
// representative negative set, asserting the projection's
// predicate matches the outer-dispatch's specific-arm firing
// exactly. A refactor that added a SEVENTH outer-dispatch arm
// (e.g. `#|…|#` block-comment) to the reader without extending
// the projection's disjunction would fail HERE at the coherence
// sweep: the new lead byte would EITHER be a boundary the
// projection missed (test asserts positive, projection returns
// false → panic) OR a bare-atom char the reader stole from the
// default arm (silent tokenizer drift the projection doesn't
// catch). Either way the coherence pin catches the drift and
// forces the projection + outer-dispatch to stay in lockstep.
let positive_arms: Vec<(char, String)> = {
let mut arms: Vec<(char, String)> = vec![
(' ', "whitespace".to_string()),
('\t', "whitespace-tab".to_string()),
('\n', "whitespace-newline".to_string()),
(Sexp::LIST_OPEN, "LIST_OPEN".to_string()),
(Sexp::LIST_CLOSE, "LIST_CLOSE".to_string()),
(Atom::STR_DELIMITER, "STR_DELIMITER".to_string()),
(Sexp::COMMENT_LEAD, "COMMENT_LEAD".to_string()),
];
for qf in QuoteForm::ALL {
arms.push((qf.lead_char(), format!("QuoteForm::{qf:?}")));
}
arms
};
for (ch, name) in &positive_arms {
assert!(
Sexp::is_bare_atom_boundary(*ch),
"outer-dispatch arm `{name}` (`{ch:?}`) must classify as \
a boundary — the projection missed a category the \
reader's outer-dispatch specialises on",
);
}
// Negative sweep: every char below MUST fall through to the
// default bare-atom arm. Includes typical alpha, digit, and
// sign chars AND the three load-bearing substrate marker LEAD
// bytes (`:` / `#` / `@`) that are first-char classifiers for
// bare-atom payload families rather than outer-dispatch
// categories.
let negative_arms: &[char] = &[
'a',
'z',
'A',
'Z',
'0',
'9',
'-',
'+',
'_',
'.',
'=',
'<',
'>',
'!',
'?',
'/',
'*',
'%',
'&',
'|',
'^',
'~',
// The `KEYWORD_MARKER` prefix's lead byte lives at the
// typed `Atom::KEYWORD_MARKER_LEAD` constant on the closed-
// set outer [`Atom`] algebra. Pre-lift this slot held an
// inline `Atom::KEYWORD_MARKER.chars().next().unwrap()`
// chain extracting the byte from the `&'static str`
// projection; post-lift the byte lives at ONE named
// constant the `&'static str` projects to (pinned by
// `atom_keyword_marker_lead_prefixes_keyword_marker`).
Atom::KEYWORD_MARKER_LEAD,
// The bool_literal spellings' shared lead byte lives at
// the typed `Atom::BOOL_LITERAL_LEAD` constant on the
// closed-set outer [`Atom`] algebra. Pre-lift this slot
// held an inline `Atom::bool_literal(true).chars().next()
// .unwrap()` chain extracting the byte from ONE spelling;
// post-lift the byte lives at ONE named constant that
// BOTH spellings project through (pinned by
// `atom_bool_literal_lead_prefixes_every_bool_literal_spelling`).
Atom::BOOL_LITERAL_LEAD,
QuoteForm::SPLICE_DISCRIMINATOR,
];
for ch in negative_arms {
assert!(
!Sexp::is_bare_atom_boundary(*ch),
"bare-atom char {ch:?} must NOT classify as a boundary — \
the reader's outer-dispatch has NO specific arm on this \
byte; the default bare-atom arm must accept it",
);
}
}
#[test]
fn sexp_non_whitespace_bare_atom_terminators_has_expected_cardinality() {
// Cardinality contract: `Self::NON_WHITESPACE_BARE_ATOM_TERMINATORS.len()
// == 7` — pinned at the declaration site by rustc's forced-arity
// check on `[char; 7]`. This test surfaces the arity as a fail-
// loud runtime pin so a future refactor that switches the array
// type to `&[char]` (dropping the compile-time arity forcing)
// doesn't silently loosen the closed-set discipline the family
// relies on. The seven arms are the FULL non-whitespace category-
// leading char set the reader's outer-dispatch specialises on
// (two structural `Sexp::LIST_{OPEN,CLOSE}`, three
// `QuoteForm::{QUOTE,QUASIQUOTE,UNQUOTE}_LEAD`, one
// `Atom::STR_DELIMITER`, one `Sexp::COMMENT_LEAD`). Sibling
// posture to `sexp_list_delimiters_has_expected_cardinality`
// and `sexp_comment_delimiters_has_expected_cardinality` on the
// paired-role sub-arrays of the SAME closed set.
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS.len(),
7,
"Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS cardinality \
drifted from 7 — the reader's outer-dispatch specialises \
on exactly seven non-whitespace category-leading chars by \
construction; an extension surfaces here"
);
}
#[test]
fn sexp_non_whitespace_bare_atom_terminators_route_through_typed_sub_algebra_constants() {
// PATH-UNIFORMITY (family-wide ARRAY-side): the seven entries
// of `Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS` MUST bind
// byte-for-byte to the seven typed sub-algebra `pub const`
// primitives — no inline `char` literals. Catches a regression
// that inlines `['(', ')', '\'', '`', ',', '"', ';']`: both
// the alignment property AND the numeric bytes would still
// hold, but the algebra-provenance would disappear, so a
// future rename (e.g. `Sexp::LIST_OPEN → Sexp::PAREN_OPEN`,
// `Sexp::COMMENT_LEAD → Sexp::LINE_COMMENT_OPEN`) at any of
// the three sibling algebras would silently drift the array's
// provenance from the algebra's canonical spelling. Sibling
// posture to the `LIST_DELIMITERS` / `COMMENT_DELIMITERS`
// ARRAY-side provenance pins on the paired-role sub-arrays,
// AND to the shape-level HASH_DISCRIMINATORS ARRAY-side
// provenance pin
// `sexp_shape_hash_discriminators_align_with_typed_per_role_constants_by_index`
// on the outer-`Sexp` cache-key axis.
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS[0],
Sexp::LIST_OPEN
);
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS[1],
Sexp::LIST_CLOSE
);
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS[2],
QuoteForm::QUOTE_LEAD,
);
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS[3],
QuoteForm::QUASIQUOTE_LEAD,
);
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS[4],
QuoteForm::UNQUOTE_LEAD,
);
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS[5],
Atom::STR_DELIMITER,
);
assert_eq!(
Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS[6],
Sexp::COMMENT_LEAD,
);
}
#[test]
fn sexp_non_whitespace_bare_atom_terminators_are_pairwise_distinct() {
// INJECTIVITY CONTRACT: the seven entries of
// `Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS` MUST be pairwise
// distinct — no char appears twice across the (structural,
// quote-family, atomic-delimiter, comment-lead) sub-vocabularies.
// A silent collision (e.g. a hypothetical Racket-compat port
// moving `QuoteForm::QUOTE_LEAD` from `'\''` to `';'` conflating
// it with `Sexp::COMMENT_LEAD`, or a future block-comment
// extension re-using `Atom::STR_DELIMITER`) would break the
// reader's outer-dispatch's implicit "each specific arm fires
// on a DISTINCT lead char" contract — the `match c { … }`
// outer-dispatch in `crate::reader::tokenize` cannot admit
// duplicate patterns without breaking exhaustiveness. This pin
// surfaces the distinctness as a substrate-level structural
// theorem so a cross-algebra rename that flips the injectivity
// is a compile-time-verified regression at the sub-carving
// level (rustc-forbidden duplicate `match` patterns) AND a
// runtime fail-loud regression here.
let mut seen: std::collections::HashSet<char> = std::collections::HashSet::new();
for ch in Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS {
assert!(
seen.insert(ch),
"Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS carries a \
duplicate char {ch:?} — the reader's outer-dispatch \
arms MUST be pairwise disjoint by construction",
);
}
assert_eq!(seen.len(), Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS.len(),);
}
#[test]
fn sexp_is_bare_atom_boundary_agrees_with_terminators_array_on_non_whitespace_partition() {
// BOUNDARY-PREDICATE COMPOSITION LAW: for every char `ch`,
// `Sexp::is_bare_atom_boundary(ch) == (ch.is_whitespace() ||
// Self::NON_WHITESPACE_BARE_ATOM_TERMINATORS.contains(&ch))`.
// Pins the ARRAY-driven refactor of the boundary predicate
// against a regression that reverts the disjunction to the
// pre-lift three-part sub-expression composition (or drifts
// ONE sub-expression's arm silently). Sibling posture to
// `sexp_is_bare_atom_boundary_matches_outer_dispatch_arm_set_exhaustively`
// — that pin binds the boundary predicate's TRUTH-TABLE against
// the reader's outer-dispatch categories; this pin binds the
// boundary predicate's DEFINITION against the family-wide
// terminators ARRAY as the sole non-whitespace clause. The
// (positive, negative) sweep covers a whitespace char + the
// seven terminator entries as positives, and a representative
// negative set (alpha, digit, sign, and the three substrate
// marker LEADs `:` / `#` / `@`) as negatives.
for &ch in &Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS {
assert!(
Sexp::is_bare_atom_boundary(ch),
"Sexp::is_bare_atom_boundary({ch:?}) must return true \
for every char in NON_WHITESPACE_BARE_ATOM_TERMINATORS",
);
}
assert!(Sexp::is_bare_atom_boundary(' '));
assert!(Sexp::is_bare_atom_boundary('\t'));
assert!(Sexp::is_bare_atom_boundary('\n'));
for ch in ['a', 'Z', '0', '9', '-', '_', ':', '#', '@'] {
let expected =
ch.is_whitespace() || Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS.contains(&ch);
assert_eq!(
Sexp::is_bare_atom_boundary(ch),
expected,
"Sexp::is_bare_atom_boundary({ch:?}) drifted from the \
ARRAY-driven composition law",
);
}
}
// ── `assert_char_array_pairwise_distinct` — the const-fn compile-
// time pairwise-distinctness contract lifter. Sibling posture to
// the runtime `_pairwise_distinct` tests: those pin the property
// at test-run time on each individual array; these pins bind the
// lift's OWN contract (accept-distinct, reject-collision, runtime-
// callability, cross-array coverage) so a regression that silently
// weakens the helper (e.g. flipping `!=` to `==`, dropping the
// inner `j` loop, or returning early on collision) is caught by
// the helper's OWN test surface rather than only surfacing as a
// false-positive on some future array's distinctness pin.
#[test]
fn assert_char_array_pairwise_distinct_accepts_the_empty_array() {
// Empty array — vacuously pairwise distinct (no pair to
// collide). The compile-time `const _: () = assert_char_array_
// pairwise_distinct(&EMPTY);` would land on this arm, so the
// runtime call MUST return normally.
assert_char_array_pairwise_distinct::<0>(&[]);
}
#[test]
fn assert_char_array_pairwise_distinct_accepts_singleton_arrays() {
// Singleton array — vacuously pairwise distinct (only one
// element, no pair). Cross-arity coverage on the `[char; 1]`
// corner of the const-N generic.
assert_char_array_pairwise_distinct(&['a']);
assert_char_array_pairwise_distinct(&[Sexp::LIST_OPEN]);
}
#[test]
fn assert_char_array_pairwise_distinct_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME seven arrays the module-
// level `const _: () = ...` witnesses cover at COMPILE time
// are pairwise distinct. A regression that removes ONE of the
// `const _` witnesses would still leave THIS runtime pin as a
// safety net; the const witness fires FIRST at `cargo check`,
// this runtime pin catches the collision at `cargo test`. The
// pair enforces the theorem at TWO stages of the toolchain.
assert_char_array_pairwise_distinct(&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS);
assert_char_array_pairwise_distinct(&Sexp::LIST_DELIMITERS);
assert_char_array_pairwise_distinct(&Sexp::COMMENT_DELIMITERS);
assert_char_array_pairwise_distinct(&QuoteForm::LEADS);
assert_char_array_pairwise_distinct(&Atom::SELF_ESCAPE_TABLE);
assert_char_array_pairwise_distinct(&Atom::ESCAPE_SOURCES);
assert_char_array_pairwise_distinct(&Atom::ESCAPE_DECODED);
}
#[test]
#[should_panic(expected = "assert_char_array_pairwise_distinct")]
fn assert_char_array_pairwise_distinct_panics_at_runtime_on_binary_collision() {
// NEGATIVE PIN — binary corner: a two-element array carrying
// the same char twice MUST panic at runtime (the const-eval
// panic surfaces normally when the function is invoked from
// a runtime context, not just a `const _` context). Pins the
// helper's OWN reject-collision arm — a regression that
// silently returns without panicking on a duplicate would
// slip through the compile-time witnesses' failure mode too.
assert_char_array_pairwise_distinct(&['x', 'x']);
}
#[test]
#[should_panic(expected = "assert_char_array_pairwise_distinct")]
fn assert_char_array_pairwise_distinct_panics_at_runtime_on_non_adjacent_collision() {
// NEGATIVE PIN — non-adjacent corner: the collision fires on
// ANY (i, j) pair with i < j, not just the adjacent (0, 1)
// corner. Pins the nested-loop shape of the helper — a
// regression that walked ONLY the adjacent pairs (i.e., swept
// `while i + 1 < N { if arr[i] == arr[i+1] { panic } … }`)
// would silently accept `['a', 'b', 'a']` (non-adjacent
// collision at positions 0 and 2), missing the contract.
assert_char_array_pairwise_distinct(&['a', 'b', 'a']);
}
#[test]
#[should_panic(expected = "assert_char_array_pairwise_distinct")]
fn assert_char_array_pairwise_distinct_panics_at_runtime_on_terminal_collision() {
// NEGATIVE PIN — terminal corner: the collision at the LAST
// pair (positions N-2 and N-1) MUST also fire. Pins the outer
// `while i < N` bound — a regression that walked `while i <
// N - 1` (dropping the last row) would silently accept a
// collision at the tail.
assert_char_array_pairwise_distinct(&['a', 'b', 'c', 'd', 'd']);
}
#[test]
fn assert_char_array_pairwise_distinct_panic_message_names_the_helper() {
// PANIC-MESSAGE PROVENANCE PIN: the panic message MUST begin
// with the helper's own name so downstream diagnostics
// (`cargo check` const-eval error output, test-suite failure
// reports) route the drift back to the helper by string
// search — the family-wide contract's failure mode surfaces
// as an identifiable panic-message prefix rather than as an
// opaque const-eval error. Sibling posture to the runtime
// pairwise-distinctness tests that name the ARRAY in their
// failure message; this pin names the HELPER.
let outcome = std::panic::catch_unwind(|| {
assert_char_array_pairwise_distinct(&['x', 'x']);
});
let payload = outcome.expect_err(
"assert_char_array_pairwise_distinct must panic on a \
duplicate — the reject-collision arm is the point of the \
helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_pairwise_distinct panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_char_array_pairwise_distinct"),
"assert_char_array_pairwise_distinct panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
}
// ── assert_char_array_all_ascii — the per-entry ASCII-SCALAR-RANGE
// gate row-dual peer of `assert_str_array_all_ascii` on the
// (element-type ∈ {char, `&'static str`}) axis of the (per-entry ×
// contract-shape) matrix at the (per-entry, ASCII) column. Contract-
// orthogonal sibling of `assert_char_array_pairwise_distinct` on
// the (INJECTIVITY, ASCII) axis of the SAME (`char`) row. ──
#[test]
fn assert_char_array_all_ascii_accepts_the_empty_array() {
// Empty array — vacuously all-ASCII (no entry to fail the
// scalar-range gate). The compile-time `const _: () =
// assert_char_array_all_ascii(&EMPTY);` would land on this
// arm, so the runtime call MUST return normally. Sibling
// posture to `assert_str_array_all_ascii_accepts_the_empty_
// array` on the (`&'static str`) row-dual ASCII helper — the
// two share the trivial-arity arm across the element-type
// column.
assert_char_array_all_ascii::<0>(&[]);
}
#[test]
fn assert_char_array_all_ascii_accepts_ascii_singleton_arrays() {
// Singleton array carrying an all-ASCII entry — the sole
// entry clears the scalar-range gate. Cross-arity coverage
// on the `[char; 1]` corner of the const-N generic. Includes
// a substrate-scalar entry (`Sexp::LIST_OPEN`) to cover the
// named-constant projection alongside the char literal
// projection.
assert_char_array_all_ascii(&['a']);
assert_char_array_all_ascii(&[Sexp::LIST_OPEN]);
}
#[test]
fn assert_char_array_all_ascii_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME seven arrays the module-
// level `const _: () = ...` witnesses cover at COMPILE time
// are all-ASCII. Sibling posture to the runtime
// `_pairwise_distinct_accepts_every_family_wide_substrate_
// array` cross-check — the two together pin BOTH the SET-
// LEVEL INJECTIVITY axis AND the PER-ENTRY ASCII-SCALAR-RANGE
// axis on the SAME seven arrays, at TWO stages of the
// toolchain (compile-time `const _` line + this runtime
// safety-net). Row-dual posture to
// `assert_str_array_all_ascii_accepts_every_family_wide_
// substrate_array` on the (`&'static str`) row — the two
// together sweep the ASCII contract across every reader-
// boundary AND every outer-algebra vocabulary the substrate
// ships.
assert_char_array_all_ascii(&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS);
assert_char_array_all_ascii(&Sexp::LIST_DELIMITERS);
assert_char_array_all_ascii(&Sexp::COMMENT_DELIMITERS);
assert_char_array_all_ascii(&QuoteForm::LEADS);
assert_char_array_all_ascii(&Atom::SELF_ESCAPE_TABLE);
assert_char_array_all_ascii(&Atom::ESCAPE_SOURCES);
assert_char_array_all_ascii(&Atom::ESCAPE_DECODED);
}
#[test]
fn assert_char_array_all_ascii_accepts_the_ascii_boundary_scalar() {
// Boundary-inclusive pin on the ASCII scalar range's upper
// edge — U+007F (DEL, the last ASCII scalar) MUST be
// accepted. Guards against an off-by-one regression that
// walked `arr[i] as u32 >= 0x7F` and spuriously rejected the
// sole `'\u{7F}'` character. Together with the negative pins
// below (which fire on U+0080 — the first non-ASCII scalar),
// the two pin the scalar-range boundary at both edges.
assert_char_array_all_ascii(&['\u{7F}']);
}
#[test]
#[should_panic(expected = "assert_char_array_all_ascii")]
fn assert_char_array_all_ascii_panics_at_runtime_on_singleton_non_ascii() {
// NEGATIVE PIN — singleton corner: a one-element array
// carrying a non-ASCII scalar MUST panic. Pins the helper's
// own reject-non-ascii arm on the smallest possible array
// shape. The scalar `'é'` (U+00E9) has `as u32 == 0xE9 >
// 0x7F` and fires the range gate.
assert_char_array_all_ascii(&['é']);
}
#[test]
#[should_panic(expected = "assert_char_array_all_ascii")]
fn assert_char_array_all_ascii_panics_at_runtime_on_head_non_ascii() {
// NEGATIVE PIN — head corner: the non-ASCII scalar at
// position 0 MUST fire even when subsequent entries are
// ASCII. Pins the sweep's inclusive-start behavior — a
// regression that walked `while i < N { … i += 1 }` from
// an off-by-one start (`i = 1`) would silently accept a
// leading non-ASCII entry.
assert_char_array_all_ascii(&['é', 'a', 'b']);
}
#[test]
#[should_panic(expected = "assert_char_array_all_ascii")]
fn assert_char_array_all_ascii_panics_at_runtime_on_interior_non_ascii() {
// NEGATIVE PIN — interior corner: the non-ASCII scalar at a
// strictly-interior position MUST fire. Pins the sweep's
// non-early-exit behavior at the head-arm — a regression
// that returned `Ok` on the first ASCII entry (bailing out
// of the sweep prematurely) would silently accept an
// interior non-ASCII entry.
assert_char_array_all_ascii(&['a', 'é', 'b']);
}
#[test]
#[should_panic(expected = "assert_char_array_all_ascii")]
fn assert_char_array_all_ascii_panics_at_runtime_on_tail_non_ascii() {
// NEGATIVE PIN — tail corner: the non-ASCII scalar at
// position `N - 1` MUST fire. Pins the outer `while i < N`
// upper bound — a regression that walked `while i < N - 1`
// (dropping the last slot) would silently accept a trailing
// non-ASCII entry.
assert_char_array_all_ascii(&['a', 'b', 'c', 'é']);
}
#[test]
#[should_panic(expected = "assert_char_array_all_ascii")]
fn assert_char_array_all_ascii_panics_on_the_first_non_ascii_scalar() {
// NEGATIVE PIN — first-non-ASCII-scalar boundary: U+0080
// (the smallest non-ASCII scalar) MUST fire. Guards against
// an off-by-one regression that walked `arr[i] as u32 >
// 0x80` (dropping U+0080 from the reject set). Together
// with `_accepts_the_ascii_boundary_scalar` (which pins
// U+007F acceptance), the two pin the scalar-range boundary
// at both edges. Row-dual posture to `assert_str_array_all_
// ascii_panics_on_the_first_non_ascii_byte` — the two
// together pin the boundary at both element-type projections.
assert_char_array_all_ascii(&['\u{80}']);
}
#[test]
fn assert_char_array_all_ascii_rejects_the_all_non_ascii_array() {
// POSITIVE-ORTHOGONAL PIN — the ALL-non-ASCII corner: an
// array whose every entry is a non-ASCII scalar fires the
// helper on the FIRST entry (the head-arm). Confirms the
// helper does not silently accept an array whose every
// entry ships non-ASCII scalars. Row-dual posture to
// `assert_str_array_all_ascii_rejects_the_all_non_ascii_
// array` on the (`&'static str`) row — the two together pin
// the all-reject corner across the element-type column.
let outcome = std::panic::catch_unwind(|| {
assert_char_array_all_ascii(&['é', 'ü']);
});
outcome.expect_err(
"assert_char_array_all_ascii must panic on an array \
whose every entry is a non-ASCII scalar — the head-arm \
fires on the first non-ASCII scalar at position 0",
);
}
#[test]
fn assert_char_array_all_ascii_panic_message_names_the_helper_and_axis() {
// PANIC-MESSAGE PROVENANCE PIN: the panic message MUST
// begin with the helper's own name AND name the failed axis
// as `"CHAR-NON-ASCII-SCALAR"` (chosen DISTINCT from every
// sibling helper's axis vocabulary: `"duplicate"` on the
// pairwise-distinct sibling; `"CHAR-SUBSET-VIOLATION"` on
// the within-finite-set sibling; `"CHAR-DISJOINTNESS-
// VIOLATION"` on the arrays-disjoint sibling; `"STR-NON-
// ASCII-ENTRY"` on the (`&'static str`) row-dual ASCII
// sibling) so a diagnostic that names the failed axis routes
// UNAMBIGUOUSLY to THIS specific (`char`)-row ASCII helper.
// The `"CHAR-"` prefix disambiguates from the (`&'static
// str`) row-dual ASCII sibling; the shared `"-NON-ASCII-"`
// infix lets callers grep any row's ASCII sibling by `"NON-
// ASCII"` alone.
let outcome = std::panic::catch_unwind(|| {
assert_char_array_all_ascii(&['é']);
});
let payload = outcome.expect_err(
"assert_char_array_all_ascii must panic on a non-ASCII \
scalar — the reject-non-ascii arm is the point of the \
helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_all_ascii panic payload must be \
a static &str or String",
);
assert!(
msg.contains("assert_char_array_all_ascii"),
"assert_char_array_all_ascii panic message {msg:?} must \
name the helper for provenance-preserving failure \
diagnostics",
);
assert!(
msg.contains("CHAR-NON-ASCII-SCALAR"),
"assert_char_array_all_ascii panic message {msg:?} must \
name the failed axis as `CHAR-NON-ASCII-SCALAR` \
DISTINCT from every sibling helper's axis vocabulary",
);
assert!(
!msg.contains("STR-NON-ASCII-ENTRY"),
"assert_char_array_all_ascii panic message {msg:?} must \
NOT name the (`&'static str`) row-dual sibling's axis \
— the two row-dual ASCII helpers must keep their axis-\
provenance strings lexically distinct on the element-\
type column",
);
assert!(
!msg.contains("CHAR-SUBSET-VIOLATION"),
"assert_char_array_all_ascii panic message {msg:?} must \
NOT name the SUBSET-embedding sibling's axis — the \
per-entry ASCII helper and the SUBSET-embedding helper \
must keep their axis-provenance strings lexically \
distinct on the contract-shape column",
);
}
// ── `assert_char_array_within_char_finite_set` — the char-element
// SUBSET-EMBEDDING verifier that binds `arr ⊆ set` at compile time
// on the reader-boundary `char` vocabulary, peer to the (u8) row's
// `assert_u8_array_within_u8_finite_set` on the (element-type ×
// contract-shape) matrix. The runtime test surface pins each of
// the helper's arms (accept-empty, accept-singleton-in-set,
// accept-arr-equals-set, accept-each-family-wide-substrate-subset,
// accept-array-duplicates-in-set, reject-single-out-of-set-entry,
// reject-terminal-out-of-set-entry, panic-message-provenance on
// the CHAR-SUBSET-VIOLATION axis, negative pin on the DELEGATED
// SET-side well-formedness arm) so a regression that silently
// weakened the helper on ANY arm is caught by the helper's OWN
// test surface rather than only surfacing as a false-positive on
// some future subset-embedded `[char; N]` array's compound pin.
#[test]
fn assert_char_array_within_char_finite_set_accepts_the_empty_array_within_any_set() {
// Empty array `arr = []` at the `[char; 0]` corner — vacuously
// a subset of every set (no `i` position exists to test).
// Cross-arity coverage on the trivial ARRAY corner of the
// const-N generic across three witness-set widths (empty,
// singleton, multi-element) to pin the helper's OUTER-sweep
// arm across the whole (`N == 0` × `M`) axis. Turbofish
// binding required because there's no other cue for the const
// parameters on the empty array literal. Sibling posture to
// `assert_u8_array_within_u8_finite_set_accepts_the_empty_array_within_any_set`
// on the (u8) row's SUBSET-EMBEDDING helper — the two share
// the trivial-arity arm across the element-type column.
assert_char_array_within_char_finite_set::<0, 0>(&[], &[]);
assert_char_array_within_char_finite_set::<0, 1>(&[], &['x']);
assert_char_array_within_char_finite_set::<0, 3>(&[], &['a', 'b', 'c']);
}
#[test]
fn assert_char_array_within_char_finite_set_accepts_singleton_array_when_char_in_set() {
// Singleton array `arr = [K]` at the `[char; 1]` corner MUST
// pass when `K ∈ set`. Cross-position coverage: the char can
// sit at the FIRST, MIDDLE, or LAST position of the `set` —
// pins the INNER `while j < M` sweep terminates at the first-
// match position rather than always at position `0` OR always
// at position `M - 1`. A regression that narrowed the inner
// sweep to `j == 0` would silently reject singleton arrays
// hitting non-first set positions.
assert_char_array_within_char_finite_set::<1, 3>(&['a'], &['a', 'b', 'c']);
assert_char_array_within_char_finite_set::<1, 3>(&['b'], &['a', 'b', 'c']);
assert_char_array_within_char_finite_set::<1, 3>(&['c'], &['a', 'b', 'c']);
}
#[test]
fn assert_char_array_within_char_finite_set_accepts_arr_equals_set() {
// Boundary corner where `arr` and `set` cover byte-for-byte
// identical distinct-value sets — the SUBSET relation
// degenerates to EQUALITY. Pins that the helper does NOT
// gratuitously require the SUBSET to be PROPER (strict):
// equal-multisets pass the SUBSET check. Sibling posture to
// `assert_u8_array_within_u8_finite_set_accepts_arr_equals_set`
// on the (u8) row's SUBSET-EMBEDDING helper — the two share
// the EQUAL-SETS corner across the element-type column.
assert_char_array_within_char_finite_set(&['a', 'b'], &['a', 'b']);
assert_char_array_within_char_finite_set(&[Sexp::LIST_OPEN], &[Sexp::LIST_OPEN]);
}
#[test]
fn assert_char_array_within_char_finite_set_accepts_each_family_wide_substrate_subset() {
// Runtime cross-check that the THREE (subset, superset) pairs
// the substrate's module-level `const _` witnesses pin at
// COMPILE time are PROPER SUBSET embeddings at runtime too.
// The pairs enforce the theorem at TWO stages of the
// toolchain: the const witnesses fire FIRST at `cargo check`
// (through the three module-level `const _: () =
// assert_char_array_within_char_finite_set::<N, M>(...)`
// lines), this runtime pin catches the drift at `cargo test`
// as a safety net. Sibling posture to
// `assert_char_array_pairwise_distinct_accepts_every_family_wide_substrate_array`
// which sweeps the seven family-wide `[char; N]` arrays at
// the INJECTIVITY axis; this pin sweeps the three (subset,
// superset) PAIRS at the SUBSET-EMBEDDING axis.
assert_char_array_within_char_finite_set::<2, 7>(
&Sexp::LIST_DELIMITERS,
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
);
assert_char_array_within_char_finite_set::<3, 7>(
&QuoteForm::LEADS,
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
);
assert_char_array_within_char_finite_set::<2, 5>(
&Atom::SELF_ESCAPE_TABLE,
&Atom::ESCAPE_SOURCES,
);
}
#[test]
fn assert_char_array_within_char_finite_set_accepts_repeated_array_entries_in_set() {
// Peer corner to a (future-lift) `_covers_char_finite_set`:
// this helper permits duplicates in `arr` because SUBSET-
// membership is a DISTINCT-value predicate — `['a', 'a', 'b']`
// is a subset of `{'a', 'b', 'c'}` even though the array is
// not pairwise-distinct. Pins that the helper does NOT
// gratuitously require INJECTIVITY on `arr` (the injectivity
// axis is a DIFFERENT compile-time contract bound by
// `assert_char_array_pairwise_distinct`; combining both binds
// BOTH axes). Sibling posture to
// `assert_u8_array_within_u8_finite_set_accepts_repeated_array_entries_in_set`
// on the (u8) row's SUBSET-EMBEDDING peer.
assert_char_array_within_char_finite_set(&['a', 'a', 'b'], &['a', 'b', 'c']);
}
#[test]
#[should_panic(expected = "CHAR-SUBSET-VIOLATION")]
fn assert_char_array_within_char_finite_set_panics_at_runtime_on_out_of_set_entry() {
// NEGATIVE PIN — CHAR-SUBSET-VIOLATION corner: an array
// carrying a single entry NOT in the target set MUST panic at
// runtime with the CHAR-SUBSET-VIOLATION-named message. Pins
// the helper's OWN reject arm — a regression that silently
// returned without panicking on an out-of-set entry would
// slip through the compile-time witnesses' failure mode too.
// The offending char `'z'` is intentionally chosen OUTSIDE
// the target set to pin the OUT-OF-SET drift mode.
assert_char_array_within_char_finite_set(&['a', 'z'], &['a', 'b', 'c']);
}
#[test]
#[should_panic(expected = "CHAR-SUBSET-VIOLATION")]
fn assert_char_array_within_char_finite_set_panics_at_runtime_on_terminal_out_of_set_entry() {
// NEGATIVE PIN — terminal-position drift: an out-of-set entry
// at the LAST array position MUST panic — pins that the outer
// `while i < N` loop reaches `i = N - 1` (else the terminal
// drift would slip through). A regression that narrowed the
// outer sweep to `while i < N - 1` (off-by-one on the OUTER
// bound) would silently accept this array. Sibling posture to
// `assert_u8_array_within_u8_finite_set_panics_at_runtime_on_terminal_out_of_set_entry`
// on the (u8) row's terminal-position pin — both bind the
// outer-sweep terminal bound at the ONE array-side outer loop
// the helper carries.
assert_char_array_within_char_finite_set(&['a', 'b', 'c', 'z'], &['a', 'b', 'c']);
}
#[test]
fn assert_char_array_within_char_finite_set_panic_message_names_the_helper_and_char_subset_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-SUBSET-VIOLATION arm:
// the panic message MUST begin with the helper's own name AND
// identify the failed AXIS as "CHAR-SUBSET-VIOLATION" so
// downstream diagnostics route the drift back to (a) the
// helper by string search on
// `"assert_char_array_within_char_finite_set"` and (b) the
// axis by string search on `"CHAR-SUBSET-VIOLATION"`. Sibling
// posture to
// `assert_u8_array_within_u8_finite_set_panic_message_names_the_helper_and_subset_violation_axis`
// on the (u8) row's provenance pin — the two pins together
// bind the (helper, failed-axis) provenance pair at ONE test
// per SUBSET helper on the (element-type) 2×1 face. The axis-
// provenance string `"CHAR-SUBSET-VIOLATION"` is chosen
// DISTINCT from EVERY sibling helper's axis vocabulary
// (`"duplicate"` on the ARRAY-side pairwise-distinct sibling;
// `"SUBSET-VIOLATION"` on the (u8) finite-set SUBSET-only
// sibling; `"RANGE-SUBSET-VIOLATION"` on the (u8) range
// SUBSET-only sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"`
// on the (u8) covers-finite-set sibling; `"OUT-OF-RANGE"` /
// `"MISSING"` on the (u8) covers-inclusive-range sibling;
// `"ARITY-MISMATCH"` on both (u8) `_permutes_*` compound
// helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on the (u8) SET-side
// well-formedness sibling) so a diagnostic that names the
// failed axis routes UNAMBIGUOUSLY to (a) this specific char
// SUBSET-embedding helper, (b) the `arr` argument as the
// drift site rather than the `set` argument specifying the
// target superset.
let outcome = std::panic::catch_unwind(|| {
assert_char_array_within_char_finite_set(&['a', 'z'], &['a', 'b', 'c']);
});
let payload = outcome.expect_err(
"assert_char_array_within_char_finite_set must panic on \
an out-of-set entry — the reject-out-of-set arm is the \
sole CHAR-SUBSET-VIOLATION failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_within_char_finite_set panic \
payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_array_within_char_finite_set"),
"assert_char_array_within_char_finite_set panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("CHAR-SUBSET-VIOLATION"),
"assert_char_array_within_char_finite_set panic message \
{msg:?} must name the failed AXIS (\"CHAR-SUBSET-\
VIOLATION\") for axis-provenance-preserving failure \
diagnostics",
);
}
#[test]
#[should_panic(expected = "assert_char_array_pairwise_distinct")]
fn assert_char_array_within_char_finite_set_panics_on_malformed_target_set_spec() {
// NEGATIVE PIN — DELEGATED SET-side well-formedness: a
// malformed target-set spec `['a', 'a', 'b']` fed into the
// ARRAY-side within helper MUST panic on the DELEGATED
// pairwise-distinct arm BEFORE the CHAR-SUBSET-VIOLATION arm
// fires. Pins the delegation chain: a regression that dropped
// the `assert_char_array_pairwise_distinct(set)` call at the
// top of `assert_char_array_within_char_finite_set` would
// silently accept a malformed set and produce a false-positive
// verdict on any `arr` embedded in the DISTINCT-value subset.
// The panic message here surfaces from the SIBLING helper
// (containing the ARRAY-side helper's `"assert_char_array_
// pairwise_distinct"` panic-name prefix rather than a bespoke
// `"SET-NOT-PAIRWISE-DISTINCT"` axis string) because the char
// row does NOT yet carry a separate `assert_char_finite_set_
// pairwise_distinct` alias — the delegation reuses the
// ARRAY-side helper directly per the design choice documented
// on the SET-side-well-formedness section of the helper's
// docstring. Sibling posture to
// `assert_u8_array_within_u8_finite_set_panics_on_malformed_target_set_spec`
// on the (u8) row's delegated-SET-well-formedness pin — the
// two pins together bind the delegation chain at ONE test per
// element-type row.
assert_char_array_within_char_finite_set::<2, 3>(&['a', 'b'], &['a', 'b', 'b']);
}
// ── `assert_char_arrays_disjoint` — the CHAR-DISJOINTNESS-VIOLATION
// verifier that binds `a ∩ b = ∅` at compile time on the reader-
// boundary `char` vocabulary, peer to
// `assert_char_array_within_char_finite_set` on the (char) row of
// the (subset, disjointness) 2-corner face of the (contract-shape)
// axis. The runtime test surface pins each of the helper's arms
// (accept-both-empty, accept-either-empty, accept-disjoint-
// singletons, accept-each-family-wide-substrate-pair, accept-arg-
// order-symmetry, reject-single-collision, reject-terminal-a-
// collision, reject-terminal-b-collision, panic-message-provenance
// on the CHAR-DISJOINTNESS-VIOLATION axis) so a regression that
// silently weakened the helper on ANY arm is caught by the
// helper's OWN test surface rather than only surfacing as a false-
// positive on some future disjoint `[char; N] × [char; M]` pair's
// compound pin.
#[test]
fn assert_char_arrays_disjoint_accepts_both_empty_arrays() {
// Both arrays empty at the `[char; 0] × [char; 0]` corner —
// vacuously disjoint (no `(i, j)` pair exists to test). The
// compile-time `const _: () = assert_char_arrays_disjoint(&[],
// &[]);` would land on this arm, so the runtime call MUST
// return normally. Turbofish binding required because there's
// no other cue for the const parameters on the empty array
// literals. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_the_empty_array_within_any_set`
// on the peer SUBSET-embedding helper — the two share the
// trivial-arity arm across the (subset, disjointness) 2-corner
// face on the (char) row.
assert_char_arrays_disjoint::<0, 0>(&[], &[]);
}
#[test]
fn assert_char_arrays_disjoint_accepts_either_side_empty() {
// Either side empty at the `[char; 0] × [char; M]` OR
// `[char; N] × [char; 0]` corners — vacuously disjoint (the
// OUTER `while i < N` OR the INNER `while j < M` sweep is a
// no-op). Pins BOTH SIDES of the (a-empty, b-empty) 2-corner
// sub-face on the trivial-arity axis so a regression that
// narrowed the sweep to only-a-non-empty OR only-b-non-empty
// fails HERE at the empty-side corner rather than at a distant
// false-positive.
assert_char_arrays_disjoint::<0, 3>(&[], &['a', 'b', 'c']);
assert_char_arrays_disjoint::<3, 0>(&['a', 'b', 'c'], &[]);
}
#[test]
fn assert_char_arrays_disjoint_accepts_disjoint_singletons() {
// Singleton `a = [K]` and singleton `b = [L]` with `K != L` at
// the `[char; 1] × [char; 1]` corner — the minimal non-empty
// disjointness relation. Pins the INNER `if a[i] != b[j]` gate
// returns without panicking on a single distinct-pair check.
// A regression that flipped the equality direction (`==` vs
// `!=`) would silently reject every disjoint singleton pair.
assert_char_arrays_disjoint(&['a'], &['b']);
}
#[test]
fn assert_char_arrays_disjoint_accepts_each_family_wide_substrate_pair() {
// Runtime cross-check that the FIVE (a, b) `[char; N] ×
// [char; M]` pairs the substrate's module-level `const _`
// witnesses pin at COMPILE time are proper DISJOINTNESS
// embeddings at runtime too. The pairs enforce the theorem at
// TWO stages of the toolchain: the const witnesses fire FIRST
// at `cargo check` (through the five module-level `const _:
// () = assert_char_arrays_disjoint::<N, M>(...)` lines), this
// runtime pin catches the drift at `cargo test` as a safety
// net. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_each_family_wide_substrate_subset`
// which sweeps the three (subset, superset) PAIRS at the
// SUBSET-EMBEDDING axis; this pin sweeps the five (a, b)
// PAIRS at the DISJOINTNESS axis on the SAME (char) row.
assert_char_arrays_disjoint::<2, 2>(&Sexp::LIST_DELIMITERS, &Sexp::COMMENT_DELIMITERS);
assert_char_arrays_disjoint::<2, 3>(&Sexp::LIST_DELIMITERS, &QuoteForm::LEADS);
assert_char_arrays_disjoint::<2, 3>(&Sexp::COMMENT_DELIMITERS, &QuoteForm::LEADS);
assert_char_arrays_disjoint::<2, 2>(&Sexp::LIST_DELIMITERS, &Atom::SELF_ESCAPE_TABLE);
assert_char_arrays_disjoint::<3, 2>(&QuoteForm::LEADS, &Atom::SELF_ESCAPE_TABLE);
}
#[test]
fn assert_char_arrays_disjoint_is_symmetric_in_argument_order() {
// SYMMETRY PIN: swapping the two arguments produces the SAME
// verdict. Pins that the disjointness relation is truly
// symmetric across the two array arguments (the helper's
// nested-sweep implementation does NOT gratuitously depend on
// argument order). A regression that narrowed the sweep to
// `for i in a { if !b.contains(a[i]) }` (subset-shape, not
// disjointness-shape) would fail the swap on one direction
// only. Runs each substrate pair BOTH ways.
assert_char_arrays_disjoint(&Sexp::COMMENT_DELIMITERS, &Sexp::LIST_DELIMITERS);
assert_char_arrays_disjoint(&QuoteForm::LEADS, &Sexp::LIST_DELIMITERS);
assert_char_arrays_disjoint(&Atom::SELF_ESCAPE_TABLE, &QuoteForm::LEADS);
}
#[test]
#[should_panic(expected = "CHAR-DISJOINTNESS-VIOLATION")]
fn assert_char_arrays_disjoint_panics_at_runtime_on_collision() {
// NEGATIVE PIN — CHAR-DISJOINTNESS-VIOLATION corner: two arrays
// sharing a single entry MUST panic at runtime with the
// CHAR-DISJOINTNESS-VIOLATION-named message. Pins the helper's
// OWN reject arm — a regression that silently returned
// without panicking on a cross-array collision would slip
// through the compile-time witnesses' failure mode too. The
// shared entry `'a'` is intentionally placed at the FIRST
// position of BOTH arrays to pin the initial-position drift
// mode.
assert_char_arrays_disjoint(&['a', 'b'], &['a', 'c']);
}
#[test]
#[should_panic(expected = "CHAR-DISJOINTNESS-VIOLATION")]
fn assert_char_arrays_disjoint_panics_at_runtime_on_terminal_a_collision() {
// NEGATIVE PIN — terminal-position drift on the OUTER `a` side:
// a shared entry at the LAST position of `a` MUST panic — pins
// that the outer `while i < N` loop reaches `i = N - 1` (else
// the terminal drift on `a` would slip through). A regression
// that narrowed the outer sweep to `while i < N - 1` (off-by-
// one on the OUTER bound) would silently accept this pair.
assert_char_arrays_disjoint(&['x', 'y', 'z'], &['z']);
}
#[test]
#[should_panic(expected = "CHAR-DISJOINTNESS-VIOLATION")]
fn assert_char_arrays_disjoint_panics_at_runtime_on_terminal_b_collision() {
// NEGATIVE PIN — terminal-position drift on the INNER `b` side:
// a shared entry at the LAST position of `b` MUST panic — pins
// that the inner `while j < M` loop reaches `j = M - 1` (else
// the terminal drift on `b` would slip through). A regression
// that narrowed the inner sweep to `while j < M - 1` (off-by-
// one on the INNER bound) would silently accept this pair.
// Sibling posture to the outer-terminal pin above — the two
// pins together bind the terminal bounds on BOTH loops.
assert_char_arrays_disjoint(&['x'], &['a', 'b', 'x']);
}
#[test]
fn assert_char_arrays_disjoint_panic_message_names_the_helper_and_char_disjointness_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-DISJOINTNESS-VIOLATION
// arm: the panic message MUST begin with the helper's own name
// AND identify the failed AXIS as "CHAR-DISJOINTNESS-VIOLATION"
// so downstream diagnostics route the drift back to (a) the
// helper by string search on `"assert_char_arrays_disjoint"`
// and (b) the axis by string search on `"CHAR-DISJOINTNESS-
// VIOLATION"`. Sibling posture to
// `assert_char_array_within_char_finite_set_panic_message_names_the_helper_and_char_subset_violation_axis`
// on the peer SUBSET-embedding helper's provenance pin — the
// two pins together bind the (helper, failed-axis) provenance
// pair at ONE test per corner of the (subset, disjointness)
// 2-corner face on the (char) row. The axis-provenance string
// `"CHAR-DISJOINTNESS-VIOLATION"` is chosen DISTINCT from EVERY
// sibling helper's axis vocabulary (`"duplicate"` on the
// ARRAY-side pairwise-distinct sibling; `"CHAR-SUBSET-
// VIOLATION"` on the (char) SUBSET-embedding sibling;
// `"SUBSET-VIOLATION"` on the (u8) finite-set SUBSET-only
// sibling; `"RANGE-SUBSET-VIOLATION"` on the (u8) range
// SUBSET-only sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"`
// on the (u8) covers-finite-set sibling; `"OUT-OF-RANGE"` /
// `"MISSING"` on the (u8) covers-inclusive-range sibling;
// `"ARITY-MISMATCH"` on both (u8) `_permutes_*` compound
// helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on the (u8) SET-side
// well-formedness sibling) so a diagnostic that names the
// failed axis routes UNAMBIGUOUSLY to (a) this specific char
// DISJOINTNESS helper.
let outcome = std::panic::catch_unwind(|| {
assert_char_arrays_disjoint(&['a', 'b'], &['a', 'c']);
});
let payload = outcome.expect_err(
"assert_char_arrays_disjoint must panic on a cross-array \
collision — the reject-collision arm is the sole CHAR-\
DISJOINTNESS-VIOLATION failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_arrays_disjoint panic payload must be a \
static &str or String",
);
assert!(
msg.contains("assert_char_arrays_disjoint"),
"assert_char_arrays_disjoint panic message {msg:?} must \
name the helper for provenance-preserving failure \
diagnostics",
);
assert!(
msg.contains("CHAR-DISJOINTNESS-VIOLATION"),
"assert_char_arrays_disjoint panic message {msg:?} must \
name the failed AXIS (\"CHAR-DISJOINTNESS-VIOLATION\") \
for axis-provenance-preserving failure diagnostics",
);
}
// ── `assert_char_array_slice_equals_char_array` — the CHAR-SLICE-
// EQUALS-ARRAY-VIOLATION verifier that binds the sub-slice
// `full[START..START + M) == sub[..]` positionwise-composition
// contract at compile time on the substrate's reader-boundary
// `[char; N]` scalar-composed vocabulary, row-dual peer to
// `assert_u8_array_slice_equals_u8_array` on the (u8) row of the
// (element-type) axis of the SAME (SUB-SLICE ARRAY-image) column
// of the (element-type × contract-shape) matrix. The runtime test
// surface pins each of the helper's arms (accept-canonical-
// middle-slice, accept-empty-sub-array-at-three-start-positions,
// accept-full-array-degenerate-at-three-arities, accept-each-of-
// the-eight-family-wide-substrate-arrays, reject-positionwise-
// drift, reject-start-out-of-bounds, reject-slice-length-out-of-
// bounds, panic-message-provenance on the CHAR-SLICE-EQUALS-
// ARRAY-VIOLATION axis) so a regression that silently weakened
// the helper on ANY arm (e.g. flipping `!=` to `==` on the char
// comparison, dropping the `START` offset from the `full[START +
// i]` read, returning early past ANY bounds gate, or dropping the
// `as u32` char-to-scalar bridge that lets the const-eval sweep
// proceed byte-for-byte) is caught by the helper's OWN test
// surface rather than only surfacing as a false-positive on some
// future `[char; N]`-typed reader-boundary array's per-position
// ORDER pin.
#[test]
fn assert_char_array_slice_equals_char_array_accepts_a_canonical_middle_slice() {
// Canonical sub-slice `full[START..START + M) == sub[..]`
// inside a longer array `full` whose ENDPOINTS carry
// DIFFERENT chars than the peer sub-array. Pins the outer
// `while i < M` sweep reads `full[START + i]` at the OFFSET
// position (not `full[i]`) — a regression that dropped the
// `START` offset would compare `full[0..M)` against `sub[..]`
// and pass on `full[0]='z' != sub[0]='b'` silently or panic
// on the wrong axis. `START = 1` pins the sweep skips
// position `[0..START)` and reads only `[1..1+3) = [1..4)`.
assert_char_array_slice_equals_char_array::<7, 3, 1>(
&['z', 'b', 'c', 'd', 'z', 'z', 'z'],
&['b', 'c', 'd'],
);
}
#[test]
fn assert_char_array_slice_equals_char_array_accepts_the_empty_sub_array() {
// LEGAL degenerate: `M == 0` collapses the sub-array into an
// empty listing `[]`. The sweep never enters the loop body
// and the helper accepts. Cross-position coverage pins the
// empty-sub-array acceptance at THREE distinct `START`
// positions (`START == 0` at the left endpoint, `START == 3`
// in the interior, `START == N` at the right endpoint — the
// latter is the corner `START == N` combined with `M == 0`
// that the START-OUT-OF-BOUNDS gate's inclusive upper bound
// must accept). A regression that hard-coded `START < N` OR
// panicked on the `M == 0` corner is caught on ALL THREE
// arms.
assert_char_array_slice_equals_char_array::<5, 0, 0>(&['x', 'x', 'x', 'x', 'x'], &[]);
assert_char_array_slice_equals_char_array::<5, 0, 3>(&['x', 'x', 'x', 'x', 'x'], &[]);
assert_char_array_slice_equals_char_array::<5, 0, 5>(&['x', 'x', 'x', 'x', 'x'], &[]);
}
#[test]
fn assert_char_array_slice_equals_char_array_accepts_the_full_array_degenerate() {
// Full-array-covering slice `M == N, START == 0` collapses
// to the ALL-positions-equal-peer-array shape `full == sub`
// pointwise. Pins that the sweep proceeds through EVERY
// position of the outer array when `START = 0` and `M = N`.
// Cross-arity coverage on `N ∈ {1, 3, 7}` pins the sweep's
// terminal-position visit across the range of char arities
// the substrate's reader-boundary arrays span (`N = 1` for
// `UnquoteForm::LEADS`, `N = 2` for the delimiter/escape
// pairs, `N = 3` for `QuoteForm::LEADS`, `N = 5` for
// `ESCAPE_SOURCES` / `ESCAPE_DECODED`, `N = 7` for
// `NON_WHITESPACE_BARE_ATOM_TERMINATORS`).
assert_char_array_slice_equals_char_array::<1, 1, 0>(&[','], &[',']);
assert_char_array_slice_equals_char_array::<3, 3, 0>(&['\'', '`', ','], &['\'', '`', ',']);
assert_char_array_slice_equals_char_array::<7, 7, 0>(
&['(', ')', '\'', '`', ',', '"', ';'],
&['(', ')', '\'', '`', ',', '"', ';'],
);
}
#[test]
fn assert_char_array_slice_equals_char_array_accepts_each_family_wide_substrate_array() {
// Runtime cross-check that the EIGHT reader-boundary
// `[char; N]` scalar-composed substrate arrays each byte-
// equal their canonical literal-char listing pointwise at the
// FULL-ARRAY corner (`M == N`, `START == 0`). Runs the SAME
// helper the eight `const _` witnesses at line ~616 in this
// file run at rustc time — a runtime safety net enforcing
// the theorem at BOTH stages of the toolchain (const at
// `cargo check`, runtime at `cargo test`). A regression that
// renamed one of the per-role `*_LEAD` / `*_DELIMITER` /
// `*_ESCAPE_LEAD` / `*_ESCAPE_SOURCE` / `*_ESCAPE_DECODED`
// aliases (or drifted its literal char value at the
// declaration site, or reordered a slot in the outer array's
// initializer) fails HERE at the substrate callsite AND at
// the const witness above. Peer of
// `assert_u8_array_slice_equals_u8_array_accepts_sub_carving_hash_discriminators_per_position_order`
// on the (u8) row — that witness carries the FULL-ARRAY per-
// position ORDER theorem for the FOUR sub-carving
// `HASH_DISCRIMINATORS` arrays; this witness carries the same
// theorem for the EIGHT reader-boundary `char` arrays.
//
// The eight reader-boundary scalar-composed arrays appear
// here in canonical (owning-algebra, per-role-alias-count-
// ascending) order:
// * `Sexp::LIST_DELIMITERS == ['(', ')']` — the outer-`Sexp`
// list-delimiter pair.
// * `Sexp::COMMENT_DELIMITERS == [';', '\n']` — the outer-
// `Sexp` comment-boundary pair.
// * `Atom::SELF_ESCAPE_TABLE == ['"', '\\']` — the `Atom`
// escape-self pair.
// * `Atom::ESCAPE_SOURCES == ['n', 't', 'r', '"', '\\']` —
// the `Atom` escape-source column.
// * `Atom::ESCAPE_DECODED == ['\n', '\t', '\r', '"', '\\']`
// — the `Atom` escape-decoded column.
// * `Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS == ['(',
// ')', '\'', '`', ',', '"', ';']` — the outer-`Sexp`
// reader-boundary category-leading seven-char SPAN.
// * `QuoteForm::LEADS == ['\'', '`', ',']` — the quote-
// family reader-lead-char triple.
// * `UnquoteForm::LEADS == [',']` — the substitution-subset
// shared-lead singleton.
assert_char_array_slice_equals_char_array::<2, 2, 0>(&Sexp::LIST_DELIMITERS, &['(', ')']);
assert_char_array_slice_equals_char_array::<2, 2, 0>(
&Sexp::COMMENT_DELIMITERS,
&[';', '\n'],
);
assert_char_array_slice_equals_char_array::<2, 2, 0>(
&Atom::SELF_ESCAPE_TABLE,
&['"', '\\'],
);
assert_char_array_slice_equals_char_array::<5, 5, 0>(
&Atom::ESCAPE_SOURCES,
&['n', 't', 'r', '"', '\\'],
);
assert_char_array_slice_equals_char_array::<5, 5, 0>(
&Atom::ESCAPE_DECODED,
&['\n', '\t', '\r', '"', '\\'],
);
assert_char_array_slice_equals_char_array::<7, 7, 0>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&['(', ')', '\'', '`', ',', '"', ';'],
);
assert_char_array_slice_equals_char_array::<3, 3, 0>(&QuoteForm::LEADS, &['\'', '`', ',']);
assert_char_array_slice_equals_char_array::<1, 1, 0>(
&crate::error::UnquoteForm::LEADS,
&[','],
);
}
#[test]
fn assert_char_array_slice_equals_char_array_accepts_terminator_span_sub_carving_positional_composition(
) {
// Runtime cross-check that the outer-`Sexp` reader-boundary
// terminator SPAN `Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS`
// (`[char; 7]`) positionally composes as the segmented
// concatenation of its FOUR sub-carvings:
//
// NON_WHITESPACE_BARE_ATOM_TERMINATORS
// == Sexp::LIST_DELIMITERS // slots [0..2)
// ++ QuoteForm::LEADS // slots [2..5)
// ++ [Atom::STR_DELIMITER] // slot [5..6)
// ++ [Sexp::COMMENT_LEAD] // slot [6..7)
//
// Runs the SAME helper the FOUR `const _` witnesses at line
// ~915 in this file run at rustc time — a runtime safety net
// enforcing the ARRAY-LEVEL POSITIONAL-COMPOSITION theorem at
// BOTH stages of the toolchain (const at `cargo check`,
// runtime at `cargo test`). Strictly STRONGER on the
// (contract-strength) axis than the sibling
// `sexp_list_delimiters_positionally_align_with_terminator_head`
// /
// `quote_form_leads_positionally_align_with_terminator_mid`
// -shape pre-lift runtime pins that lived only in prose in the
// sub-carvings' composition-rule docstrings: those pin the
// SUBSET containment `LIST_DELIMITERS ⊆ NON_WHITESPACE_BARE_
// ATOM_TERMINATORS` (and `QuoteForm::LEADS ⊆
// NON_WHITESPACE_BARE_ATOM_TERMINATORS`) as a SET-level
// theorem, order-invariant on the sub-carving side; this pin
// binds the ARRAY-LEVEL POSITIONAL identity at the CANONICAL
// slot segments. A regression that reorders any sub-carving's
// declaration (e.g. `Sexp::LIST_DELIMITERS = [LIST_CLOSE,
// LIST_OPEN]` swapping the pair, or `QuoteForm::LEADS =
// [QUASIQUOTE_LEAD, QUOTE_LEAD, UNQUOTE_LEAD]` permuting the
// triple) preserves the SET-level SUBSET theorem AND the FULL-
// ARRAY LITERAL witness on `NON_WHITESPACE_BARE_ATOM_
// TERMINATORS` (which peer-compares against a HARDCODED
// `[char; 7]` literal via its inline listing rather than
// against the SUB-CARVING arrays) but silently misaligns every
// consumer that treats the composite's slot segment as
// positionally-interchangeable with its sub-carving. Peer
// posture to `assert_u8_array_slice_equals_u8_array_accepts_
// sexp_shape_hash_discriminators_per_position_order`-shape
// sibling on the (u8) row — that pin carries the SUB-CARVING
// per-position POSITIONAL-COMPOSITION theorem for the twelve-
// slot outer `SexpShape::HASH_DISCRIMINATORS` container; this
// pin carries the same theorem for the seven-slot outer
// `NON_WHITESPACE_BARE_ATOM_TERMINATORS` SPAN.
assert_char_array_slice_equals_char_array::<7, 2, 0>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&Sexp::LIST_DELIMITERS,
);
assert_char_array_slice_equals_char_array::<7, 3, 2>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&QuoteForm::LEADS,
);
assert_char_array_slice_equals_char_array::<7, 1, 5>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&[Atom::STR_DELIMITER],
);
assert_char_array_slice_equals_char_array::<7, 1, 6>(
&Sexp::NON_WHITESPACE_BARE_ATOM_TERMINATORS,
&[Sexp::COMMENT_LEAD],
);
}
#[test]
#[should_panic(expected = "CHAR-SLICE-EQUALS-ARRAY-VIOLATION")]
fn assert_char_array_slice_equals_char_array_panics_at_runtime_on_positionwise_drift() {
// NEGATIVE PIN — CHAR-SLICE-EQUALS-ARRAY-VIOLATION corner: a
// char at some position in `full[START..START + M)` that
// does NOT byte-equal the peer sub-array `sub` at the
// offset-matched position MUST panic at runtime with the
// axis-named message. Pins the helper's positionwise-drift
// reject arm — a regression that silently short-circuited on
// the first slice position without checking the middle or
// terminal slice positions would slip through the compile-
// time witness's failure mode too. The offending char `'!'`
// at outer position `3` (interior of the sub-slice `[1..4)`,
// offset `2` inside `sub`) pins the middle-of-slice drift
// mode.
assert_char_array_slice_equals_char_array::<5, 3, 1>(
&['z', 'b', 'c', '!', 'z'],
&['b', 'c', 'd'],
);
}
#[test]
#[should_panic(expected = "START-OUT-OF-BOUNDS")]
fn assert_char_array_slice_equals_char_array_panics_at_runtime_on_start_out_of_bounds() {
// NEGATIVE PIN — START-OUT-OF-BOUNDS gate: a caller-side
// turbofish arity slip on the `START` const-generic where
// `START > N` MUST panic at runtime with the START-OUT-OF-
// BOUNDS-named message BEFORE the peer SLICE-LENGTH-OUT-OF-
// BOUNDS gate reads `N - START` (which would `usize`-
// underflow had this gate not caught the slip first). Pins
// the gate's placement at the TOP of the helper — a
// regression that dropped the gate would either underflow
// subtraction at the peer gate OR panic deeper in
// `full[START + i]` bounds-checking with a helper-name-less
// panic message. The offending `START = 7` against `N = 5`
// pins the strict `START > N` reject arm; the LEGAL
// `START == N` empty-slice-at-right-endpoint corner is
// covered by the peer acceptance test above.
assert_char_array_slice_equals_char_array::<5, 0, 7>(&['x', 'x', 'x', 'x', 'x'], &[]);
}
#[test]
#[should_panic(expected = "SLICE-LENGTH-OUT-OF-BOUNDS")]
fn assert_char_array_slice_equals_char_array_panics_at_runtime_on_slice_length_out_of_bounds() {
// NEGATIVE PIN — SLICE-LENGTH-OUT-OF-BOUNDS gate: a peer
// sub-array arity `M` that exceeds the outer array's tail
// cardinality `N - START` MUST panic at runtime with the
// slice-length-out-of-bounds-named message. Peer gate to the
// START-OUT-OF-BOUNDS arm above — the two gates jointly
// enforce `START ≤ N` and `M ≤ N - START` before any content
// sweep. The offending `M = 5` against `N - START = 5 - 3 =
// 2` pins the strict `M > N - START` reject arm; the LEGAL
// exact-fit corner `M == N - START` is covered by the
// middle-slice acceptance test above.
assert_char_array_slice_equals_char_array::<5, 5, 3>(
&['x', 'x', 'x', 'x', 'x'],
&['x', 'x', 'x', 'x', 'x'],
);
}
#[test]
fn assert_char_array_slice_equals_char_array_panic_message_names_the_helper_and_char_slice_equals_array_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-SLICE-EQUALS-ARRAY-
// VIOLATION arm: the panic message MUST begin with the
// helper's own name AND identify the failed AXIS as "CHAR-
// SLICE-EQUALS-ARRAY-VIOLATION" so downstream diagnostics
// route the drift back to (a) the helper by string search on
// `"assert_char_array_slice_equals_char_array"` and (b) the
// failed axis by string search on `"CHAR-SLICE-EQUALS-ARRAY-
// VIOLATION"`. Sibling posture to the u8-row peer's
// provenance pin
// `assert_u8_array_slice_equals_u8_array_panic_message_names_the_helper_and_slice_equals_array_violation_axis`
// — the two pins together bind the (helper, failed-axis)
// provenance pair at ONE test per corner of the (SUB-SLICE
// ARRAY-image) column on both the (u8) row AND the (char)
// row of the (element-type × contract-shape) matrix. The
// `CHAR-` prefix on this axis disambiguates it from the u8-
// row sibling's plain `SLICE-EQUALS-ARRAY-VIOLATION` axis
// vocabulary; the shared `-SLICE-EQUALS-ARRAY-VIOLATION`
// infix lets callers grep either element-type variant by
// the shared axis substring.
let outcome = std::panic::catch_unwind(|| {
assert_char_array_slice_equals_char_array::<5, 3, 1>(
&['z', 'b', 'c', '!', 'z'],
&['b', 'c', 'd'],
);
});
let payload = outcome.expect_err(
"assert_char_array_slice_equals_char_array must panic on \
a positionwise drift — the reject-positionwise-drift arm \
is the CONTENT failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_slice_equals_char_array panic \
payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_array_slice_equals_char_array"),
"assert_char_array_slice_equals_char_array panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("CHAR-SLICE-EQUALS-ARRAY-VIOLATION"),
"assert_char_array_slice_equals_char_array panic message \
{msg:?} must name the failed AXIS (\"CHAR-SLICE-EQUALS-\
ARRAY-VIOLATION\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_str_array_slice_equals_str_array` — the (str)-row
// peer to `assert_u8_array_slice_equals_u8_array` +
// `assert_char_array_slice_equals_char_array` on the (element-
// type) axis of the SUB-SLICE ARRAY-image column of the
// (element-type × contract-shape) matrix. The runtime test
// surface pins each of the helper's arms (accept-middle-slice,
// accept-empty-sub-array, accept-full-array-degenerate, accept-
// sexp-shape-labels-positional-decomposition, reject-positionwise-
// drift, reject-start-out-of-bounds, reject-slice-length-out-of-
// bounds, panic-message-provenance on the STR-SLICE-EQUALS-ARRAY-
// VIOLATION axis) so a regression that silently weakened the
// helper on ANY arm is caught by the helper's OWN test surface
// rather than only surfacing as a false-positive on some future
// sub-slice `[&'static str; N]` pair's compound pin.
#[test]
fn assert_str_array_slice_equals_str_array_accepts_a_canonical_middle_slice() {
// Canonical sub-slice `full[START..START + M) == sub[..]`
// inside a longer array `full` whose ENDPOINTS carry DIFFERENT
// strings than the peer sub-array. Pins the outer `while i <
// M` sweep reads `full[START + i]` at the OFFSET position
// (not `full[i]`) — a regression that dropped the `START`
// offset would compare `full[0..M)` against `sub[..]` and
// pass on `full[0]="z" != sub[0]="b"` silently or panic on
// the wrong axis. `START = 1` pins the sweep skips position
// `[0..START)` and reads only `[1..1+3) = [1..4)`. Sibling
// posture to
// `assert_char_array_slice_equals_char_array_accepts_a_canonical_middle_slice`
// and
// `assert_u8_array_slice_equals_u8_array_accepts_a_canonical_middle_slice`
// — the three share the middle-slice acceptance arm across
// the (element-type × contract-shape) 3-row × 1-column face
// at the (SUB-SLICE ARRAY-image) column.
assert_str_array_slice_equals_str_array::<7, 3, 1>(
&["z", "b", "c", "d", "z", "z", "z"],
&["b", "c", "d"],
);
}
#[test]
fn assert_str_array_slice_equals_str_array_accepts_the_empty_sub_array() {
// LEGAL degenerate: `M == 0` collapses the sub-array into an
// empty listing `[]`. The sweep never enters the loop body
// and the helper accepts. Cross-position coverage pins the
// empty-sub-array acceptance at THREE distinct `START`
// positions (`START == 0` at the left endpoint, `START == 3`
// in the interior, `START == N` at the right endpoint — the
// latter is the corner `START == N` combined with `M == 0`
// that the START-OUT-OF-BOUNDS gate's inclusive upper bound
// must accept). A regression that hard-coded `START < N` OR
// panicked on the `M == 0` corner is caught on ALL THREE
// arms.
assert_str_array_slice_equals_str_array::<5, 0, 0>(&["x", "x", "x", "x", "x"], &[]);
assert_str_array_slice_equals_str_array::<5, 0, 3>(&["x", "x", "x", "x", "x"], &[]);
assert_str_array_slice_equals_str_array::<5, 0, 5>(&["x", "x", "x", "x", "x"], &[]);
}
#[test]
fn assert_str_array_slice_equals_str_array_accepts_the_full_array_degenerate() {
// Full-array-covering slice `M == N, START == 0` collapses
// to the ALL-positions-equal-peer-array shape `full == sub`
// pointwise. Pins that the sweep proceeds through EVERY
// position of the outer array when `START = 0` and `M = N`.
// Cross-arity coverage on `N ∈ {1, 3, 6}` pins the sweep's
// terminal-position visit across the range of str arities
// the substrate's LABELS arrays span (`N = 1` for the
// singleton sub-carvings, `N = 4` for `QuoteForm::LABELS`,
// `N = 6` for `AtomKind::LABELS`).
assert_str_array_slice_equals_str_array::<1, 1, 0>(&["nil"], &["nil"]);
assert_str_array_slice_equals_str_array::<3, 3, 0>(
&["quote", "quasiquote", "unquote"],
&["quote", "quasiquote", "unquote"],
);
assert_str_array_slice_equals_str_array::<6, 6, 0>(
&["symbol", "keyword", "string", "int", "float", "bool"],
&["symbol", "keyword", "string", "int", "float", "bool"],
);
}
#[test]
fn assert_str_array_slice_equals_str_array_accepts_sexp_shape_labels_positional_decomposition()
{
// Runtime cross-check that the FOUR canonical sub-slices of
// `crate::error::SexpShape::LABELS` (`[&'static str; 12]`)
// each byte-equal their sub-carving's canonical
// `[&'static str; M]` listing pointwise. Runs the SAME
// helper the FOUR `const _` witnesses in `error.rs` (in the
// block titled "Compile-time SLICE-EQUALS-ARRAY witnesses
// closing the twelve-arm `SexpShape::LABELS` POSITIONAL
// decomposition") run at rustc time — a runtime safety net
// enforcing the theorem at BOTH stages of the toolchain
// (const at `cargo check`, runtime at `cargo test`). A
// regression that reordered any of the twelve slots in the
// outer array's initializer, or drifted any sub-carving's
// per-role LABEL alias, fails HERE at the substrate callsite
// AND at the const witness in `error.rs`. Sibling posture to
// `assert_u8_array_slice_equals_u8_array_accepts_sub_carving_hash_discriminators_per_position_order`
// on the (u8) row — that witness carries the positional
// decomposition theorem for the FOUR sub-carving
// `HASH_DISCRIMINATORS` arrays; this witness carries the
// SAME theorem for the FOUR sub-carving LABELS arrays
// (strictly STRONGER at the `[1..7)` slice: the (u8) row's
// sibling collapses to a SCALAR replica witness on the six-
// slot atomic-payload middle slice, but the (str) row's
// per-slot label listing distinguishes ALL SIX slots
// individually).
//
// The four canonical sub-slices are (all under the shared
// `&'static str` element-type and shared parent
// `[&'static str; 12]` outer container `SexpShape::LABELS`):
// 1. `SexpShape::LABELS[0..1) ==
// [StructuralKind::NIL_LABEL]`
// 2. `SexpShape::LABELS[1..7) == AtomKind::LABELS`
// 3. `SexpShape::LABELS[7..8) ==
// [StructuralKind::LIST_LABEL]`
// 4. `SexpShape::LABELS[8..12) == QuoteForm::LABELS`
assert_str_array_slice_equals_str_array::<12, 1, 0>(
&crate::error::SexpShape::LABELS,
&[crate::error::StructuralKind::NIL_LABEL],
);
assert_str_array_slice_equals_str_array::<12, 6, 1>(
&crate::error::SexpShape::LABELS,
&AtomKind::LABELS,
);
assert_str_array_slice_equals_str_array::<12, 1, 7>(
&crate::error::SexpShape::LABELS,
&[crate::error::StructuralKind::LIST_LABEL],
);
assert_str_array_slice_equals_str_array::<12, 4, 8>(
&crate::error::SexpShape::LABELS,
&QuoteForm::LABELS,
);
}
#[test]
fn assert_str_array_slice_equals_str_array_accepts_every_family_wide_substrate_array_full_array_literal_listing(
) {
// Runtime cross-check that the SAME five (str)-row FULL-ARRAY
// LITERAL witnesses covered at COMPILE time by the module-
// level `const _: () = ...` cluster immediately below the
// (str)-row `assert_str_array_pairwise_distinct` witnesses
// (`Atom::BOOL_LITERALS` / `AtomKind::LABELS` /
// `QuoteForm::PREFIXES` / `QuoteForm::LABELS` /
// `QuoteForm::IAC_FORGE_TAGS`) also hold when exercised at
// runtime. A regression that removes ONE of the const
// witnesses would still leave THIS runtime pin as a safety
// net; the const witness fires FIRST at `cargo check`, this
// runtime pin catches the positionwise drift at `cargo
// test`. The pair enforces the theorem at TWO stages of the
// toolchain (const at `cargo check`, runtime at `cargo
// test`). Sibling posture to
// `assert_char_array_slice_equals_char_array_accepts_every_family_wide_substrate_array_full_array_literal_listing`
// (if / when that (char)-row runtime-safety-net peer is
// added) — the two would jointly enforce the FULL-ARRAY per-
// position ORDER column at runtime across the (char, str)
// 2-row face of the (element-type × contract-shape) matrix.
//
// A regression that (a) reorders one of the outer arrays'
// slots away from canonical declaration order, or (b) drifts
// one of the per-role scalar `pub const *_LABEL` / `*_PREFIX`
// / `*_TAG` / `TRUE_LITERAL` / `FALSE_LITERAL` aliases the
// outer array's slots re-export, fails HERE with the
// `STR-SLICE-EQUALS-ARRAY-VIOLATION` axis panic naming the
// drifted position.
assert_str_array_slice_equals_str_array::<2, 2, 0>(&Atom::BOOL_LITERALS, &["#t", "#f"]);
assert_str_array_slice_equals_str_array::<6, 6, 0>(
&AtomKind::LABELS,
&["symbol", "keyword", "string", "int", "float", "bool"],
);
assert_str_array_slice_equals_str_array::<4, 4, 0>(
&QuoteForm::PREFIXES,
&["'", "`", ",", ",@"],
);
assert_str_array_slice_equals_str_array::<4, 4, 0>(
&QuoteForm::LABELS,
&["quote", "quasiquote", "unquote", "unquote-splice"],
);
assert_str_array_slice_equals_str_array::<4, 4, 0>(
&QuoteForm::IAC_FORGE_TAGS,
&["quote", "quasiquote", "unquote", "unquote-splicing"],
);
}
#[test]
#[should_panic(expected = "STR-SLICE-EQUALS-ARRAY-VIOLATION")]
fn assert_str_array_slice_equals_str_array_panics_at_runtime_on_positionwise_drift() {
// NEGATIVE PIN — STR-SLICE-EQUALS-ARRAY-VIOLATION corner: a
// str at some position in `full[START..START + M)` that does
// NOT byte-equal the peer sub-array `sub` at the offset-
// matched position MUST panic at runtime with the axis-named
// message. Pins the helper's positionwise-drift reject arm —
// a regression that silently short-circuited on the first
// slice position without checking the middle or terminal
// slice positions would slip through the compile-time
// witness's failure mode too. The offending str `"!"` at
// outer position `3` (interior of the sub-slice `[1..4)`,
// offset `2` inside `sub`) pins the middle-of-slice drift
// mode.
assert_str_array_slice_equals_str_array::<5, 3, 1>(
&["z", "b", "c", "!", "z"],
&["b", "c", "d"],
);
}
#[test]
#[should_panic(expected = "START-OUT-OF-BOUNDS")]
fn assert_str_array_slice_equals_str_array_panics_at_runtime_on_start_out_of_bounds() {
// NEGATIVE PIN — START-OUT-OF-BOUNDS gate: a caller-side
// turbofish arity slip on the `START` const-generic where
// `START > N` MUST panic at runtime with the START-OUT-OF-
// BOUNDS-named message BEFORE the peer SLICE-LENGTH-OUT-OF-
// BOUNDS gate reads `N - START` (which would `usize`-
// underflow had this gate not caught the slip first). Pins
// the gate's placement at the TOP of the helper — a
// regression that dropped the gate would either underflow
// subtraction at the peer gate OR panic deeper in
// `full[START + i]` bounds-checking with a helper-name-less
// panic message. The offending `START = 7` against `N = 5`
// pins the strict `START > N` reject arm; the LEGAL
// `START == N` empty-slice-at-right-endpoint corner is
// covered by the peer acceptance test above.
assert_str_array_slice_equals_str_array::<5, 0, 7>(&["x", "x", "x", "x", "x"], &[]);
}
#[test]
#[should_panic(expected = "SLICE-LENGTH-OUT-OF-BOUNDS")]
fn assert_str_array_slice_equals_str_array_panics_at_runtime_on_slice_length_out_of_bounds() {
// NEGATIVE PIN — SLICE-LENGTH-OUT-OF-BOUNDS gate: a peer
// sub-array arity `M` that exceeds the outer array's tail
// cardinality `N - START` MUST panic at runtime with the
// slice-length-out-of-bounds-named message. Peer gate to the
// START-OUT-OF-BOUNDS arm above — the two gates jointly
// enforce `START ≤ N` and `M ≤ N - START` before any content
// sweep. The offending `M = 5` against `N - START = 5 - 3 =
// 2` pins the strict `M > N - START` reject arm; the LEGAL
// exact-fit corner `M == N - START` is covered by the middle-
// slice acceptance test above.
assert_str_array_slice_equals_str_array::<5, 5, 3>(
&["x", "x", "x", "x", "x"],
&["x", "x", "x", "x", "x"],
);
}
#[test]
fn assert_str_array_slice_equals_str_array_panic_message_names_the_helper_and_str_slice_equals_array_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — STR-SLICE-EQUALS-ARRAY-
// VIOLATION arm: the panic message MUST begin with the
// helper's own name AND identify the failed AXIS as "STR-
// SLICE-EQUALS-ARRAY-VIOLATION" so downstream diagnostics
// route the drift back to (a) the helper by string search on
// `"assert_str_array_slice_equals_str_array"` and (b) the
// failed axis by string search on `"STR-SLICE-EQUALS-ARRAY-
// VIOLATION"`. Sibling posture to the u8-row peer's
// provenance pin
// `assert_u8_array_slice_equals_u8_array_panic_message_names_the_helper_and_slice_equals_array_violation_axis`
// AND the char-row peer's provenance pin
// `assert_char_array_slice_equals_char_array_panic_message_names_the_helper_and_char_slice_equals_array_violation_axis`
// — the three pins together bind the (helper, failed-axis)
// provenance triple at ONE test per corner of the (SUB-SLICE
// ARRAY-image) column on the (u8) + (char) + (str) rows of
// the (element-type × contract-shape) matrix. The `STR-`
// prefix on this axis disambiguates it from the u8-row
// sibling's plain `SLICE-EQUALS-ARRAY-VIOLATION` axis
// vocabulary AND the char-row sibling's `CHAR-SLICE-EQUALS-
// ARRAY-VIOLATION` axis vocabulary; the shared `-SLICE-
// EQUALS-ARRAY-VIOLATION` infix lets callers grep any of
// the three element-type variants by the shared axis
// substring.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_slice_equals_str_array::<5, 3, 1>(
&["z", "b", "c", "!", "z"],
&["b", "c", "d"],
);
});
let payload = outcome.expect_err(
"assert_str_array_slice_equals_str_array must panic on a \
positionwise drift — the reject-positionwise-drift arm \
is the CONTENT failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_array_slice_equals_str_array panic \
payload must be a static &str or String",
);
assert!(
msg.contains("assert_str_array_slice_equals_str_array"),
"assert_str_array_slice_equals_str_array panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("STR-SLICE-EQUALS-ARRAY-VIOLATION"),
"assert_str_array_slice_equals_str_array panic message \
{msg:?} must name the failed AXIS (\"STR-SLICE-EQUALS-\
ARRAY-VIOLATION\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_u8_arrays_disjoint` — the U8-DISJOINTNESS-VIOLATION
// verifier that binds `a ∩ b = ∅` at compile time on the outer-
// `Sexp` cache-key `u8` vocabulary, peer to
// `assert_u8_array_within_u8_finite_set` on the (u8) row of the
// (subset, disjointness) 2-corner face of the (contract-shape)
// axis AND row-dual peer to `assert_char_arrays_disjoint` on the
// (element-type) axis of the SAME (contract-shape) column. The
// runtime test surface pins each of the helper's arms (accept-
// both-empty, accept-either-empty, accept-disjoint-singletons,
// accept-each-family-wide-substrate-pair, accept-arg-order-
// symmetry, reject-single-collision, reject-terminal-a-collision,
// reject-terminal-b-collision, panic-message-provenance on the
// U8-DISJOINTNESS-VIOLATION axis) so a regression that silently
// weakened the helper on ANY arm is caught by the helper's OWN
// test surface rather than only surfacing as a false-positive on
// some future disjoint `[u8; N] × [u8; M]` pair's compound pin.
#[test]
fn assert_u8_arrays_disjoint_accepts_both_empty_arrays() {
// Both arrays empty at the `[u8; 0] × [u8; 0]` corner —
// vacuously disjoint (no `(i, j)` pair exists to test). The
// compile-time `const _: () = assert_u8_arrays_disjoint(&[],
// &[]);` would land on this arm, so the runtime call MUST
// return normally. Turbofish binding required because there's
// no other cue for the const parameters on the empty array
// literals. Sibling posture to
// `assert_char_arrays_disjoint_accepts_both_empty_arrays` on
// the (char) row-dual peer — the two share the trivial-arity
// arm across the (element-type × contract-shape) 4-corner
// face at the (disjointness) column.
assert_u8_arrays_disjoint::<0, 0>(&[], &[]);
}
#[test]
fn assert_u8_arrays_disjoint_accepts_either_side_empty() {
// Either side empty at the `[u8; 0] × [u8; M]` OR
// `[u8; N] × [u8; 0]` corners — vacuously disjoint (the
// OUTER `while i < N` OR the INNER `while j < M` sweep is a
// no-op). Pins BOTH SIDES of the (a-empty, b-empty) 2-corner
// sub-face on the trivial-arity axis so a regression that
// narrowed the sweep to only-a-non-empty OR only-b-non-empty
// fails HERE at the empty-side corner rather than at a
// distant false-positive.
assert_u8_arrays_disjoint::<0, 3>(&[], &[0, 1, 2]);
assert_u8_arrays_disjoint::<3, 0>(&[0, 1, 2], &[]);
}
#[test]
fn assert_u8_arrays_disjoint_accepts_disjoint_singletons() {
// Singleton `a = [K]` and singleton `b = [L]` with `K != L`
// at the `[u8; 1] × [u8; 1]` corner — the minimal non-empty
// disjointness relation. Pins the INNER `if a[i] != b[j]`
// gate returns without panicking on a single distinct-pair
// check. A regression that flipped the equality direction
// (`==` vs `!=`) would silently reject every disjoint
// singleton pair.
assert_u8_arrays_disjoint(&[0u8], &[1u8]);
}
#[test]
fn assert_u8_arrays_disjoint_accepts_each_family_wide_substrate_pair() {
// Runtime cross-check that the TWO (a, b) `[u8; N] × [u8; M]`
// pairs the substrate's module-level `const _` witnesses pin
// at COMPILE time are proper DISJOINTNESS embeddings at
// runtime too. The pairs enforce the theorem at TWO stages
// of the toolchain: the const witnesses fire FIRST at `cargo
// check` (through the two module-level `const _: () =
// assert_u8_arrays_disjoint::<N, M>(...)` lines), this
// runtime pin catches the drift at `cargo test` as a safety
// net. Sibling posture to
// `assert_char_arrays_disjoint_accepts_each_family_wide_substrate_pair`
// which sweeps the FIVE (a, b) PAIRS at the (char) row's
// DISJOINTNESS axis; this pin sweeps the two (a, b) PAIRS
// at the (u8) row's DISJOINTNESS axis on the SAME contract-
// shape column.
assert_u8_arrays_disjoint::<2, 4>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
assert_u8_arrays_disjoint::<2, 2>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
);
}
#[test]
fn assert_u8_arrays_disjoint_is_symmetric_in_argument_order() {
// SYMMETRY PIN: swapping the two arguments produces the SAME
// verdict. Pins that the disjointness relation is truly
// symmetric across the two array arguments (the helper's
// nested-sweep implementation does NOT gratuitously depend on
// argument order). A regression that narrowed the sweep to
// `for i in a { if !b.contains(a[i]) }` (subset-shape, not
// disjointness-shape) would fail the swap on one direction
// only. Runs each substrate pair BOTH ways. Sibling posture
// to `assert_char_arrays_disjoint_is_symmetric_in_argument_order`
// on the (char) row-dual peer.
assert_u8_arrays_disjoint(
&QuoteForm::HASH_DISCRIMINATORS,
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
);
assert_u8_arrays_disjoint(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
);
}
#[test]
#[should_panic(expected = "U8-DISJOINTNESS-VIOLATION")]
fn assert_u8_arrays_disjoint_panics_at_runtime_on_collision() {
// NEGATIVE PIN — U8-DISJOINTNESS-VIOLATION corner: two arrays
// sharing a single byte MUST panic at runtime with the
// U8-DISJOINTNESS-VIOLATION-named message. Pins the helper's
// OWN reject arm — a regression that silently returned
// without panicking on a cross-array collision would slip
// through the compile-time witnesses' failure mode too. The
// shared byte `0u8` is intentionally placed at the FIRST
// position of BOTH arrays to pin the initial-position drift
// mode.
assert_u8_arrays_disjoint(&[0u8, 1u8], &[0u8, 2u8]);
}
#[test]
#[should_panic(expected = "U8-DISJOINTNESS-VIOLATION")]
fn assert_u8_arrays_disjoint_panics_at_runtime_on_terminal_a_collision() {
// NEGATIVE PIN — terminal-position drift on the OUTER `a`
// side: a shared byte at the LAST position of `a` MUST panic
// — pins that the outer `while i < N` loop reaches `i = N -
// 1` (else the terminal drift on `a` would slip through). A
// regression that narrowed the outer sweep to `while i < N
// - 1` (off-by-one on the OUTER bound) would silently accept
// this pair.
assert_u8_arrays_disjoint(&[10u8, 20u8, 30u8], &[30u8]);
}
#[test]
#[should_panic(expected = "U8-DISJOINTNESS-VIOLATION")]
fn assert_u8_arrays_disjoint_panics_at_runtime_on_terminal_b_collision() {
// NEGATIVE PIN — terminal-position drift on the INNER `b`
// side: a shared byte at the LAST position of `b` MUST panic
// — pins that the inner `while j < M` loop reaches `j = M -
// 1` (else the terminal drift on `b` would slip through). A
// regression that narrowed the inner sweep to `while j < M
// - 1` (off-by-one on the INNER bound) would silently accept
// this pair. Sibling posture to the outer-terminal pin above
// — the two pins together bind the terminal bounds on BOTH
// loops.
assert_u8_arrays_disjoint(&[30u8], &[10u8, 20u8, 30u8]);
}
#[test]
fn assert_u8_arrays_disjoint_panic_message_names_the_helper_and_u8_disjointness_violation_axis()
{
// PANIC-MESSAGE PROVENANCE PIN — U8-DISJOINTNESS-VIOLATION
// arm: the panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "U8-DISJOINTNESS-
// VIOLATION" so downstream diagnostics route the drift back
// to (a) the helper by string search on
// `"assert_u8_arrays_disjoint"` and (b) the axis by string
// search on `"U8-DISJOINTNESS-VIOLATION"`. Sibling posture to
// `assert_char_arrays_disjoint_panic_message_names_the_helper_and_char_disjointness_violation_axis`
// on the (char) row-dual peer's provenance pin AND to
// `assert_u8_array_within_u8_finite_set_panic_message_names_the_helper_and_subset_violation_axis`
// on the (u8, subset) contract-orthogonal peer's provenance
// pin — the three pins together bind the (helper, failed-
// axis) provenance triple across the (element-type × contract-
// shape) 2×2 = 4-corner face's three currently-populated
// corners with matching provenance-preservation discipline.
// The axis-provenance string `"U8-DISJOINTNESS-VIOLATION"` is
// chosen DISTINCT from EVERY sibling helper's axis vocabulary
// (`"duplicate"` on the ARRAY-side pairwise-distinct sibling;
// `"CHAR-DISJOINTNESS-VIOLATION"` on the (char) row-dual
// DISJOINTNESS sibling; `"CHAR-SUBSET-VIOLATION"` on the
// (char) SUBSET-embedding sibling; `"SUBSET-VIOLATION"` on
// the (u8) finite-set SUBSET-only sibling; `"RANGE-SUBSET-
// VIOLATION"` on the (u8) range SUBSET-only sibling;
// `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the (u8) covers-
// finite-set sibling; `"OUT-OF-RANGE"` / `"MISSING"` on the
// (u8) covers-inclusive-range sibling; `"ARITY-MISMATCH"` on
// both (u8) `_permutes_*` compound helpers; `"SET-NOT-
// PAIRWISE-DISTINCT"` on the (u8) SET-side well-formedness
// sibling) so a diagnostic that names the failed axis routes
// UNAMBIGUOUSLY to (a) this specific u8 DISJOINTNESS helper.
let outcome = std::panic::catch_unwind(|| {
assert_u8_arrays_disjoint(&[0u8, 1u8], &[0u8, 2u8]);
});
let payload = outcome.expect_err(
"assert_u8_arrays_disjoint must panic on a cross-array \
collision — the reject-collision arm is the sole U8-\
DISJOINTNESS-VIOLATION failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_arrays_disjoint panic payload must be a \
static &str or String",
);
assert!(
msg.contains("assert_u8_arrays_disjoint"),
"assert_u8_arrays_disjoint panic message {msg:?} must \
name the helper for provenance-preserving failure \
diagnostics",
);
assert!(
msg.contains("U8-DISJOINTNESS-VIOLATION"),
"assert_u8_arrays_disjoint panic message {msg:?} must \
name the failed AXIS (\"U8-DISJOINTNESS-VIOLATION\") \
for axis-provenance-preserving failure diagnostics",
);
}
// ── `assert_str_array_pairwise_distinct` — the `&'static str`
// element-type sibling of `assert_char_array_pairwise_distinct`.
// Sibling posture: same runtime-test surface (accept-empty,
// accept-singleton, accept-every-family-wide-substrate-array,
// reject-binary, reject-non-adjacent, reject-terminal, panic-
// message-provenance) restricted to the `&'static str` element
// type. A regression that silently weakens the helper (e.g.
// dropping the byte-length gate, flipping `!=` to `==`, or
// returning early on collision) is caught by the helper's OWN
// test surface rather than only surfacing as a false-positive
// on some future string-typed array's distinctness pin.
#[test]
fn assert_str_array_pairwise_distinct_accepts_the_empty_array() {
// Empty array — vacuously pairwise distinct (no pair to
// collide). The compile-time `const _: () =
// assert_str_array_pairwise_distinct(&EMPTY);` would land on
// this arm, so the runtime call MUST return normally.
assert_str_array_pairwise_distinct::<0>(&[]);
}
#[test]
fn assert_str_array_pairwise_distinct_accepts_singleton_arrays() {
// Singleton array — vacuously pairwise distinct (only one
// element, no pair). Cross-arity coverage on the
// `[&'static str; 1]` corner of the const-N generic.
assert_str_array_pairwise_distinct(&["a"]);
assert_str_array_pairwise_distinct(&[Atom::TRUE_LITERAL]);
}
#[test]
fn assert_str_array_pairwise_distinct_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME five arrays the module-
// level `const _: () = ...` witnesses cover at COMPILE time
// are pairwise distinct. A regression that removes ONE of
// the `const _` witnesses would still leave THIS runtime pin
// as a safety net; the const witness fires FIRST at `cargo
// check`, this runtime pin catches the collision at `cargo
// test`. The pair enforces the theorem at TWO stages of the
// toolchain.
assert_str_array_pairwise_distinct(&Atom::BOOL_LITERALS);
assert_str_array_pairwise_distinct(&AtomKind::LABELS);
assert_str_array_pairwise_distinct(&QuoteForm::PREFIXES);
assert_str_array_pairwise_distinct(&QuoteForm::IAC_FORGE_TAGS);
assert_str_array_pairwise_distinct(&QuoteForm::LABELS);
}
#[test]
#[should_panic(expected = "assert_str_array_pairwise_distinct")]
fn assert_str_array_pairwise_distinct_panics_at_runtime_on_binary_collision() {
// NEGATIVE PIN — binary corner: a two-element array carrying
// the same string twice MUST panic at runtime (the const-eval
// panic surfaces normally when the function is invoked from a
// runtime context, not just a `const _` context). Pins the
// helper's OWN reject-collision arm — a regression that
// silently returned without panicking on a duplicate would
// slip through the compile-time witnesses' failure mode too.
assert_str_array_pairwise_distinct(&["dup", "dup"]);
}
#[test]
#[should_panic(expected = "assert_str_array_pairwise_distinct")]
fn assert_str_array_pairwise_distinct_panics_at_runtime_on_non_adjacent_collision() {
// NEGATIVE PIN — non-adjacent corner: the collision fires on
// ANY (i, j) pair with i < j, not just the adjacent (0, 1)
// corner. Pins the nested-loop shape of the helper — a
// regression that walked ONLY the adjacent pairs (i.e., swept
// `while i + 1 < N { if arr[i] == arr[i+1] { panic } … }`)
// would silently accept `["a", "b", "a"]` (non-adjacent
// collision at positions 0 and 2), missing the contract.
assert_str_array_pairwise_distinct(&["a", "b", "a"]);
}
#[test]
#[should_panic(expected = "assert_str_array_pairwise_distinct")]
fn assert_str_array_pairwise_distinct_panics_at_runtime_on_terminal_collision() {
// NEGATIVE PIN — terminal corner: the collision at the LAST
// pair (positions N-2 and N-1) MUST also fire. Pins the outer
// `while i < N` bound — a regression that walked `while i <
// N - 1` (dropping the last row) would silently accept a
// collision at the tail.
assert_str_array_pairwise_distinct(&["a", "b", "c", "d", "d"]);
}
#[test]
fn assert_str_array_pairwise_distinct_rejects_length_zero_collision() {
// POSITIVE-ORTHOGONAL PIN — the byte-length gate at
// `str_bytes_equal`: two empty strings must be flagged as
// EQUAL (both are the zero-length byte sequence). A
// regression that mishandled `a.len() == 0 && b.len() == 0`
// (e.g. by returning `false` when both lengths are 0, or by
// panicking on the zero-length index) would silently accept
// a `["", ""]` duplicate. Pins the vacuous-length corner of
// the byte-equality helper via the outer helper's runtime
// panic surface.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_pairwise_distinct(&["", ""]);
});
outcome.expect_err(
"assert_str_array_pairwise_distinct must panic on a \
duplicate at the zero-length string corner — the \
`str_bytes_equal` helper's `a.len() == b.len()` gate \
holds vacuously at length 0, so the byte-walk falls \
through to a positive equality verdict",
);
}
#[test]
fn assert_str_array_pairwise_distinct_accepts_prefix_pair_without_collision() {
// POSITIVE-ORTHOGONAL PIN — the byte-length gate at
// `str_bytes_equal`: two strings where one is a strict
// prefix of the other must be flagged as DISTINCT. A
// regression that dropped the `a.len() != b.len()` gate
// (e.g. by comparing bytes only up to the shorter length)
// would silently accept `["ab", "abc"]` as equal. This pin
// fires the outer helper on a prefix pair; the runtime call
// MUST return normally.
assert_str_array_pairwise_distinct(&["ab", "abc"]);
assert_str_array_pairwise_distinct(&["", "a"]);
}
#[test]
fn assert_str_array_pairwise_distinct_panic_message_names_the_helper() {
// PANIC-MESSAGE PROVENANCE PIN: the panic message MUST begin
// with the helper's own name so downstream diagnostics
// (`cargo check` const-eval error output, test-suite failure
// reports) route the drift back to the helper by string
// search — the family-wide contract's failure mode surfaces
// as an identifiable panic-message prefix rather than as an
// opaque const-eval error. Sibling posture to the runtime
// pairwise-distinctness tests that name the ARRAY in their
// failure message; this pin names the HELPER.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_pairwise_distinct(&["x", "x"]);
});
let payload = outcome.expect_err(
"assert_str_array_pairwise_distinct must panic on a \
duplicate — the reject-collision arm is the point of \
the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_array_pairwise_distinct panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_str_array_pairwise_distinct"),
"assert_str_array_pairwise_distinct panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
}
#[test]
fn assert_str_array_all_nonempty_accepts_the_empty_array() {
// Empty array — vacuously all-nonempty (no entry to be empty).
// The compile-time `const _: () = assert_str_array_all_nonempty
// (&EMPTY);` would land on this arm, so the runtime call MUST
// return normally.
assert_str_array_all_nonempty::<0>(&[]);
}
#[test]
fn assert_str_array_all_nonempty_accepts_nonempty_singleton_arrays() {
// Singleton array carrying a nonempty entry — the sole entry
// clears the length-gate. Cross-arity coverage on the
// `[&'static str; 1]` corner of the const-N generic.
assert_str_array_all_nonempty(&["a"]);
assert_str_array_all_nonempty(&[Atom::TRUE_LITERAL]);
}
#[test]
fn assert_str_array_all_nonempty_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME five arrays the module-
// level `const _: () = ...` witnesses cover at COMPILE time
// are all-nonempty. Sibling posture to the runtime
// `_pairwise_distinct` cross-check above — the two together
// pin BOTH the INJECTIVITY axis AND the NONEMPTY-CARDINALITY-
// LOWER-BOUND axis on the SAME five arrays, at TWO stages of
// the toolchain (compile-time `const _` line + this runtime
// safety-net).
assert_str_array_all_nonempty(&Atom::BOOL_LITERALS);
assert_str_array_all_nonempty(&AtomKind::LABELS);
assert_str_array_all_nonempty(&QuoteForm::PREFIXES);
assert_str_array_all_nonempty(&QuoteForm::IAC_FORGE_TAGS);
assert_str_array_all_nonempty(&QuoteForm::LABELS);
}
#[test]
#[should_panic(expected = "assert_str_array_all_nonempty")]
fn assert_str_array_all_nonempty_panics_at_runtime_on_singleton_empty() {
// NEGATIVE PIN — singleton corner: a one-element array
// carrying the empty string MUST panic. Pins the helper's own
// reject-empty arm on the smallest possible array shape.
assert_str_array_all_nonempty(&[""]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_nonempty")]
fn assert_str_array_all_nonempty_panics_at_runtime_on_head_empty() {
// NEGATIVE PIN — head corner: the empty entry at position 0
// MUST fire even when subsequent entries are nonempty. Pins
// the outer sweep's inclusive-start behavior — a regression
// that walked `while i < N { … i += 1 }` from an off-by-one
// start (`i = 1`) would silently accept a leading `""` entry.
assert_str_array_all_nonempty(&["", "a", "b"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_nonempty")]
fn assert_str_array_all_nonempty_panics_at_runtime_on_interior_empty() {
// NEGATIVE PIN — interior corner: the empty entry at a
// strictly-interior position MUST fire. Pins the outer
// sweep's non-early-exit behavior at the head-arm — a
// regression that returned `Ok` on the first nonempty entry
// (bailing out of the sweep prematurely) would silently
// accept an interior `""` entry.
assert_str_array_all_nonempty(&["a", "", "b"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_nonempty")]
fn assert_str_array_all_nonempty_panics_at_runtime_on_tail_empty() {
// NEGATIVE PIN — tail corner: the empty entry at position
// `N - 1` MUST fire. Pins the outer `while i < N` upper bound
// — a regression that walked `while i < N - 1` (dropping the
// last slot) would silently accept a trailing `""` entry.
assert_str_array_all_nonempty(&["a", "b", "c", ""]);
}
#[test]
fn assert_str_array_all_nonempty_rejects_the_all_empty_array() {
// POSITIVE-ORTHOGONAL PIN — the ALL-empty corner: an array
// whose every entry is `""` fires the helper on the FIRST
// entry (the head-arm). Confirms the helper does not silently
// accept an array whose every entry alias-collapses onto the
// zero-length byte sequence — a corner that composes with
// `assert_str_array_pairwise_distinct_rejects_length_zero_
// collision` (that pin rejects `["", ""]` on the pairwise-
// distinctness axis; this pin rejects `["", ""]` on the
// NONEMPTY axis — the two contracts pin the `""`-repeat
// failure mode at BOTH the INJECTIVITY axis AND the
// NONEMPTY axis).
let outcome = std::panic::catch_unwind(|| {
assert_str_array_all_nonempty(&["", ""]);
});
outcome.expect_err(
"assert_str_array_all_nonempty must panic on an array \
whose every entry is `\"\"` — the head-arm fires on the \
zero-length entry at position 0",
);
}
#[test]
fn assert_str_array_all_nonempty_panic_message_names_the_helper_and_axis() {
// PANIC-MESSAGE PROVENANCE PIN: the panic message MUST begin
// with the helper's own name AND name the failed axis as
// `"STR-EMPTY-ENTRY"` (chosen DISTINCT from every sibling
// helper's axis vocabulary: `"duplicate"` on the pairwise-
// distinct sibling; `"STR-DISJOINTNESS-VIOLATION"` on the
// arrays-disjoint sibling; `"STR-SUBSET-VIOLATION"` on the
// within-finite-set sibling) so a diagnostic that names the
// failed axis routes UNAMBIGUOUSLY to THIS specific helper.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_all_nonempty(&[""]);
});
let payload = outcome.expect_err(
"assert_str_array_all_nonempty must panic on an empty \
entry — the reject-empty arm is the point of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_array_all_nonempty panic payload must be \
a static &str or String",
);
assert!(
msg.contains("assert_str_array_all_nonempty"),
"assert_str_array_all_nonempty panic message {msg:?} must \
name the helper for provenance-preserving failure \
diagnostics",
);
assert!(
msg.contains("STR-EMPTY-ENTRY"),
"assert_str_array_all_nonempty panic message {msg:?} must \
name the failed axis as `STR-EMPTY-ENTRY` DISTINCT from \
every sibling helper's axis vocabulary",
);
// Trailing gate — the sibling `_all_ascii` axis vocabulary
// (`STR-NON-ASCII-ENTRY`) must NOT appear in the NONEMPTY
// helper's panic message. Guards against a copy-paste
// regression that drifted the two helpers' axis-provenance
// strings onto the same slot.
assert!(
!msg.contains("STR-NON-ASCII-ENTRY"),
"assert_str_array_all_nonempty panic message {msg:?} \
must NOT name the ASCII-sibling axis — the two per-\
entry helpers must keep their axis-provenance strings \
lexically distinct",
);
}
// ── assert_str_array_all_ascii — the per-entry ASCII-BYTE-RANGE
// gate sibling of `assert_str_array_all_nonempty` on the
// (`&'static str`) row's (per-entry × contract-shape) axis. ──
#[test]
fn assert_str_array_all_ascii_accepts_the_empty_array() {
// Empty array — vacuously all-ASCII (no entry to fail the
// byte-range gate). The compile-time `const _: () =
// assert_str_array_all_ascii(&EMPTY);` would land on this
// arm, so the runtime call MUST return normally.
assert_str_array_all_ascii::<0>(&[]);
}
#[test]
fn assert_str_array_all_ascii_accepts_ascii_singleton_arrays() {
// Singleton array carrying an all-ASCII entry — the sole
// entry clears the byte-range gate. Cross-arity coverage on
// the `[&'static str; 1]` corner of the const-N generic.
assert_str_array_all_ascii(&["a"]);
assert_str_array_all_ascii(&[Atom::TRUE_LITERAL]);
}
#[test]
fn assert_str_array_all_ascii_accepts_the_empty_entry() {
// Vacuous-inner-loop corner — a zero-length entry has no
// byte to fail the range gate, so the helper MUST accept.
// Positive-orthogonal pin against the NONEMPTY sibling — a
// regression that fused the two contracts into one (rejecting
// `""` on the ASCII sweep) would fail this pin. The two
// per-entry contracts stay independent axes on the SAME row.
assert_str_array_all_ascii(&[""]);
assert_str_array_all_ascii(&["", "a", ""]);
}
#[test]
fn assert_str_array_all_ascii_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME five arrays the module-
// level `const _: () = ...` witnesses cover at COMPILE time
// are all-ASCII. Sibling posture to the runtime
// `_pairwise_distinct` + `_all_nonempty` cross-checks — the
// three together pin BOTH the INJECTIVITY axis AND the
// NONEMPTY-CARDINALITY-LOWER-BOUND axis AND the ASCII-BYTE-
// RANGE axis on the SAME five arrays, at TWO stages of the
// toolchain (compile-time `const _` line + this runtime
// safety-net).
assert_str_array_all_ascii(&Atom::BOOL_LITERALS);
assert_str_array_all_ascii(&AtomKind::LABELS);
assert_str_array_all_ascii(&QuoteForm::PREFIXES);
assert_str_array_all_ascii(&QuoteForm::IAC_FORGE_TAGS);
assert_str_array_all_ascii(&QuoteForm::LABELS);
}
#[test]
fn assert_str_array_all_ascii_accepts_the_ascii_boundary_byte() {
// Boundary-inclusive pin on the ASCII byte range's upper
// edge — byte `0x7F` (DEL, the last ASCII byte) MUST be
// accepted. Guards against an off-by-one regression that
// walked `bytes[j] >= 0x7F` and spuriously rejected the
// sole `0x7F` character. Together with the negative pins
// below (which fire on `0x80` — the first non-ASCII byte),
// the two pin the byte-range boundary at both edges.
assert_str_array_all_ascii(&["\u{7F}"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_ascii")]
fn assert_str_array_all_ascii_panics_at_runtime_on_singleton_non_ascii() {
// NEGATIVE PIN — singleton corner: a one-element array
// carrying a non-ASCII entry MUST panic. Pins the helper's
// own reject-non-ascii arm on the smallest possible array
// shape. The two-byte UTF-8 sequence `"é"` (0xC3 0xA9) fires
// on the leading high-byte `0xC3`.
assert_str_array_all_ascii(&["é"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_ascii")]
fn assert_str_array_all_ascii_panics_at_runtime_on_head_non_ascii() {
// NEGATIVE PIN — head corner: the non-ASCII entry at
// position 0 MUST fire even when subsequent entries are
// ASCII. Pins the outer sweep's inclusive-start behavior
// — a regression that walked `while i < N { … i += 1 }`
// from an off-by-one start (`i = 1`) would silently accept
// a leading non-ASCII entry.
assert_str_array_all_ascii(&["café", "a", "b"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_ascii")]
fn assert_str_array_all_ascii_panics_at_runtime_on_interior_non_ascii() {
// NEGATIVE PIN — interior corner: the non-ASCII entry at a
// strictly-interior position MUST fire. Pins the outer
// sweep's non-early-exit behavior at the head-arm — a
// regression that returned `Ok` on the first ASCII entry
// (bailing out of the sweep prematurely) would silently
// accept an interior non-ASCII entry.
assert_str_array_all_ascii(&["a", "café", "b"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_ascii")]
fn assert_str_array_all_ascii_panics_at_runtime_on_tail_non_ascii() {
// NEGATIVE PIN — tail corner: the non-ASCII entry at
// position `N - 1` MUST fire. Pins the outer `while i < N`
// upper bound — a regression that walked `while i < N - 1`
// (dropping the last slot) would silently accept a trailing
// non-ASCII entry.
assert_str_array_all_ascii(&["a", "b", "c", "café"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_ascii")]
fn assert_str_array_all_ascii_panics_at_runtime_on_interior_byte_non_ascii() {
// NEGATIVE PIN — interior-byte corner: the non-ASCII byte at
// a strictly-interior position WITHIN a single entry MUST
// fire. Pins the inner `while j < bytes.len()` sweep's
// non-early-exit behavior — a regression that returned on
// the first ASCII byte within an entry (bailing out of the
// inner sweep prematurely at `bytes[0] <= 0x7F`) would
// silently accept a non-ASCII byte in a strictly-interior
// slot of the entry.
assert_str_array_all_ascii(&["asdéf"]);
}
#[test]
#[should_panic(expected = "assert_str_array_all_ascii")]
fn assert_str_array_all_ascii_panics_on_the_first_non_ascii_byte() {
// NEGATIVE PIN — first-non-ASCII-byte boundary: byte `0x80`
// (the smallest non-ASCII byte) MUST fire. Guards against
// an off-by-one regression that walked `bytes[j] > 0x80`
// (dropping `0x80` from the reject set). Together with
// `_accepts_the_ascii_boundary_byte` (which pins `0x7F`
// acceptance), the two pin the byte-range boundary at both
// edges. UTF-8 lowest continuation byte in isolation is not
// well-formed, so we use `"\u{80}"` — which is the two-byte
// sequence `0xC2 0x80` — either byte is `> 0x7F` so the
// sweep fires on the leading byte `0xC2` regardless.
assert_str_array_all_ascii(&["\u{80}"]);
}
#[test]
fn assert_str_array_all_ascii_rejects_the_all_non_ascii_array() {
// POSITIVE-ORTHOGONAL PIN — the ALL-non-ASCII corner: an
// array whose every entry contains a non-ASCII byte fires
// the helper on the FIRST entry (the head-arm). Confirms
// the helper does not silently accept an array whose every
// entry ships non-ASCII bytes.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_all_ascii(&["café", "über"]);
});
outcome.expect_err(
"assert_str_array_all_ascii must panic on an array whose \
every entry carries a non-ASCII byte — the head-arm \
fires on the first non-ASCII byte at position 0",
);
}
#[test]
fn assert_str_array_all_ascii_panic_message_names_the_helper_and_axis() {
// PANIC-MESSAGE PROVENANCE PIN: the panic message MUST
// begin with the helper's own name AND name the failed axis
// as `"STR-NON-ASCII-ENTRY"` (chosen DISTINCT from every
// sibling helper's axis vocabulary: `"duplicate"` on the
// pairwise-distinct sibling; `"STR-EMPTY-ENTRY"` on the
// per-entry NONEMPTY sibling; `"STR-DISJOINTNESS-VIOLATION"`
// on the arrays-disjoint sibling; `"STR-SUBSET-VIOLATION"`
// on the within-finite-set sibling) so a diagnostic that
// names the failed axis routes UNAMBIGUOUSLY to THIS
// specific ASCII helper.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_all_ascii(&["é"]);
});
let payload = outcome.expect_err(
"assert_str_array_all_ascii must panic on a non-ASCII \
entry — the reject-non-ascii arm is the point of the \
helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_array_all_ascii panic payload must be a \
static &str or String",
);
assert!(
msg.contains("assert_str_array_all_ascii"),
"assert_str_array_all_ascii panic message {msg:?} must \
name the helper for provenance-preserving failure \
diagnostics",
);
assert!(
msg.contains("STR-NON-ASCII-ENTRY"),
"assert_str_array_all_ascii panic message {msg:?} must \
name the failed axis as `STR-NON-ASCII-ENTRY` DISTINCT \
from every sibling helper's axis vocabulary",
);
assert!(
!msg.contains("STR-EMPTY-ENTRY"),
"assert_str_array_all_ascii panic message {msg:?} must \
NOT name the NONEMPTY-sibling axis — the two per-entry \
helpers must keep their axis-provenance strings \
lexically distinct",
);
}
#[test]
fn str_bytes_equal_accepts_the_empty_pair() {
// Direct pin on `str_bytes_equal`'s zero-length corner —
// both inputs are the empty byte sequence, so the helper
// MUST return `true`. Verifies the `a.len() == b.len()`
// gate does not spuriously reject at `len == 0`.
assert!(str_bytes_equal("", ""));
}
#[test]
fn str_bytes_equal_rejects_the_prefix_pair() {
// Direct pin on `str_bytes_equal`'s length-gate: a strict
// prefix pair MUST be rejected. Guards against a regression
// that dropped the length gate and compared bytes only up
// to the shorter length.
assert!(!str_bytes_equal("ab", "abc"));
assert!(!str_bytes_equal("abc", "ab"));
}
#[test]
fn str_bytes_equal_accepts_the_identical_pair() {
// Direct pin on `str_bytes_equal`'s positive-match arm —
// two identical strings MUST be flagged as equal at every
// canonical shape the substrate carries (bool literal,
// atomic-kind label, quote-family prefix). Sibling posture
// to the `_accepts_every_family_wide_substrate_array` pin
// on the outer helper: this pin fires the inner helper on
// the SAME string values that back the outer witnesses'
// per-array entries.
assert!(str_bytes_equal(Atom::TRUE_LITERAL, Atom::TRUE_LITERAL));
assert!(str_bytes_equal(
AtomKind::SYMBOL_LABEL,
AtomKind::SYMBOL_LABEL,
));
assert!(str_bytes_equal(
QuoteForm::QUOTE_PREFIX,
QuoteForm::QUOTE_PREFIX,
));
}
#[test]
fn str_bytes_equal_rejects_the_distinct_pair() {
// Direct pin on `str_bytes_equal`'s reject-arm — two
// distinct family-wide substrate strings MUST be flagged
// as unequal. Guards against a regression that returned
// `true` unconditionally (which would silently pass every
// caller through the collision arm).
assert!(!str_bytes_equal(Atom::TRUE_LITERAL, Atom::FALSE_LITERAL,));
assert!(!str_bytes_equal(
AtomKind::SYMBOL_LABEL,
AtomKind::KEYWORD_LABEL,
));
assert!(!str_bytes_equal(
QuoteForm::QUOTE_PREFIX,
QuoteForm::QUASIQUOTE_PREFIX,
));
}
// ── `assert_str_arrays_disjoint` — the `&'static str` element-
// type sibling of `assert_char_arrays_disjoint` and
// `assert_u8_arrays_disjoint`. Sibling posture: same runtime-test
// surface (accept-both-empty, accept-either-side-empty, accept-
// disjoint-singletons, accept-every-family-wide-substrate-pair,
// symmetric-in-argument-order, reject-cross-collision, reject-
// terminal-a-collision, reject-terminal-b-collision, panic-message-
// provenance) restricted to the `&'static str` element type. A
// regression that silently weakens the helper (e.g. flipping
// `str_bytes_equal` polarity, dropping the outer OR inner sweep,
// or returning early on collision) is caught by the helper's OWN
// test surface rather than only surfacing as a false-positive on
// some future disjoint `[&'static str; N] × [&'static str; M]`
// pair's compound pin.
#[test]
fn assert_str_arrays_disjoint_accepts_both_empty_arrays() {
// Both arrays empty at the `[&'static str; 0] × [&'static str; 0]`
// corner — vacuously disjoint (no `(i, j)` pair exists to
// test). The compile-time `const _: () =
// assert_str_arrays_disjoint(&[], &[]);` would land on this
// arm, so the runtime call MUST return normally. Turbofish
// binding required because there's no other cue for the const
// parameters on the empty array literals. Sibling posture to
// `assert_char_arrays_disjoint_accepts_both_empty_arrays` and
// `assert_u8_arrays_disjoint_accepts_both_empty_arrays` on
// the (char) and (u8) row-dual peers — the three share the
// trivial-arity arm across the (element-type × contract-shape)
// 3-row × (disjointness)-column face.
assert_str_arrays_disjoint::<0, 0>(&[], &[]);
}
#[test]
fn assert_str_arrays_disjoint_accepts_either_side_empty() {
// Either side empty at the `[&'static str; 0] × [&'static str; M]`
// OR `[&'static str; N] × [&'static str; 0]` corners —
// vacuously disjoint (the OUTER `while i < N` OR the INNER
// `while j < M` sweep is a no-op). Pins BOTH SIDES of the
// (a-empty, b-empty) 2-corner sub-face on the trivial-arity
// axis so a regression that narrowed the sweep to only-a-non-
// empty OR only-b-non-empty fails HERE at the empty-side
// corner rather than at a distant false-positive.
assert_str_arrays_disjoint::<0, 3>(&[], &["a", "b", "c"]);
assert_str_arrays_disjoint::<3, 0>(&["a", "b", "c"], &[]);
}
#[test]
fn assert_str_arrays_disjoint_accepts_disjoint_singletons() {
// Singleton `a = [K]` and singleton `b = [L]` with `K != L`
// at the `[&'static str; 1] × [&'static str; 1]` corner — the
// minimal non-empty disjointness relation. Pins the INNER
// `if str_bytes_equal(a[i], b[j])` gate returns without
// panicking on a single distinct-pair check. A regression
// that flipped the equality direction (`!=` vs `==` on the
// byte-equality delegate) would silently reject every
// disjoint singleton pair.
assert_str_arrays_disjoint(&["a"], &["b"]);
}
#[test]
fn assert_str_arrays_disjoint_accepts_each_family_wide_substrate_pair() {
// Runtime cross-check that the FOUR (a, b) `[&'static str; N]
// × [&'static str; M]` pairs the substrate's module-level
// `const _` witnesses pin at COMPILE time are proper
// DISJOINTNESS embeddings at runtime too. The pairs enforce
// the theorem at TWO stages of the toolchain: the const
// witnesses fire FIRST at `cargo check` (through the four
// module-level `const _: () = assert_str_arrays_disjoint::
// <N, M>(...)` lines), this runtime pin catches the drift at
// `cargo test` as a safety net. Sibling posture to
// `assert_char_arrays_disjoint_accepts_each_family_wide_substrate_pair`
// which sweeps the FIVE (a, b) PAIRS at the (char) row and
// `assert_u8_arrays_disjoint_accepts_each_family_wide_substrate_pair`
// which sweeps the TWO (a, b) PAIRS at the (u8) row; this
// pin sweeps the four (a, b) PAIRS at the (`&'static str`)
// row on the SAME contract-shape column.
assert_str_arrays_disjoint::<4, 4>(&QuoteForm::PREFIXES, &QuoteForm::LABELS);
assert_str_arrays_disjoint::<4, 4>(&QuoteForm::PREFIXES, &QuoteForm::IAC_FORGE_TAGS);
assert_str_arrays_disjoint::<4, 6>(&QuoteForm::PREFIXES, &AtomKind::LABELS);
assert_str_arrays_disjoint::<6, 4>(&AtomKind::LABELS, &QuoteForm::LABELS);
}
#[test]
fn assert_str_arrays_disjoint_is_symmetric_in_argument_order() {
// SYMMETRY PIN: swapping the two arguments produces the SAME
// verdict. Pins that the disjointness relation is truly
// symmetric across the two array arguments (the helper's
// nested-sweep implementation does NOT gratuitously depend on
// argument order). A regression that narrowed the sweep to
// `for i in a { if !b.contains(a[i]) }` (subset-shape, not
// disjointness-shape) would fail the swap on one direction
// only. Runs each substrate pair BOTH ways. Sibling posture
// to `assert_char_arrays_disjoint_is_symmetric_in_argument_order`
// on the (char) row-dual peer and
// `assert_u8_arrays_disjoint_is_symmetric_in_argument_order`
// on the (u8) row-dual peer.
assert_str_arrays_disjoint(&QuoteForm::LABELS, &QuoteForm::PREFIXES);
assert_str_arrays_disjoint(&QuoteForm::IAC_FORGE_TAGS, &QuoteForm::PREFIXES);
assert_str_arrays_disjoint(&AtomKind::LABELS, &QuoteForm::PREFIXES);
assert_str_arrays_disjoint(&QuoteForm::LABELS, &AtomKind::LABELS);
}
#[test]
#[should_panic(expected = "STR-DISJOINTNESS-VIOLATION")]
fn assert_str_arrays_disjoint_panics_at_runtime_on_collision() {
// NEGATIVE PIN — STR-DISJOINTNESS-VIOLATION corner: two arrays
// sharing a single string MUST panic at runtime with the
// STR-DISJOINTNESS-VIOLATION-named message. Pins the helper's
// OWN reject arm — a regression that silently returned
// without panicking on a cross-array collision would slip
// through the compile-time witnesses' failure mode too. The
// shared string `"dup"` is intentionally placed at the FIRST
// position of BOTH arrays to pin the initial-position drift
// mode.
assert_str_arrays_disjoint(&["dup", "x"], &["dup", "y"]);
}
#[test]
#[should_panic(expected = "STR-DISJOINTNESS-VIOLATION")]
fn assert_str_arrays_disjoint_panics_at_runtime_on_terminal_a_collision() {
// NEGATIVE PIN — terminal-position drift on the OUTER `a`
// side: a shared string at the LAST position of `a` MUST
// panic — pins that the outer `while i < N` loop reaches
// `i = N - 1` (else the terminal drift on `a` would slip
// through). A regression that narrowed the outer sweep to
// `while i < N - 1` (off-by-one on the OUTER bound) would
// silently accept this pair.
assert_str_arrays_disjoint(&["a", "b", "shared"], &["shared"]);
}
#[test]
#[should_panic(expected = "STR-DISJOINTNESS-VIOLATION")]
fn assert_str_arrays_disjoint_panics_at_runtime_on_terminal_b_collision() {
// NEGATIVE PIN — terminal-position drift on the INNER `b`
// side: a shared string at the LAST position of `b` MUST
// panic — pins that the inner `while j < M` loop reaches
// `j = M - 1` (else the terminal drift on `b` would slip
// through). A regression that narrowed the inner sweep to
// `while j < M - 1` (off-by-one on the INNER bound) would
// silently accept this pair. Sibling posture to the outer-
// terminal pin above — the two pins together bind the
// terminal bounds on BOTH loops.
assert_str_arrays_disjoint(&["shared"], &["a", "b", "shared"]);
}
#[test]
#[should_panic(expected = "STR-DISJOINTNESS-VIOLATION")]
fn assert_str_arrays_disjoint_panics_at_runtime_on_length_zero_collision() {
// NEGATIVE PIN — the byte-length gate at `str_bytes_equal`
// must classify TWO empty strings across the (a, b) boundary
// as equal too (both are the zero-length byte sequence). A
// regression that treated `""` as never-colliding across the
// arrays would silently accept the empty-string collision.
// Delegated to the SAME `str_bytes_equal` helper the
// pairwise-distinct sibling uses — this pin exercises the
// cross-array direction of the same zero-length arm.
assert_str_arrays_disjoint(&[""], &[""]);
}
#[test]
fn assert_str_arrays_disjoint_accepts_prefix_pair_without_collision() {
// POSITIVE-ORTHOGONAL PIN — the byte-length gate at
// `str_bytes_equal` across the (a, b) boundary: two arrays
// where entries of one are strict prefixes of entries of the
// other but no full-length equal pair exists must be flagged
// as DISJOINT. A regression that dropped the
// `a.len() != b.len()` gate (e.g. by comparing bytes only up
// to the shorter length) would silently reject
// `(["ab"], ["abc"])` as a collision. Sibling to the (str,
// pairwise-distinct) sibling's `_accepts_prefix_pair_without_
// collision` pin — the two share the byte-length-gate
// theorem across (intra-array, inter-array) row-dual peers.
assert_str_arrays_disjoint(&["ab"], &["abc"]);
assert_str_arrays_disjoint(&["abc"], &["ab"]);
assert_str_arrays_disjoint(&[""], &["a"]);
}
#[test]
fn assert_str_arrays_disjoint_panic_message_names_the_helper_and_str_disjointness_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — STR-DISJOINTNESS-VIOLATION
// arm: the panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "STR-DISJOINTNESS-
// VIOLATION" so downstream diagnostics route the drift back
// to (a) the helper by string search on
// `"assert_str_arrays_disjoint"` and (b) the axis by string
// search on `"STR-DISJOINTNESS-VIOLATION"`. Sibling posture
// to `assert_char_arrays_disjoint_panic_message_names_the_helper_and_char_disjointness_violation_axis`
// on the (char) row-dual peer's provenance pin AND to
// `assert_u8_arrays_disjoint_panic_message_names_the_helper_and_u8_disjointness_violation_axis`
// on the (u8) row-dual peer's provenance pin — the three
// pins together bind the (helper, failed-axis) provenance
// triple across the (element-type ∈ {char, u8, `&'static
// str`}) × (disjointness)-column 3-row face with matching
// provenance-preservation discipline. The axis-provenance
// string `"STR-DISJOINTNESS-VIOLATION"` is chosen DISTINCT
// from EVERY sibling helper's axis vocabulary (`"duplicate"`
// on the (str) ARRAY-side pairwise-distinct sibling;
// `"CHAR-DISJOINTNESS-VIOLATION"` on the (char) row-dual
// DISJOINTNESS sibling; `"U8-DISJOINTNESS-VIOLATION"` on
// the (u8) row-dual DISJOINTNESS sibling; `"CHAR-SUBSET-
// VIOLATION"` on the (char) SUBSET-embedding sibling;
// `"SUBSET-VIOLATION"` on the (u8) finite-set SUBSET-only
// sibling; `"RANGE-SUBSET-VIOLATION"` on the (u8) range
// SUBSET-only sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"`
// on the (u8) covers-finite-set sibling; `"OUT-OF-RANGE"` /
// `"MISSING"` on the (u8) covers-inclusive-range sibling;
// `"ARITY-MISMATCH"` on both (u8) `_permutes_*` compound
// helpers; `"SET-NOT-PAIRWISE-DISTINCT"` on the (u8) SET-side
// well-formedness sibling) so a diagnostic that names the
// failed axis routes UNAMBIGUOUSLY to (a) this specific
// `&'static str` DISJOINTNESS helper.
let outcome = std::panic::catch_unwind(|| {
assert_str_arrays_disjoint(&["dup", "x"], &["dup", "y"]);
});
let payload = outcome.expect_err(
"assert_str_arrays_disjoint must panic on a cross-array \
collision — the reject-collision arm is the sole STR-\
DISJOINTNESS-VIOLATION failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_arrays_disjoint panic payload must be a \
static &str or String",
);
assert!(
msg.contains("assert_str_arrays_disjoint"),
"assert_str_arrays_disjoint panic message {msg:?} must \
name the helper for provenance-preserving failure \
diagnostics",
);
assert!(
msg.contains("STR-DISJOINTNESS-VIOLATION"),
"assert_str_arrays_disjoint panic message {msg:?} must \
name the failed AXIS (\"STR-DISJOINTNESS-VIOLATION\") \
for axis-provenance-preserving failure diagnostics",
);
}
// ── `assert_str_array_within_str_finite_set` — the `&'static str`
// element-type sibling of `assert_char_array_within_char_finite_
// set` and `assert_u8_array_within_u8_finite_set` on the (element-
// type) axis of the (element-type × contract-shape) matrix at the
// (subset-embedding) column. Sibling posture: same runtime-test
// surface (accept-empty, accept-singleton, accept-arr-equals-set,
// accept-each-family-wide-substrate-subset, accept-repeated-array-
// entries, reject-out-of-set, reject-terminal-out-of-set, panic-
// message-provenance, delegated-set-well-formedness) restricted to
// the `&'static str` element type. A regression that silently
// weakens the helper (e.g. flipping the found flag, dropping the
// outer `i` loop, or short-circuiting on the first-position match)
// is caught by the helper's OWN test surface rather than only
// surfacing as a false-positive on some future `[&'static str; N]`
// sub-vocabulary array's subset-embedding pin.
#[test]
fn assert_str_array_within_str_finite_set_accepts_the_empty_array_within_any_set() {
// Empty array `arr = []` at the `[&'static str; 0]` corner —
// vacuously a subset of every set (no `i` position exists to
// test). Cross-arity coverage on the trivial ARRAY corner of
// the const-N generic across three witness-set widths (empty,
// singleton, multi-element) to pin the helper's OUTER-sweep
// arm across the whole (`N == 0` × `M`) axis. Turbofish
// binding required because there's no other cue for the const
// parameters on the empty array literal. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_the_empty_array_within_any_set`
// and `assert_u8_array_within_u8_finite_set_accepts_the_empty_array_within_any_set`
// on the (char) + (u8) row-dual peers of the SUBSET-EMBEDDING
// helper — the three share the trivial-arity arm across the
// element-type column.
assert_str_array_within_str_finite_set::<0, 0>(&[], &[]);
assert_str_array_within_str_finite_set::<0, 1>(&[], &["x"]);
assert_str_array_within_str_finite_set::<0, 3>(&[], &["a", "b", "c"]);
}
#[test]
fn assert_str_array_within_str_finite_set_accepts_singleton_array_when_str_in_set() {
// Singleton array `arr = [K]` at the `[&'static str; 1]`
// corner MUST pass when `K ∈ set`. Cross-position coverage:
// the str can sit at the FIRST, MIDDLE, or LAST position of
// the `set` — pins the INNER `while j < M` sweep terminates
// at the first-match position rather than always at position
// `0` OR always at position `M - 1`. A regression that
// narrowed the inner sweep to `j == 0` would silently reject
// singleton arrays hitting non-first set positions.
assert_str_array_within_str_finite_set::<1, 3>(&["a"], &["a", "b", "c"]);
assert_str_array_within_str_finite_set::<1, 3>(&["b"], &["a", "b", "c"]);
assert_str_array_within_str_finite_set::<1, 3>(&["c"], &["a", "b", "c"]);
}
#[test]
fn assert_str_array_within_str_finite_set_accepts_arr_equals_set() {
// Boundary corner where `arr` and `set` cover byte-for-byte
// identical distinct-value sets — the SUBSET relation
// degenerates to EQUALITY. Pins that the helper does NOT
// gratuitously require the SUBSET to be PROPER (strict):
// equal-multisets pass the SUBSET check. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_arr_equals_set`
// and `assert_u8_array_within_u8_finite_set_accepts_arr_equals_set`
// on the (char) + (u8) row-dual peers of the SUBSET-EMBEDDING
// helper — the three share the EQUAL-SETS corner across the
// element-type column.
assert_str_array_within_str_finite_set(&["a", "b"], &["a", "b"]);
assert_str_array_within_str_finite_set(&[Atom::TRUE_LITERAL], &[Atom::TRUE_LITERAL]);
}
#[test]
fn assert_str_array_within_str_finite_set_accepts_each_family_wide_substrate_subset() {
// Runtime cross-check that the THREE (subset, superset) pairs
// the substrate's module-level `const _` witnesses at
// `error.rs` pin at COMPILE time are PROPER SUBSET embeddings
// at runtime too. The pairs enforce the theorem at TWO stages
// of the toolchain: the const witnesses fire FIRST at `cargo
// check` (through the three module-level `const _: () =
// crate::ast::assert_str_array_within_str_finite_set::<N, M>
// (...)` lines in `error.rs`), this runtime pin catches the
// drift at `cargo test` as a safety net. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_each_family_wide_substrate_subset`
// and `assert_str_array_pairwise_distinct_accepts_every_family_wide_substrate_array`
// — the first sweeps the (char) subset pairs at the SUBSET-
// EMBEDDING axis; the second sweeps the (str) five arrays at
// the INJECTIVITY axis; this pin sweeps the (str) three
// (subset, superset) PAIRS at the SUBSET-EMBEDDING axis.
// Cardinality composition: 6 + 4 + 2 = 12 =
// `SexpShape::LABELS.len()` — the three subsets partition the
// outer twelve-arm vocabulary (composed with the pre-existing
// pairwise-disjointness witness of `AtomKind::LABELS ∩
// QuoteForm::LABELS`).
assert_str_array_within_str_finite_set::<6, 12>(&AtomKind::LABELS, &SexpShape::LABELS);
assert_str_array_within_str_finite_set::<4, 12>(&QuoteForm::LABELS, &SexpShape::LABELS);
assert_str_array_within_str_finite_set::<2, 12>(
&StructuralKind::LABELS,
&SexpShape::LABELS,
);
}
#[test]
fn assert_str_array_within_str_finite_set_accepts_repeated_array_entries_in_set() {
// Peer corner to a (future-lift) `_covers_str_finite_set`:
// this helper permits duplicates in `arr` because SUBSET-
// membership is a DISTINCT-value predicate — `["a", "a", "b"]`
// is a subset of `{"a", "b", "c"}` even though the array is
// not pairwise-distinct. Pins that the helper does NOT
// gratuitously require INJECTIVITY on `arr` (the injectivity
// axis is a DIFFERENT compile-time contract bound by
// `assert_str_array_pairwise_distinct`; combining both binds
// BOTH axes). Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_repeated_array_entries_in_set`
// and `assert_u8_array_within_u8_finite_set_accepts_repeated_array_entries_in_set`
// on the (char) + (u8) row-dual peers of the SUBSET-EMBEDDING
// helper.
assert_str_array_within_str_finite_set(&["a", "a", "b"], &["a", "b", "c"]);
}
#[test]
#[should_panic(expected = "STR-SUBSET-VIOLATION")]
fn assert_str_array_within_str_finite_set_panics_at_runtime_on_out_of_set_entry() {
// NEGATIVE PIN — STR-SUBSET-VIOLATION corner: an array
// carrying a single entry NOT in the target set MUST panic
// at runtime with the STR-SUBSET-VIOLATION-named message.
// Pins the helper's OWN reject arm — a regression that
// silently returned without panicking on an out-of-set entry
// would slip through the compile-time witnesses' failure mode
// too. The offending str `"z"` is intentionally chosen
// OUTSIDE the target set to pin the OUT-OF-SET drift mode.
assert_str_array_within_str_finite_set(&["a", "z"], &["a", "b", "c"]);
}
#[test]
#[should_panic(expected = "STR-SUBSET-VIOLATION")]
fn assert_str_array_within_str_finite_set_panics_at_runtime_on_terminal_out_of_set_entry() {
// NEGATIVE PIN — terminal-position drift: an out-of-set entry
// at the LAST array position MUST panic — pins that the
// outer `while i < N` loop reaches `i = N - 1` (else the
// terminal drift would slip through). A regression that
// narrowed the outer sweep to `while i < N - 1` (off-by-one
// on the OUTER bound) would silently accept this array.
// Sibling posture to
// `assert_char_array_within_char_finite_set_panics_at_runtime_on_terminal_out_of_set_entry`
// and `assert_u8_array_within_u8_finite_set_panics_at_runtime_on_terminal_out_of_set_entry`
// on the (char) + (u8) row-dual peers' terminal-position
// pins — all three bind the outer-sweep terminal bound at
// the ONE array-side outer loop the helper carries.
assert_str_array_within_str_finite_set(&["a", "b", "c", "z"], &["a", "b", "c"]);
}
#[test]
fn assert_str_array_within_str_finite_set_rejects_length_prefix_shorter_than_set_entry() {
// Byte-length gate corner: an `arr` entry that shares a
// strict-prefix with a `set` entry but is BYTE-SHORTER than
// that `set` entry MUST fail the subset check (prefix ≠
// equal-bytes at the `str_bytes_equal` byte-length gate).
// Pins the cross-array direction of the SAME byte-length
// gate the pairwise-distinct sibling's test surface
// (`assert_str_array_pairwise_distinct_rejects_length_zero_collision`,
// `assert_str_array_pairwise_distinct_accepts_prefix_pair_without_collision`)
// pins on the intra-array direction. Cross-array prefix
// mismatch → out-of-set → STR-SUBSET-VIOLATION panic.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_within_str_finite_set(&["quo"], &["quote", "quasiquote"]);
});
outcome.expect_err(
"assert_str_array_within_str_finite_set must panic on a \
STRICT-PREFIX-only entry outside the target set — the \
byte-length gate at str_bytes_equal separates \
`\"quo\"` from `\"quote\"` at the length-check arm before \
any byte comparison, routing to the STR-SUBSET-VIOLATION \
out-of-set panic",
);
}
#[test]
fn assert_str_array_within_str_finite_set_accepts_length_zero_entry_in_length_zero_set() {
// BYTE-LENGTH-ZERO corner: the empty-string entry `""` in
// `arr` MUST match the empty-string entry `""` in `set` at
// the byte-length gate (both length 0). Pins the LOWER
// boundary of the byte-length axis on the cross-array
// direction of the SAME byte-length gate. A regression that
// gated `str_bytes_equal` on `a.len() > 0` (rather than
// `a.len() == b.len()`) would silently reject this pair.
assert_str_array_within_str_finite_set(&[""], &[""]);
}
#[test]
fn assert_str_array_within_str_finite_set_panic_message_names_the_helper_and_str_subset_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — STR-SUBSET-VIOLATION arm:
// the panic message MUST begin with the helper's own name AND
// identify the failed AXIS as "STR-SUBSET-VIOLATION" so
// downstream diagnostics route the drift back to (a) the
// helper by string search on
// `"assert_str_array_within_str_finite_set"` and (b) the axis
// by string search on `"STR-SUBSET-VIOLATION"`. Sibling
// posture to
// `assert_char_array_within_char_finite_set_panic_message_names_the_helper_and_char_subset_violation_axis`
// on the (char) row-dual peer's provenance pin AND to
// `assert_u8_array_within_u8_finite_set_panic_message_names_the_helper_and_subset_violation_axis`
// on the (u8) row-dual peer's provenance pin — the three
// pins together bind the (helper, failed-axis) provenance
// triple across the (element-type ∈ {char, u8, `&'static
// str`}) × (subset-embedding)-column 3-row face with matching
// provenance-preservation discipline. The axis-provenance
// string `"STR-SUBSET-VIOLATION"` is chosen DISTINCT from
// EVERY sibling helper's axis vocabulary (`"duplicate"` on
// the (str) ARRAY-side pairwise-distinct sibling; `"STR-
// DISJOINTNESS-VIOLATION"` on the (str) row DISJOINTNESS
// sibling; `"CHAR-SUBSET-VIOLATION"` on the (char) row-dual
// SUBSET sibling; `"SUBSET-VIOLATION"` on the (u8) finite-
// set SUBSET-only sibling; `"RANGE-SUBSET-VIOLATION"` on the
// (u8) range SUBSET-only sibling; `"CHAR-DISJOINTNESS-
// VIOLATION"` / `"U8-DISJOINTNESS-VIOLATION"` on the (char)
// / (u8) row-dual DISJOINTNESS siblings; `"OUT-OF-SET"` /
// `"SET-BYTE-MISSING"` on the (u8) covers-finite-set
// sibling; `"OUT-OF-RANGE"` / `"MISSING"` on the (u8)
// covers-inclusive-range sibling; `"ARITY-MISMATCH"` on both
// (u8) `_permutes_*` compound helpers; `"SET-NOT-PAIRWISE-
// DISTINCT"` on the (u8) SET-side well-formedness sibling)
// so a diagnostic that names the failed axis routes
// UNAMBIGUOUSLY to (a) this specific `&'static str` SUBSET-
// embedding helper, (b) the `arr` argument as the drift site
// rather than the `set` argument specifying the target
// superset.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_within_str_finite_set(&["a", "z"], &["a", "b", "c"]);
});
let payload = outcome.expect_err(
"assert_str_array_within_str_finite_set must panic on an \
out-of-set entry — the reject-out-of-set arm is the \
sole STR-SUBSET-VIOLATION failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_array_within_str_finite_set panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_str_array_within_str_finite_set"),
"assert_str_array_within_str_finite_set panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("STR-SUBSET-VIOLATION"),
"assert_str_array_within_str_finite_set panic message \
{msg:?} must name the failed AXIS (\"STR-SUBSET-\
VIOLATION\") for axis-provenance-preserving failure \
diagnostics",
);
}
#[test]
#[should_panic(expected = "assert_str_array_pairwise_distinct")]
fn assert_str_array_within_str_finite_set_panics_on_malformed_target_set_spec() {
// NEGATIVE PIN — DELEGATED SET-side well-formedness: a
// malformed target-set spec `["a", "a", "b"]` fed into the
// ARRAY-side within helper MUST panic on the DELEGATED
// pairwise-distinct arm BEFORE the STR-SUBSET-VIOLATION arm
// fires. Pins the delegation chain: a regression that
// dropped the `assert_str_array_pairwise_distinct(set)` call
// at the top of `assert_str_array_within_str_finite_set`
// would silently accept a malformed set and produce a false-
// positive verdict on any `arr` embedded in the DISTINCT-
// value subset. The panic message here surfaces from the
// SIBLING helper (containing the ARRAY-side helper's
// `"assert_str_array_pairwise_distinct"` panic-name prefix
// rather than a bespoke `"SET-NOT-PAIRWISE-DISTINCT"` axis
// string) because the (str) row does NOT yet carry a
// separate `assert_str_finite_set_pairwise_distinct` alias —
// the delegation reuses the ARRAY-side helper directly per
// the design choice documented on the SET-side-well-
// formedness section of the helper's docstring. Sibling
// posture to
// `assert_char_array_within_char_finite_set_panics_on_malformed_target_set_spec`
// and `assert_u8_array_within_u8_finite_set_panics_on_malformed_target_set_spec`
// on the (char) + (u8) row-dual peers' delegated-SET-well-
// formedness pins — the three pins together bind the
// delegation chain at ONE test per element-type row.
assert_str_array_within_str_finite_set::<2, 3>(&["a", "b"], &["a", "b", "b"]);
}
// ── `assert_str_finite_set_covered_by_three_str_arrays` — the
// (⊆) SET-COVERAGE dual of the SUBSET-embedding sibling on the
// (`&'static str`) row of the (element-type × contract-shape)
// matrix, extended to the 3-array-union carrier shape. Sibling
// posture: same runtime-test surface (accept-empty-parent,
// accept-parent-covered-by-first-array, accept-parent-covered-
// by-second-array, accept-parent-covered-by-third-array, accept-
// sexp-shape-labels-partition, reject-uncovered-parent-entry,
// reject-terminal-uncovered-parent-entry, panic-message-
// provenance, delegated-set-well-formedness) specialised to the
// 3-array coverage shape. A regression that silently weakens the
// helper (e.g. dropping the second-array probe, dropping the
// third-array probe, or short-circuiting on the first parent
// position) is caught by the helper's OWN test surface rather
// than only surfacing as a false-positive on the
// `SexpShape::LABELS` disjoint-union witness.
#[test]
fn assert_str_finite_set_covered_by_three_str_arrays_accepts_the_empty_parent() {
// Empty parent `set = []` at the `[&'static str; 0]` corner
// — vacuously covered by any triple of sub-vocabulary arrays
// (no `w` position exists to test). Cross-arity coverage on
// the trivial PARENT corner of the const-W generic across
// three sub-vocabulary-arity combinations. Turbofish binding
// required because there's no other cue for the const
// parameters on the empty array literal.
assert_str_finite_set_covered_by_three_str_arrays::<0, 0, 0, 0>(&[], &[], &[], &[]);
assert_str_finite_set_covered_by_three_str_arrays::<1, 0, 0, 0>(&["x"], &[], &[], &[]);
assert_str_finite_set_covered_by_three_str_arrays::<1, 2, 3, 0>(
&["a"],
&["b", "c"],
&["d", "e", "f"],
&[],
);
}
#[test]
fn assert_str_finite_set_covered_by_three_str_arrays_accepts_parent_covered_by_first_array() {
// Singleton parent `set = [K]` at the `[&'static str; 1]`
// corner MUST pass when `K` is in the FIRST sub-vocabulary
// array `a`. Pins the FIRST-ARRAY probe arm's short-circuit
// discovery — the parent entry is reached without exhausting
// the second- or third-array probes. Cross-position coverage
// inside `a`: parent hit at FIRST, MIDDLE, LAST position of
// `a` pins the INNER `while i < N` sweep terminates at the
// first-match position rather than always at position `0` OR
// always at position `N - 1`.
assert_str_finite_set_covered_by_three_str_arrays::<3, 2, 1, 1>(
&["k", "b", "c"],
&["d", "e"],
&["f"],
&["k"],
);
assert_str_finite_set_covered_by_three_str_arrays::<3, 2, 1, 1>(
&["a", "k", "c"],
&["d", "e"],
&["f"],
&["k"],
);
assert_str_finite_set_covered_by_three_str_arrays::<3, 2, 1, 1>(
&["a", "b", "k"],
&["d", "e"],
&["f"],
&["k"],
);
}
#[test]
fn assert_str_finite_set_covered_by_three_str_arrays_accepts_parent_covered_by_second_array() {
// Singleton parent MUST pass when `K` is in the SECOND sub-
// vocabulary array `b` but NOT in `a`. Pins the SECOND-ARRAY
// probe arm — the coverage sweep proceeds from `a` to `b`
// when `a` returns no hit. A regression that dropped the
// `if !found { … b sweep … }` block would silently reject
// this case as SET-STR-MISSING even though `b` carries the
// covering entry. Cross-position coverage inside `b`: FIRST,
// MIDDLE, LAST positions of `b` pin the INNER `while j < M`
// sweep terminates at the first-match position.
assert_str_finite_set_covered_by_three_str_arrays::<3, 3, 1, 1>(
&["a", "b", "c"],
&["k", "e", "f"],
&["g"],
&["k"],
);
assert_str_finite_set_covered_by_three_str_arrays::<3, 3, 1, 1>(
&["a", "b", "c"],
&["d", "k", "f"],
&["g"],
&["k"],
);
assert_str_finite_set_covered_by_three_str_arrays::<3, 3, 1, 1>(
&["a", "b", "c"],
&["d", "e", "k"],
&["g"],
&["k"],
);
}
#[test]
fn assert_str_finite_set_covered_by_three_str_arrays_accepts_parent_covered_by_third_array() {
// Singleton parent MUST pass when `K` is in the THIRD sub-
// vocabulary array `c` but NOT in `a` or `b`. Pins the
// THIRD-ARRAY probe arm — the coverage sweep proceeds all
// the way to `c` when `a` and `b` both return no hit. A
// regression that dropped the `if !found { … c sweep … }`
// block would silently reject this case as SET-STR-MISSING
// even though `c` carries the covering entry. Cross-position
// coverage inside `c`: FIRST, MIDDLE, LAST positions of `c`
// pin the INNER `while k < K` sweep terminates at the first-
// match position.
assert_str_finite_set_covered_by_three_str_arrays::<3, 2, 3, 1>(
&["a", "b", "c"],
&["d", "e"],
&["k", "g", "h"],
&["k"],
);
assert_str_finite_set_covered_by_three_str_arrays::<3, 2, 3, 1>(
&["a", "b", "c"],
&["d", "e"],
&["f", "k", "h"],
&["k"],
);
assert_str_finite_set_covered_by_three_str_arrays::<3, 2, 3, 1>(
&["a", "b", "c"],
&["d", "e"],
&["f", "g", "k"],
&["k"],
);
}
#[test]
fn assert_str_finite_set_covered_by_three_str_arrays_accepts_sexp_shape_labels_partition() {
// Runtime cross-check that the twelve-arm
// (`AtomKind::LABELS`, `QuoteForm::LABELS`,
// `StructuralKind::LABELS`, `SexpShape::LABELS`) partition
// quadruple the substrate's module-level `const _` witness at
// `error.rs` pins at COMPILE time is a well-formed SET-
// COVERAGE relation at runtime too. The quadruple enforces the
// (⊆) direction of the disjoint-union theorem at TWO stages
// of the toolchain: the const witness fires FIRST at `cargo
// check`, this runtime pin catches the drift at `cargo test`
// as a safety net. Sibling posture to
// `assert_str_array_within_str_finite_set_accepts_each_family_wide_substrate_subset`
// — the sibling sweeps the (⊇) SUBSET direction for the three
// sub-vocabularies; this pin sweeps the (⊆) COVERAGE direction
// for the parent. Cardinality composition: 6 + 4 + 2 = 12 =
// `SexpShape::LABELS.len()`.
assert_str_finite_set_covered_by_three_str_arrays::<6, 4, 2, 12>(
&AtomKind::LABELS,
&QuoteForm::LABELS,
&crate::error::StructuralKind::LABELS,
&crate::error::SexpShape::LABELS,
);
}
#[test]
#[should_panic(expected = "SET-STR-MISSING")]
fn assert_str_finite_set_covered_by_three_str_arrays_panics_at_runtime_on_uncovered_parent_entry(
) {
// NEGATIVE PIN — SET-STR-MISSING corner: a parent set carrying
// an entry NOT in any of the three sub-vocabulary arrays MUST
// panic at runtime with the SET-STR-MISSING-named message.
// Pins the helper's OWN reject arm — a regression that
// silently returned without panicking on an uncovered entry
// would slip through the compile-time witness's failure mode
// too. The offending str `"z"` is intentionally chosen ABSENT
// from `a ∪ b ∪ c` to pin the SET-STR-MISSING drift mode.
assert_str_finite_set_covered_by_three_str_arrays::<1, 1, 1, 2>(
&["a"],
&["b"],
&["c"],
&["a", "z"],
);
}
#[test]
#[should_panic(expected = "SET-STR-MISSING")]
fn assert_str_finite_set_covered_by_three_str_arrays_panics_at_runtime_on_terminal_uncovered_parent_entry(
) {
// NEGATIVE PIN — terminal-position drift: an uncovered entry
// at the LAST parent position MUST panic — pins that the
// outer `while w < W` loop reaches `w = W - 1` (else the
// terminal drift would slip through). A regression that
// narrowed the outer sweep to `while w < W - 1` (off-by-one
// on the OUTER bound) would silently accept this parent set
// even though the trailing `"z"` is uncovered.
assert_str_finite_set_covered_by_three_str_arrays::<1, 1, 1, 4>(
&["a"],
&["b"],
&["c"],
&["a", "b", "c", "z"],
);
}
#[test]
fn assert_str_finite_set_covered_by_three_str_arrays_panic_message_names_the_helper_and_set_str_missing_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — SET-STR-MISSING arm: the
// panic message MUST begin with the helper's own name AND
// identify the failed AXIS as "SET-STR-MISSING" so downstream
// diagnostics route the drift back to (a) the helper by
// string search on
// `"assert_str_finite_set_covered_by_three_str_arrays"` and
// (b) the axis by string search on `"SET-STR-MISSING"`.
// Sibling posture to
// `assert_str_array_within_str_finite_set_panic_message_names_the_helper_and_str_subset_violation_axis`
// on the sibling (str)-row SUBSET-VIOLATION provenance pin
// AND to the (u8) row-dual peer's `"SET-BYTE-MISSING"` axis
// vocabulary on `assert_u8_array_covers_finite_set` — the
// element-type infix `"STR"` vs `"BYTE"` disambiguates the
// element-type peer while the shared `"SET-…-MISSING"` suffix
// lets callers grep any row's COVERAGE-side SET-MISSING
// sibling by the shared suffix pattern alone.
let outcome = std::panic::catch_unwind(|| {
assert_str_finite_set_covered_by_three_str_arrays::<1, 1, 1, 2>(
&["a"],
&["b"],
&["c"],
&["a", "z"],
);
});
let payload = outcome.expect_err(
"assert_str_finite_set_covered_by_three_str_arrays must \
panic on an uncovered parent entry — the reject-uncovered \
arm is the sole SET-STR-MISSING failure mode of the \
helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_finite_set_covered_by_three_str_arrays \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_str_finite_set_covered_by_three_str_arrays"),
"assert_str_finite_set_covered_by_three_str_arrays panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("SET-STR-MISSING"),
"assert_str_finite_set_covered_by_three_str_arrays panic \
message {msg:?} must name the failed AXIS (\"SET-STR-\
MISSING\") for axis-provenance-preserving failure \
diagnostics",
);
}
#[test]
#[should_panic(expected = "assert_str_array_pairwise_distinct")]
fn assert_str_finite_set_covered_by_three_str_arrays_panics_on_malformed_target_set_spec() {
// NEGATIVE PIN — DELEGATED SET-side well-formedness: a
// malformed parent-set spec `["a", "a", "b"]` fed into the
// COVERAGE helper MUST panic on the DELEGATED pairwise-
// distinct arm BEFORE the SET-STR-MISSING arm fires. Pins the
// delegation chain: a regression that dropped the
// `assert_str_array_pairwise_distinct(set)` call at the top
// of `assert_str_finite_set_covered_by_three_str_arrays`
// would silently accept a malformed parent set with duplicate
// entries (the duplicated byte counts as covered on the first
// hit even when the second copy is absent from `a ∪ b ∪ c`).
// The panic message surfaces from the sibling ARRAY-side
// pairwise-distinct helper directly (containing its
// `"assert_str_array_pairwise_distinct"` panic-name prefix)
// because the (str) row does NOT carry a separate
// `assert_str_finite_set_pairwise_distinct` alias — the
// delegation reuses the ARRAY-side helper per the design
// choice documented on the SET-side well-formedness section
// of the helper's docstring.
assert_str_finite_set_covered_by_three_str_arrays::<1, 1, 1, 3>(
&["a"],
&["b"],
&["c"],
&["a", "a", "b"],
);
}
// ── `assert_str_array_is_concatenation_of_two_scalar_replicas` —
// the MANY-TO-ONE-BLOCK-CONSTANCY sibling of the INJECTIVITY
// sibling on the (`&'static str`) row of the (element-type ×
// contract-shape) matrix. Sibling posture: symmetric runtime-test
// surface (accept-two-block-partition, accept-K-zero-degenerate,
// accept-K-equals-N-degenerate, accept-empty-array, accept-
// compiler-spec-io-stage-operations-partition, reject-head-drift,
// reject-tail-drift, reject-arity-slip, panic-message-provenance)
// specialised to the MANY-TO-ONE block-constant projection shape.
// A regression that silently weakens the helper (e.g. flipping
// `str_bytes_equal` to `!str_bytes_equal`, narrowing the outer
// sweep to `while i < K - 1` on the HEAD segment, silently
// skipping the TAIL segment, or returning early past the
// CARDINALITY-MISMATCH gate) is caught by the helper's OWN test
// surface rather than only surfacing as a false-positive on the
// `CompilerSpecIoStage::OPERATIONS` witness.
#[test]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_accepts_the_two_block_partition() {
// Canonical two-block partition `[head; K] ++ [tail; N - K]`
// at the substrate's ONE non-injective per-index projection
// array `CompilerSpecIoStage::OPERATIONS` — the `(N, K) =
// (4, 2)` corner with `(head, tail) = (REALIZE_TO_DISK,
// LOAD_FROM_DISK)` MUST pass. Cross-partition coverage on
// arities (3, 1), (4, 2), (5, 3) pins the INNER `while i < K`
// and `while j < N` sweeps proceed through EACH position of
// BOTH segments rather than short-circuiting on ANY early
// position.
assert_str_array_is_concatenation_of_two_scalar_replicas::<3, 1>(
&["a", "b", "b"],
"a",
"b",
);
assert_str_array_is_concatenation_of_two_scalar_replicas::<4, 2>(
&["a", "a", "b", "b"],
"a",
"b",
);
assert_str_array_is_concatenation_of_two_scalar_replicas::<5, 3>(
&["a", "a", "a", "b", "b"],
"a",
"b",
);
}
#[test]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_accepts_the_k_zero_all_tail_degenerate(
) {
// Degenerate `K = 0` corner collapses the array into the ALL-
// TAIL replica `arr == [tail; N]`. The HEAD segment is empty
// (`while i < 0` never enters); the TAIL segment covers
// positions `[0, N)`. Cross-arity coverage on the `K = 0`
// axis pins the HEAD-segment sweep's outer `while i < K`
// terminates at `i = 0` when `K = 0`, and the TAIL-segment
// sweep's outer `while j < N` starts at `j = K = 0` and
// proceeds through EVERY position. A regression that hard-
// coded `K > 0` or short-circuited on the empty HEAD-segment
// arm would silently reject this legal degenerate shape.
assert_str_array_is_concatenation_of_two_scalar_replicas::<3, 0>(
&["x", "x", "x"],
"unused",
"x",
);
}
#[test]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_accepts_the_k_equals_n_all_head_degenerate(
) {
// Degenerate `K = N` corner collapses the array into the ALL-
// HEAD replica `arr == [head; N]`. The HEAD segment covers
// positions `[0, N)`; the TAIL segment is empty (`while j <
// N` starts at `j = K = N` and never enters). Peer to the
// `K = 0` degenerate corner — together the two corners pin
// the ONE-BLOCK degenerate shapes on BOTH endpoints of the
// `K ∈ [0, N]` const-generic range. A regression that hard-
// coded `K < N` or short-circuited on the empty TAIL-segment
// arm would silently reject this legal degenerate shape.
assert_str_array_is_concatenation_of_two_scalar_replicas::<3, 3>(
&["x", "x", "x"],
"x",
"unused",
);
}
#[test]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_accepts_the_empty_array() {
// Trivial `N = 0, K = 0` corner: the empty array trivially
// satisfies BOTH the empty HEAD segment `[head; 0]` and the
// empty TAIL segment `[tail; 0]`. Pins that the vacuous case
// on the `[&'static str; 0]` corner of the const-N generic
// passes without either segment sweep entering. Turbofish
// binding required because there's no cue for the const
// parameters on the empty array literal.
assert_str_array_is_concatenation_of_two_scalar_replicas::<0, 0>(
&[],
"unused-head",
"unused-tail",
);
}
#[test]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_accepts_head_equals_tail_single_block(
) {
// Corner where `head == tail` collapses the two-block
// partition into a SINGLE-BLOCK replica: `arr == [head; N] ==
// [tail; N]`. The partition boundary `K` is irrelevant to the
// observable byte-shape when `head` and `tail` are byte-
// equal, so ANY `K ∈ [0, N]` accepts. Pins the docstring
// note "the two scalars `head` and `tail` MAY be byte-equal
// (in which case the helper degenerates to a SINGLE-BLOCK
// replica-check)". Cross-K coverage inside `N = 4`: K = 0
// (empty HEAD), K = 2 (interior split), K = 4 (empty TAIL).
assert_str_array_is_concatenation_of_two_scalar_replicas::<4, 0>(
&["z", "z", "z", "z"],
"z",
"z",
);
assert_str_array_is_concatenation_of_two_scalar_replicas::<4, 2>(
&["z", "z", "z", "z"],
"z",
"z",
);
assert_str_array_is_concatenation_of_two_scalar_replicas::<4, 4>(
&["z", "z", "z", "z"],
"z",
"z",
);
}
#[test]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_accepts_compiler_spec_io_stage_operations_partition(
) {
// Runtime cross-check that the substrate's ONE non-injective
// per-index projection array `CompilerSpecIoStage::OPERATIONS`
// — the `(N, K) = (4, 2)` corner with `(head, tail) =
// (REALIZE_TO_DISK_OPERATION, LOAD_FROM_DISK_OPERATION)` —
// the substrate's module-level `const _` witness at `error.rs`
// pins at COMPILE time is a well-formed BLOCK-CONSTANCY
// relation at runtime too. The pair enforces the theorem at
// TWO stages of the toolchain: the const witness fires FIRST
// at `cargo check`, this runtime pin catches the drift at
// `cargo test` as a safety net. Sibling posture to
// `compiler_spec_io_stage_operations_align_with_all_by_index`
// (which pins per-position equality via `stage.operation()`
// at runtime) and to
// `compiler_spec_io_stage_operations_partition_all_two_ways`
// (which pins the two operation-label multiplicities at
// runtime) — this witness carries the SAME theorem at the
// ARRAY-LEVEL block-constant shape at COMPILE time.
assert_str_array_is_concatenation_of_two_scalar_replicas::<4, 2>(
&crate::error::CompilerSpecIoStage::OPERATIONS,
crate::error::CompilerSpecIoStage::REALIZE_TO_DISK_OPERATION,
crate::error::CompilerSpecIoStage::LOAD_FROM_DISK_OPERATION,
);
}
#[test]
#[should_panic(expected = "HEAD-SEGMENT-BLOCK-CONSTANCY-VIOLATION")]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_panics_at_runtime_on_head_segment_drift(
) {
// NEGATIVE PIN — HEAD-SEGMENT-BLOCK-CONSTANCY-VIOLATION
// corner: an entry in the HEAD segment `arr[0..K)` that does
// NOT byte-equal `head` MUST panic at runtime with the HEAD-
// segment-named message. Pins the helper's HEAD-segment
// reject arm — a regression that silently short-circuited on
// the first HEAD position without checking the middle or
// terminal HEAD positions would slip through the compile-
// time witness's failure mode too. The offending str "x" at
// position 1 (interior HEAD) pins the middle-of-HEAD drift
// mode. `K = 3, N = 5` so the HEAD segment spans positions
// `[0, 3)` — the interior drift at position 1 is inside the
// HEAD, not the TAIL boundary.
assert_str_array_is_concatenation_of_two_scalar_replicas::<5, 3>(
&["a", "x", "a", "b", "b"],
"a",
"b",
);
}
#[test]
#[should_panic(expected = "TAIL-SEGMENT-BLOCK-CONSTANCY-VIOLATION")]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_panics_at_runtime_on_tail_segment_drift(
) {
// NEGATIVE PIN — TAIL-SEGMENT-BLOCK-CONSTANCY-VIOLATION
// corner: an entry in the TAIL segment `arr[K..N)` that does
// NOT byte-equal `tail` MUST panic at runtime with the TAIL-
// segment-named message. Peer to the HEAD-segment drift arm
// above — the SAME helper, DIFFERENT segment arm. Pins that
// the outer `while j < N` sweep on the TAIL segment reaches
// `j = N - 1` (else the terminal drift would slip through).
// The offending str "x" at position 4 (terminal TAIL) with
// `K = 3, N = 5` pins the terminal-TAIL drift mode.
assert_str_array_is_concatenation_of_two_scalar_replicas::<5, 3>(
&["a", "a", "a", "b", "x"],
"a",
"b",
);
}
#[test]
#[should_panic(expected = "CARDINALITY-MISMATCH")]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_panics_at_runtime_on_arity_slip() {
// NEGATIVE PIN — CARDINALITY-MISMATCH gate: a caller-side
// turbofish arity slip on the `K` const-generic where `K > N`
// MUST panic at runtime with the CARDINALITY-MISMATCH-named
// message BEFORE any per-position sweep begins. Pins the
// gate's placement at the TOP of the helper — a regression
// that dropped the gate would silently degenerate into a
// truncated HEAD-only sweep at the caller's `K` cap without
// ever entering the TAIL sweep, silently accepting an array
// whose TAIL positions carry arbitrary drift. The offending
// `K = 5` against `N = 3` pins the strict `K > N` reject
// arm; the LEGAL `K == N` degenerate is covered by a peer
// acceptance test above.
assert_str_array_is_concatenation_of_two_scalar_replicas::<3, 5>(
&["a", "a", "a"],
"a",
"b",
);
}
#[test]
fn assert_str_array_is_concatenation_of_two_scalar_replicas_panic_message_names_the_helper_and_block_constancy_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — HEAD-SEGMENT-BLOCK-
// CONSTANCY-VIOLATION arm: the panic message MUST begin with
// the helper's own name AND identify the failed AXIS as
// "HEAD-SEGMENT-BLOCK-CONSTANCY-VIOLATION" so downstream
// diagnostics route the drift back to (a) the helper by
// string search on
// `"assert_str_array_is_concatenation_of_two_scalar_replicas"`
// and (b) the segment + axis by string search on
// `"HEAD-SEGMENT-BLOCK-CONSTANCY-VIOLATION"`. Sibling posture
// to `assert_str_array_pairwise_distinct_panic_message_...`
// on the sibling (str)-row INJECTIVITY provenance pin AND to
// the sibling ROW-DUAL `_covered_by_three_str_arrays`'s
// `"SET-STR-MISSING"` axis vocabulary — the shared
// `"BLOCK-CONSTANCY-VIOLATION"` suffix lets callers grep
// either the HEAD or TAIL segment arm by the shared suffix
// pattern alone, while the `HEAD-` / `TAIL-` prefix
// disambiguates the SEGMENT.
let outcome = std::panic::catch_unwind(|| {
assert_str_array_is_concatenation_of_two_scalar_replicas::<3, 2>(
&["a", "x", "b"],
"a",
"b",
);
});
let payload = outcome.expect_err(
"assert_str_array_is_concatenation_of_two_scalar_replicas \
must panic on a HEAD-segment drift — the reject-HEAD-drift \
arm is one of the two BLOCK-CONSTANCY-VIOLATION failure \
modes of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_str_array_is_concatenation_of_two_scalar_replicas \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_str_array_is_concatenation_of_two_scalar_replicas"),
"assert_str_array_is_concatenation_of_two_scalar_replicas \
panic message {msg:?} must name the helper for \
provenance-preserving failure diagnostics",
);
assert!(
msg.contains("HEAD-SEGMENT-BLOCK-CONSTANCY-VIOLATION"),
"assert_str_array_is_concatenation_of_two_scalar_replicas \
panic message {msg:?} must name the failed AXIS (\"HEAD-\
SEGMENT-BLOCK-CONSTANCY-VIOLATION\") for axis-provenance-\
preserving failure diagnostics",
);
}
// ── `assert_u8_array_slice_is_scalar_replica` — the (`u8`)-row
// SLICE-BLOCK-CONSTANCY sibling of the (`&'static str`)-row FULL-
// ARRAY-two-block-partition sibling
// `assert_str_array_is_concatenation_of_two_scalar_replicas`.
// Sibling posture: symmetric runtime-test surface (accept-canonical-
// slice, accept-empty-slice-corners, accept-full-array-degenerate,
// accept-sexp-shape-atomic-collapse, reject-slice-content-drift,
// reject-start-out-of-bounds, reject-end-out-of-bounds, reject-
// inverted-range, panic-message-provenance) specialised to the (u8)
// sub-slice SINGLE-scalar block-constant shape. A regression that
// silently weakens the helper (e.g. flipping `arr[i] != scalar`
// to `==`, moving the START gate BELOW the sweep, narrowing the
// sweep to `while i < END - 1` and missing the terminal position,
// or returning early past ANY bounds gate) is caught by the
// helper's OWN test surface rather than only surfacing as a false-
// positive on the `SexpShape::HASH_DISCRIMINATORS[1..7)` witness.
#[test]
fn assert_u8_array_slice_is_scalar_replica_accepts_a_canonical_middle_slice() {
// Canonical sub-slice `arr[START..END) == [scalar; END - START]`
// inside a longer array `arr` whose ENDPOINTS carry DIFFERENT
// bytes than the slice. Pins the outer `while i < END` sweep
// enters at `i = START` (skipping positions `[0..START)`) AND
// terminates at `i = END` (skipping positions `[END..N)`) —
// BOTH endpoint bytes DIFFER from `scalar` so a regression
// that widened the sweep beyond the slice would fail here.
assert_u8_array_slice_is_scalar_replica::<7, 1, 6>(&[9, 1, 1, 1, 1, 1, 9], 1);
}
#[test]
fn assert_u8_array_slice_is_scalar_replica_accepts_the_empty_slice_at_start_equals_end() {
// LEGAL degenerate: `START == END` collapses the slice into an
// empty range `[START..START)`. The sweep never enters the
// loop body and the helper accepts. Cross-position coverage
// pins the empty-slice acceptance at THREE distinct positions
// (`START == 0` at the left endpoint, `START == 3` in the
// interior, `START == N` at the right endpoint) so a
// regression that hard-coded `START < END` OR panicked on the
// `START == END` corner is caught on ALL THREE arms. Peer to
// the `K == N` / `K == 0` degenerate corners of the sibling
// `assert_str_array_is_concatenation_of_two_scalar_replicas`.
assert_u8_array_slice_is_scalar_replica::<5, 0, 0>(&[7, 7, 7, 7, 7], 42);
assert_u8_array_slice_is_scalar_replica::<5, 3, 3>(&[7, 7, 7, 7, 7], 42);
assert_u8_array_slice_is_scalar_replica::<5, 5, 5>(&[7, 7, 7, 7, 7], 42);
}
#[test]
fn assert_u8_array_slice_is_scalar_replica_accepts_the_full_array_slice() {
// Full-array-covering slice `[0..N)` collapses to the ALL-
// scalar-replica shape `arr == [scalar; N]` (peer to the
// `K == N` degenerate of the sibling str-row helper). Pins
// that the sweep proceeds through EVERY position of the array
// when `START = 0` and `END = N`. Cross-arity coverage on
// `N ∈ {3, 6, 8}` pins the sweep's terminal-position visit
// across a range of array cardinalities.
assert_u8_array_slice_is_scalar_replica::<3, 0, 3>(&[5, 5, 5], 5);
assert_u8_array_slice_is_scalar_replica::<6, 0, 6>(&[0, 0, 0, 0, 0, 0], 0);
assert_u8_array_slice_is_scalar_replica::<8, 0, 8>(
&[255, 255, 255, 255, 255, 255, 255, 255],
255,
);
}
#[test]
fn assert_u8_array_slice_is_scalar_replica_accepts_sexp_shape_atomic_collapse_slice() {
// Runtime cross-check that the substrate's ONE MANY-TO-ONE-
// COLLAPSE `[u8; N]` sub-slice `SexpShape::HASH_DISCRIMINATORS
// [1..7)` — the six-slot atomic-outer-shape collapse onto
// `AtomKind::OUTER_HASH_DISCRIMINATOR` — the substrate's
// module-level `const _` witness at `ast.rs` pins at COMPILE
// time is a well-formed SLICE-BLOCK-CONSTANCY relation at
// runtime too. The pair enforces the theorem at TWO stages of
// the toolchain: the const witness fires FIRST at `cargo
// check`, this runtime pin catches the drift at `cargo test`
// as a safety net. Sibling posture to the peer runtime cross-
// check on the sibling
// `assert_str_array_is_concatenation_of_two_scalar_replicas_accepts_compiler_spec_io_stage_operations_partition`
// — this witness carries the SAME class of MANY-TO-ONE-
// COLLAPSE theorem at the ARRAY-slice level on the (u8) row
// rather than the FULL-ARRAY-two-block level on the (str) row.
assert_u8_array_slice_is_scalar_replica::<12, 1, 7>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
AtomKind::OUTER_HASH_DISCRIMINATOR,
);
}
#[test]
#[should_panic(expected = "SLICE-BLOCK-CONSTANCY-VIOLATION")]
fn assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_slice_content_drift() {
// NEGATIVE PIN — SLICE-BLOCK-CONSTANCY-VIOLATION corner: an
// entry in the slice `arr[START..END)` that does NOT byte-
// equal `scalar` MUST panic at runtime with the slice-named
// message. Pins the helper's slice-content reject arm — a
// regression that silently short-circuited on the first slice
// position without checking the middle or terminal slice
// positions would slip through the compile-time witness's
// failure mode too. The offending byte `9` at position `3`
// (interior of the slice) with `START = 1, END = 6` pins the
// middle-of-slice drift mode.
assert_u8_array_slice_is_scalar_replica::<7, 1, 6>(&[0, 1, 1, 9, 1, 1, 0], 1);
}
#[test]
#[should_panic(expected = "START-OUT-OF-BOUNDS")]
fn assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_start_out_of_bounds() {
// NEGATIVE PIN — START-OUT-OF-BOUNDS gate: a caller-side
// turbofish arity slip on the `START` const-generic where
// `START > N` MUST panic at runtime with the START-OUT-OF-
// BOUNDS-named message BEFORE any per-position sweep begins.
// Pins the gate's placement at the TOP of the helper — a
// regression that dropped the gate would either silently
// degenerate into a vacuous sweep OR panic deeper in `arr[i]`
// bounds-checking with a helper-name-less panic message. The
// offending `START = 7` against `N = 5` pins the strict
// `START > N` reject arm; the LEGAL `START == N` empty
// corner is covered by the peer acceptance test above.
assert_u8_array_slice_is_scalar_replica::<5, 7, 7>(&[1, 1, 1, 1, 1], 1);
}
#[test]
#[should_panic(expected = "END-OUT-OF-BOUNDS")]
fn assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_end_out_of_bounds() {
// NEGATIVE PIN — END-OUT-OF-BOUNDS gate: a caller-side
// turbofish arity slip on the `END` const-generic where
// `END > N` MUST panic at runtime with the END-OUT-OF-BOUNDS-
// named message. Peer to the START-OUT-OF-BOUNDS arm above —
// the two gates jointly enforce `START, END ∈ [0..N]` before
// any content sweep. The offending `END = 9` against `N = 5`
// pins the strict `END > N` reject arm; the LEGAL `END == N`
// slice-to-end corner is covered by the full-array acceptance
// test above. `START = 0` sits in-bounds so the START gate
// does not fire first.
assert_u8_array_slice_is_scalar_replica::<5, 0, 9>(&[1, 1, 1, 1, 1], 1);
}
#[test]
#[should_panic(expected = "INVERTED-RANGE")]
fn assert_u8_array_slice_is_scalar_replica_panics_at_runtime_on_inverted_range() {
// NEGATIVE PIN — INVERTED-RANGE gate: a caller-side turbofish
// typo that swaps `START` and `END` (both individually in-
// bounds, but `START > END`) MUST panic at runtime with the
// INVERTED-RANGE-named message. Pins that the strict `START
// > END` slip fails-loud on a DISTINCT axis rather than
// silently accepting the empty sweep — a regression that
// dropped this gate would silently accept ANY array on the
// swapped-turbofish call site. The offending `START = 5,
// END = 2` against `N = 7` pins the strict `START > END`
// reject arm; the LEGAL `START == END` empty corner is
// covered by the peer acceptance test above.
assert_u8_array_slice_is_scalar_replica::<7, 5, 2>(&[1, 1, 1, 1, 1, 1, 1], 1);
}
#[test]
fn assert_u8_array_slice_is_scalar_replica_panic_message_names_the_helper_and_slice_block_constancy_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — SLICE-BLOCK-CONSTANCY-
// VIOLATION arm: the panic message MUST begin with the
// helper's own name AND identify the failed AXIS as "SLICE-
// BLOCK-CONSTANCY-VIOLATION" so downstream diagnostics route
// the drift back to (a) the helper by string search on
// `"assert_u8_array_slice_is_scalar_replica"` and (b) the
// failed axis by string search on `"SLICE-BLOCK-CONSTANCY-
// VIOLATION"`. Sibling posture to
// `assert_str_array_is_concatenation_of_two_scalar_replicas_panic_message_...`
// on the sibling (str)-row FULL-ARRAY BLOCK-CONSTANCY
// provenance pin — the shared `"BLOCK-CONSTANCY-VIOLATION"`
// suffix lets callers grep either the SUB-SLICE or FULL-
// ARRAY variant by the shared suffix pattern alone, while
// the `SLICE-` / `HEAD-SEGMENT-` / `TAIL-SEGMENT-` prefix
// disambiguates the CONTRACT SHAPE.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_slice_is_scalar_replica::<5, 1, 4>(&[0, 1, 9, 1, 0], 1);
});
let payload = outcome.expect_err(
"assert_u8_array_slice_is_scalar_replica must panic on a \
slice-content drift — the reject-slice-drift arm is the \
CONTENT failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_slice_is_scalar_replica panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_slice_is_scalar_replica"),
"assert_u8_array_slice_is_scalar_replica panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("SLICE-BLOCK-CONSTANCY-VIOLATION"),
"assert_u8_array_slice_is_scalar_replica panic message \
{msg:?} must name the failed AXIS (\"SLICE-BLOCK-\
CONSTANCY-VIOLATION\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_u8_array_slice_equals_u8_array` — the SLICE-EQUALS-
// ARRAY sibling of `assert_u8_array_slice_is_scalar_replica` on
// the SAME (u8) row. Sibling posture: same runtime-test surface
// (accept-canonical-middle-slice, accept-empty-sub-array, accept-
// full-array-degenerate, accept-sexp-shape-quote-tail-composition,
// reject-positionwise-drift, reject-start-out-of-bounds, reject-
// slice-length-out-of-bounds, panic-message-provenance)
// specialised to the (u8) SUB-SLICE ARRAY-image composition shape.
// A regression that silently weakens the helper (e.g. flipping
// `full[START + i] != sub[i]` to `==`, dropping the `START`
// offset from the outer read, moving the START gate BELOW the
// sweep, narrowing the sweep to `while i < M - 1` and missing
// the terminal position, or returning early past ANY bounds gate)
// is caught by the helper's OWN test surface rather than only
// surfacing as a false-positive on the
// `SexpShape::HASH_DISCRIMINATORS[8..12] ==
// QuoteForm::HASH_DISCRIMINATORS` witness.
#[test]
fn assert_u8_array_slice_equals_u8_array_accepts_a_canonical_middle_slice() {
// Canonical sub-slice `full[START..START + M) == sub[..]`
// inside a longer array `full` whose ENDPOINTS carry
// DIFFERENT bytes than the peer sub-array. Pins the outer
// `while i < M` sweep reads `full[START + i]` at the
// OFFSET position (not `full[i]`) — a regression that
// dropped the `START` offset would compare `full[0..M)`
// against `sub[..]` and pass on `full[0]=9 != sub[0]=1`
// silently or panic on the wrong axis. `START = 1` pins
// the sweep skips position `[0..START)` and reads only
// `[1..1+3) = [1..4)`.
assert_u8_array_slice_equals_u8_array::<7, 3, 1>(&[9, 3, 4, 5, 9, 9, 9], &[3, 4, 5]);
}
#[test]
fn assert_u8_array_slice_equals_u8_array_accepts_the_empty_sub_array() {
// LEGAL degenerate: `M == 0` collapses the sub-array into
// an empty listing `[]`. The sweep never enters the loop
// body and the helper accepts. Cross-position coverage
// pins the empty-sub-array acceptance at THREE distinct
// `START` positions (`START == 0` at the left endpoint,
// `START == 3` in the interior, `START == N` at the right
// endpoint — the latter is the corner `START == N` combined
// with `M == 0` that the START-OUT-OF-BOUNDS gate's
// inclusive upper bound must accept). A regression that
// hard-coded `START < N` OR panicked on the `M == 0` corner
// is caught on ALL THREE arms.
assert_u8_array_slice_equals_u8_array::<5, 0, 0>(&[7, 7, 7, 7, 7], &[]);
assert_u8_array_slice_equals_u8_array::<5, 0, 3>(&[7, 7, 7, 7, 7], &[]);
assert_u8_array_slice_equals_u8_array::<5, 0, 5>(&[7, 7, 7, 7, 7], &[]);
}
#[test]
fn assert_u8_array_slice_equals_u8_array_accepts_the_full_array_degenerate() {
// Full-array-covering slice `M == N, START == 0` collapses
// to the ALL-positions-equal-peer-array shape `full == sub`
// pointwise. Pins that the sweep proceeds through EVERY
// position of the outer array when `START = 0` and `M = N`.
// Cross-arity coverage on `N ∈ {3, 4, 6}` pins the sweep's
// terminal-position visit across a range of array
// cardinalities.
assert_u8_array_slice_equals_u8_array::<3, 3, 0>(&[10, 20, 30], &[10, 20, 30]);
assert_u8_array_slice_equals_u8_array::<4, 4, 0>(&[3, 4, 5, 6], &[3, 4, 5, 6]);
assert_u8_array_slice_equals_u8_array::<6, 6, 0>(&[0, 1, 2, 3, 4, 5], &[0, 1, 2, 3, 4, 5]);
}
#[test]
fn assert_u8_array_slice_equals_u8_array_accepts_sexp_shape_quote_tail_composition() {
// Runtime cross-check that the substrate's ONE
// POSITIONWISE-COMPOSITION `[u8; N]` sub-slice
// `SexpShape::HASH_DISCRIMINATORS[8..12]` byte-for-byte
// equal to the peer `QuoteForm::HASH_DISCRIMINATORS` is a
// well-formed SLICE-EQUALS-ARRAY relation at runtime too.
// The pair enforces the theorem at TWO stages of the
// toolchain: the const witness fires FIRST at `cargo
// check`, this runtime pin catches the drift at `cargo
// test` as a safety net. Sibling posture to the peer
// runtime cross-check
// `assert_u8_array_slice_is_scalar_replica_accepts_sexp_shape_atomic_collapse_slice`
// — this witness carries the SLICE-EQUALS-ARRAY theorem
// (positionwise composition with a peer array of arity
// `M`) on the SAME (u8) row's quote-family tail slice
// rather than the MANY-TO-ONE-COLLAPSE theorem
// (positionwise composition with a SCALAR) on the atomic-
// collapse mid slice.
assert_u8_array_slice_equals_u8_array::<12, 4, 8>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
}
#[test]
fn assert_u8_array_slice_equals_u8_array_accepts_sub_carving_hash_discriminators_per_position_order(
) {
// Runtime cross-check that the FOUR sub-carving
// `HASH_DISCRIMINATORS` arrays each byte-equal their
// canonical literal-byte listing pointwise at the FULL-ARRAY
// corner (`M == N`, `START == 0`). Runs the SAME helper the
// four `const _` witnesses above line 5842 in this file run
// at rustc time — a runtime safety net enforcing the
// theorem at BOTH stages of the toolchain (const at `cargo
// check`, runtime at `cargo test`). A regression that
// renamed one of the per-role `*_HASH_DISCRIMINATOR` aliases
// (or drifted its literal byte value at the declaration
// site, or reordered a slot in the outer array's
// initializer) fails HERE at the substrate callsite AND at
// the const witness above. Peer of
// `assert_u8_array_slice_equals_u8_array_accepts_sexp_shape_quote_tail_composition`
// above — that witness carries the SLICE-EQUALS-ARRAY
// theorem for the OUTER container against a SUB-CARVING
// array; this witness carries the theorem for each of the
// FOUR sub-carving arrays against a literal-byte listing.
//
// The four sub-carvings appear here in canonical order
// (`{0..=6}` outer-`Sexp` cache-key partition, top-to-
// bottom):
// * `StructuralKind::HASH_DISCRIMINATORS == [0u8, 2]` — the
// structural-residual carving. Non-contiguous (gap at
// `1u8` reserved for the atomic-carve outer marker).
// * `AtomKind::HASH_DISCRIMINATORS == [0u8, 1, 2, 3, 4, 5]`
// — the nested-inner atomic-payload carving specialising
// the outer `1u8` atomic marker inside `Hash for Atom`.
// * `QuoteForm::HASH_DISCRIMINATORS == [3u8, 4, 5, 6]` —
// the quote-family carving covering the four homoiconic
// prefixes.
// * `UnquoteForm::HASH_DISCRIMINATORS == [5u8, 6]` — the
// two-of-four substitution subset of `QuoteForm`
// projecting through `to_quote_form()`.
assert_u8_array_slice_equals_u8_array::<2, 2, 0>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&[0u8, 2],
);
assert_u8_array_slice_equals_u8_array::<6, 6, 0>(
&AtomKind::HASH_DISCRIMINATORS,
&[0u8, 1, 2, 3, 4, 5],
);
assert_u8_array_slice_equals_u8_array::<4, 4, 0>(
&QuoteForm::HASH_DISCRIMINATORS,
&[3u8, 4, 5, 6],
);
assert_u8_array_slice_equals_u8_array::<2, 2, 0>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
&[5u8, 6],
);
}
/// Runtime SLICE-EQUALS-ARRAY safety net for the (UnquoteForm ⊂
/// QuoteForm) 2-of-4 sub-carve on the (u8) HASH_DISCRIMINATORS
/// vocabulary axis — mirrors the module-level `const _: () =
/// assert_u8_array_slice_equals_u8_array::<4, 2, 2>(&QuoteForm::
/// HASH_DISCRIMINATORS, &UnquoteForm::HASH_DISCRIMINATORS)` witness
/// added below line 5617 in this file. The `const _` witness fires
/// FIRST at `cargo check`; this runtime pin catches the ARRAY-LEVEL
/// positionwise drift at `cargo test` as a safety net enforcing the
/// theorem at BOTH stages of the toolchain.
///
/// (U8)-row peer to `assert_str_array_slice_equals_str_array_
/// accepts_unquote_form_sub_carve_of_quote_form` at `error.rs`'s
/// tests submodule — that test sweeps the SAME 2-of-4 sub-carve at
/// the (str) row across three vocabulary axes (`LABELS`,
/// `MARKERS↔PREFIXES`, `IAC_FORGE_TAGS`); this test sweeps the same
/// carve at the (u8) row on the ONE `HASH_DISCRIMINATORS` axis.
/// Together the four runtime witnesses close the (element-type ×
/// vocabulary-axis) matrix of the substitution-subset carve at the
/// SLICE-EQUALS positionwise-composition contract, on the runtime-
/// pin sibling face of the four-witness compile-time cluster.
///
/// A regression that (a) swaps `UnquoteForm::HASH_DISCRIMINATORS`
/// from `[UNQUOTE_HASH_DISCRIMINATOR, SPLICE_HASH_DISCRIMINATOR]`
/// to `[SPLICE_HASH_DISCRIMINATOR, UNQUOTE_HASH_DISCRIMINATOR]`, or
/// (b) reorders `QuoteForm::HASH_DISCRIMINATORS` such that the two
/// `UnquoteForm` bytes no longer sit contiguously at slots
/// `[2..4)`, fails HERE with the `SLICE-EQUALS-ARRAY-VIOLATION`
/// axis panic naming the drifted position — where the sibling
/// SET-level SUBSET safety-net stays silent (both bytes still
/// appear in the superset, just at different positions).
#[test]
fn assert_u8_array_slice_equals_u8_array_accepts_unquote_form_sub_carve_of_quote_form() {
assert_u8_array_slice_equals_u8_array::<4, 2, 2>(
&QuoteForm::HASH_DISCRIMINATORS,
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
);
}
#[test]
#[should_panic(expected = "SLICE-EQUALS-ARRAY-VIOLATION")]
fn assert_u8_array_slice_equals_u8_array_panics_at_runtime_on_positionwise_drift() {
// NEGATIVE PIN — SLICE-EQUALS-ARRAY-VIOLATION corner: a
// byte at some position in `full[START..START + M)` that
// does NOT byte-equal the peer sub-array `sub` at the
// offset-matched position MUST panic at runtime with the
// slice-named message. Pins the helper's positionwise-
// drift reject arm — a regression that silently short-
// circuited on the first slice position without checking
// the middle or terminal slice positions would slip
// through the compile-time witness's failure mode too.
// The offending byte `9` at outer position `3` (interior
// of the sub-slice `[1..4)`, offset `2` inside `sub`)
// pins the middle-of-slice drift mode.
assert_u8_array_slice_equals_u8_array::<5, 3, 1>(&[0, 3, 4, 9, 0], &[3, 4, 5]);
}
#[test]
#[should_panic(expected = "START-OUT-OF-BOUNDS")]
fn assert_u8_array_slice_equals_u8_array_panics_at_runtime_on_start_out_of_bounds() {
// NEGATIVE PIN — START-OUT-OF-BOUNDS gate: a caller-side
// turbofish arity slip on the `START` const-generic where
// `START > N` MUST panic at runtime with the START-OUT-OF-
// BOUNDS-named message BEFORE the peer SLICE-LENGTH-OUT-OF-
// BOUNDS gate reads `N - START` (which would `usize`-
// underflow had this gate not caught the slip first). Pins
// the gate's placement at the TOP of the helper — a
// regression that dropped the gate would either underflow
// subtraction at the peer gate OR panic deeper in
// `full[START + i]` bounds-checking with a helper-name-less
// panic message. The offending `START = 7` against `N = 5`
// pins the strict `START > N` reject arm; the LEGAL
// `START == N` empty-slice-at-right-endpoint corner is
// covered by the peer acceptance test above.
assert_u8_array_slice_equals_u8_array::<5, 0, 7>(&[1, 1, 1, 1, 1], &[]);
}
#[test]
#[should_panic(expected = "SLICE-LENGTH-OUT-OF-BOUNDS")]
fn assert_u8_array_slice_equals_u8_array_panics_at_runtime_on_slice_length_out_of_bounds() {
// NEGATIVE PIN — SLICE-LENGTH-OUT-OF-BOUNDS gate: a peer
// sub-array arity `M` that exceeds the outer array's tail
// cardinality `N - START` MUST panic at runtime with the
// slice-length-out-of-bounds-named message. Peer gate to
// the START-OUT-OF-BOUNDS arm above — the two gates
// jointly enforce `START ≤ N` and `M ≤ N - START` before
// any content sweep. The offending `M = 5` against
// `N - START = 5 - 3 = 2` pins the strict `M > N - START`
// reject arm; the LEGAL exact-fit corner `M == N - START`
// is covered by the middle-slice acceptance test above.
assert_u8_array_slice_equals_u8_array::<5, 5, 3>(&[1, 1, 1, 1, 1], &[1, 1, 1, 1, 1]);
}
#[test]
fn assert_u8_array_slice_equals_u8_array_panic_message_names_the_helper_and_slice_equals_array_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — SLICE-EQUALS-ARRAY-
// VIOLATION arm: the panic message MUST begin with the
// helper's own name AND identify the failed AXIS as
// "SLICE-EQUALS-ARRAY-VIOLATION" so downstream diagnostics
// route the drift back to (a) the helper by string search
// on `"assert_u8_array_slice_equals_u8_array"` and (b) the
// failed axis by string search on `"SLICE-EQUALS-ARRAY-
// VIOLATION"`. Sibling posture to
// `assert_u8_array_slice_is_scalar_replica_panic_message_names_the_helper_and_slice_block_constancy_violation_axis`
// on the sibling SLICE-BLOCK-CONSTANCY corner — the shared
// `"SLICE-"` prefix lets callers grep either the SINGLE-
// scalar-image or ARRAY-of-length-`M`-image variant by
// the shared prefix, while the `-BLOCK-CONSTANCY-` /
// `-EQUALS-ARRAY-` infix disambiguates the CONTRACT
// SHAPE.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_slice_equals_u8_array::<5, 3, 1>(&[0, 3, 4, 9, 0], &[3, 4, 5]);
});
let payload = outcome.expect_err(
"assert_u8_array_slice_equals_u8_array must panic on a \
positionwise drift — the reject-positionwise-drift arm \
is the CONTENT failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_slice_equals_u8_array panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_slice_equals_u8_array"),
"assert_u8_array_slice_equals_u8_array panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("SLICE-EQUALS-ARRAY-VIOLATION"),
"assert_u8_array_slice_equals_u8_array panic message \
{msg:?} must name the failed AXIS (\"SLICE-EQUALS-\
ARRAY-VIOLATION\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_u8_array_pairwise_distinct` — the `u8` element-type
// sibling of `assert_char_array_pairwise_distinct` and
// `assert_str_array_pairwise_distinct`. Sibling posture: same
// runtime-test surface (accept-empty, accept-singleton, accept-
// every-family-wide-substrate-array, reject-binary, reject-non-
// adjacent, reject-terminal, panic-message-provenance) restricted
// to the `u8` element type. A regression that silently weakens the
// helper (e.g. flipping `==` to `!=`, dropping the inner `j` loop,
// or returning early on collision) is caught by the helper's OWN
// test surface rather than only surfacing as a false-positive on
// some future `[u8; N]`-typed discriminator array's distinctness pin.
#[test]
fn assert_u8_array_pairwise_distinct_accepts_the_empty_array() {
// Empty array — vacuously pairwise distinct (no pair to
// collide). The compile-time `const _: () =
// assert_u8_array_pairwise_distinct(&EMPTY);` would land on
// this arm, so the runtime call MUST return normally.
assert_u8_array_pairwise_distinct::<0>(&[]);
}
#[test]
fn assert_u8_array_pairwise_distinct_accepts_singleton_arrays() {
// Singleton array — vacuously pairwise distinct (only one
// element, no pair). Cross-arity coverage on the `[u8; 1]`
// corner of the const-N generic.
assert_u8_array_pairwise_distinct(&[0u8]);
assert_u8_array_pairwise_distinct(&[AtomKind::SYMBOL_HASH_DISCRIMINATOR]);
}
#[test]
fn assert_u8_array_pairwise_distinct_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME four arrays the module-
// level `const _: () = ...` witnesses cover at COMPILE time
// are pairwise distinct. A regression that removes ONE of
// the `const _` witnesses would still leave THIS runtime pin
// as a safety net; the const witness fires FIRST at `cargo
// check`, this runtime pin catches the collision at `cargo
// test`. The pair enforces the theorem at TWO stages of the
// toolchain. `SexpShape::HASH_DISCRIMINATORS` is excluded
// per the intentionally-non-injective twelve-shape → seven-
// byte collapse rule documented on the helper.
assert_u8_array_pairwise_distinct(&AtomKind::HASH_DISCRIMINATORS);
assert_u8_array_pairwise_distinct(&QuoteForm::HASH_DISCRIMINATORS);
assert_u8_array_pairwise_distinct(&crate::error::StructuralKind::HASH_DISCRIMINATORS);
assert_u8_array_pairwise_distinct(&crate::error::UnquoteForm::HASH_DISCRIMINATORS);
}
#[test]
#[should_panic(expected = "assert_u8_array_pairwise_distinct")]
fn assert_u8_array_pairwise_distinct_panics_at_runtime_on_binary_collision() {
// NEGATIVE PIN — binary corner: a two-element array carrying
// the same byte twice MUST panic at runtime (the const-eval
// panic surfaces normally when the function is invoked from a
// runtime context, not just a `const _` context). Pins the
// helper's OWN reject-collision arm — a regression that
// silently returned without panicking on a duplicate would
// slip through the compile-time witnesses' failure mode too.
assert_u8_array_pairwise_distinct(&[0u8, 0u8]);
}
#[test]
#[should_panic(expected = "assert_u8_array_pairwise_distinct")]
fn assert_u8_array_pairwise_distinct_panics_at_runtime_on_non_adjacent_collision() {
// NEGATIVE PIN — non-adjacent corner: the collision fires on
// ANY (i, j) pair with i < j, not just the adjacent (0, 1)
// corner. Pins the nested-loop shape of the helper — a
// regression that walked ONLY the adjacent pairs (i.e., swept
// `while i + 1 < N { if arr[i] == arr[i+1] { panic } … }`)
// would silently accept `[0, 1, 0]` (non-adjacent collision
// at positions 0 and 2), missing the contract.
assert_u8_array_pairwise_distinct(&[0u8, 1u8, 0u8]);
}
#[test]
#[should_panic(expected = "assert_u8_array_pairwise_distinct")]
fn assert_u8_array_pairwise_distinct_panics_at_runtime_on_terminal_collision() {
// NEGATIVE PIN — terminal corner: the collision at the LAST
// pair (positions N-2 and N-1) MUST also fire. Pins the outer
// `while i < N` bound — a regression that walked `while i <
// N - 1` (dropping the last row) would silently accept a
// collision at the tail.
assert_u8_array_pairwise_distinct(&[0u8, 1u8, 2u8, 3u8, 3u8]);
}
#[test]
#[should_panic(expected = "assert_u8_array_pairwise_distinct")]
fn assert_u8_array_pairwise_distinct_panics_at_runtime_on_boundary_byte_collision() {
// NEGATIVE PIN — u8-domain boundary corner: the reject-arm
// fires equivalently at the two u8-domain endpoints (`0x00`,
// `0xff`). Pins the element-type-native `==` on `u8` — a
// regression that widened the comparison via `as u32` (from
// an over-mechanical copy of the char sibling's shape) or
// via a signed-cast (`as i8` collapsing `0xff` to `-1`)
// would still fire on the `0x00` corner AND on the
// `0xff` corner because both survive any widening; a truly
// load-bearing regression here would silently drop the
// comparison altogether.
assert_u8_array_pairwise_distinct(&[0xffu8, 0xffu8]);
}
#[test]
fn assert_u8_array_pairwise_distinct_panic_message_names_the_helper() {
// PANIC-MESSAGE PROVENANCE PIN: the panic message MUST begin
// with the helper's own name so downstream diagnostics
// (`cargo check` const-eval error output, test-suite failure
// reports) route the drift back to the helper by string
// search — the family-wide contract's failure mode surfaces
// as an identifiable panic-message prefix rather than as an
// opaque const-eval error. Sibling posture to the runtime
// pairwise-distinctness tests that name the ARRAY in their
// failure message; this pin names the HELPER.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_pairwise_distinct(&[7u8, 7u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_pairwise_distinct must panic on a \
duplicate — the reject-collision arm is the point of \
the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_pairwise_distinct panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_pairwise_distinct"),
"assert_u8_array_pairwise_distinct panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
}
// ── `assert_char_pair_array_bijective` — the product-element
// sibling of the three scalar-element `assert_{char,str,u8}_array_
// pairwise_distinct` compile-time contract verifiers, restricted
// to the `(char, char)` product element type at the paired
// escape-table substrate vocabulary (`Atom::NAMED_ESCAPE_TABLE`,
// `Atom::ESCAPE_TABLE`). The runtime test surface here matches
// the scalar-sibling shape (accept-empty, accept-singleton,
// accept-every-family-wide-substrate-array, reject-left-column-
// collision, reject-right-column-collision, reject-non-adjacent,
// reject-terminal, panic-message-provenance-left, panic-message-
// provenance-right) split across BOTH columns so a regression that
// silently weakens the helper on EITHER column (e.g. dropping ONE
// of the two `if arr[i].{0,1} == arr[j].{0,1}` checks, or
// conflating the two `panic!` calls into one column-anonymous
// message) is caught by the helper's OWN test surface rather than
// only surfacing as a false-positive on some future
// `[(char, char); N]`-typed paired array's bijection pin.
#[test]
fn assert_char_pair_array_bijective_accepts_the_empty_array() {
// Empty array — vacuously bijective (no pair to collide on
// EITHER column). The compile-time `const _: () =
// assert_char_pair_array_bijective(&EMPTY);` would land on
// this arm, so the runtime call MUST return normally.
assert_char_pair_array_bijective::<0>(&[]);
}
#[test]
fn assert_char_pair_array_bijective_accepts_singleton_arrays() {
// Singleton array — vacuously bijective (only one pair, so
// no cross-pair collision is possible on EITHER column even
// if the two components alias each other WITHIN the pair —
// that's not a bijection failure, it's the pattern-equals-
// value SELF-escape shape at `SELF_ESCAPE_TABLE`'s two rows).
// Cross-arity coverage on the `[(char, char); 1]` corner of
// the const-N generic.
assert_char_pair_array_bijective(&[('a', 'b')]);
assert_char_pair_array_bijective(&[('x', 'x')]);
}
#[test]
fn assert_char_pair_array_bijective_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME two paired arrays the
// module-level `const _: () = ...` witnesses cover at COMPILE
// time are bijective. A regression that removes ONE of the
// `const _` witnesses would still leave THIS runtime pin as a
// safety net; the const witness fires FIRST at `cargo check`,
// this runtime pin catches the collision at `cargo test`. The
// pair enforces the theorem at TWO stages of the toolchain.
assert_char_pair_array_bijective(&Atom::NAMED_ESCAPE_TABLE);
assert_char_pair_array_bijective(&Atom::ESCAPE_TABLE);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_bijective: LEFT column")]
fn assert_char_pair_array_bijective_panics_at_runtime_on_left_column_collision() {
// NEGATIVE PIN — LEFT-column corner: a two-element array
// whose two SOURCE chars alias (regardless of whether the two
// DECODED chars alias) MUST panic at runtime with the LEFT-
// column-named message. Pins the helper's OWN LEFT-column
// reject-arm — a regression that silently returned without
// panicking on a source-column duplicate would slip through
// the compile-time witnesses' failure mode too. The two
// distinct DECODED chars witness that the RIGHT column is
// INTACT — the panic MUST fire specifically on the LEFT-
// column disjointness failure.
assert_char_pair_array_bijective(&[('a', 'x'), ('a', 'y')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_bijective: RIGHT column")]
fn assert_char_pair_array_bijective_panics_at_runtime_on_right_column_collision() {
// NEGATIVE PIN — RIGHT-column corner: a two-element array
// whose two DECODED chars alias (with distinct SOURCE chars
// so the LEFT column is intact) MUST panic at runtime with
// the RIGHT-column-named message. Column-provenance in the
// panic message is load-bearing: downstream diagnostics
// route the drift back to the failed COLUMN (LEFT vs.
// RIGHT) by string search — the two panic sites MUST NOT
// collapse into one column-anonymous message.
assert_char_pair_array_bijective(&[('a', 'x'), ('b', 'x')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_bijective")]
fn assert_char_pair_array_bijective_panics_at_runtime_on_non_adjacent_collision() {
// NEGATIVE PIN — non-adjacent corner: the collision fires on
// ANY (i, j) pair with i < j, not just the adjacent (0, 1)
// corner. Pins the nested-loop shape of the helper — a
// regression that walked ONLY the adjacent pairs (i.e., swept
// `while i + 1 < N { if arr[i].0 == arr[i+1].0 { panic } … }`)
// would silently accept the non-adjacent collision at
// positions 0 and 2 tested here (a LEFT-column collision
// `'a'` at [0].0 and [2].0, with `'b'` at [1].0 breaking
// adjacency).
assert_char_pair_array_bijective(&[('a', 'x'), ('b', 'y'), ('a', 'z')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_bijective")]
fn assert_char_pair_array_bijective_panics_at_runtime_on_terminal_collision() {
// NEGATIVE PIN — terminal corner: the collision at the LAST
// pair (positions N-2 and N-1) MUST also fire. Pins the outer
// `while i < N` bound — a regression that walked `while i <
// N - 1` (dropping the last row) would silently accept a
// collision at the tail. Uses a RIGHT-column collision at
// the terminal pair to also exercise the second (RIGHT)
// panic arm's terminal-index reachability, symmetric to the
// LEFT-column non-adjacent pin above.
assert_char_pair_array_bijective(&[
('a', 'w'),
('b', 'x'),
('c', 'y'),
('d', 'z'),
('e', 'z'),
]);
}
#[test]
fn assert_char_pair_array_bijective_panic_message_names_the_helper_and_left_column() {
// PANIC-MESSAGE PROVENANCE PIN — LEFT-column arm: the panic
// message MUST begin with the helper's own name AND identify
// the failed COLUMN as "LEFT column" so downstream diagnostics
// route the drift back to (a) the helper by string search on
// `"assert_char_pair_array_bijective"` and (b) the column by
// string search on `"LEFT column"`. Sibling posture to the
// scalar-sibling `_panic_message_names_the_helper` tests
// (which name only the helper); the column-provenance
// extension is load-bearing on the paired-array vocabulary
// where a bijection failure has TWO distinguishable failure
// modes (source-column non-injective vs. decoded-column
// non-injective).
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_bijective(&[('a', 'x'), ('a', 'y')]);
});
let payload = outcome.expect_err(
"assert_char_pair_array_bijective must panic on a LEFT-\
column duplicate — the reject-collision arm is the \
point of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_bijective panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_bijective"),
"assert_char_pair_array_bijective LEFT-column panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("LEFT column"),
"assert_char_pair_array_bijective LEFT-column panic \
message {msg:?} must name the failed COLUMN (\"LEFT \
column\") for column-provenance-preserving failure \
diagnostics",
);
}
#[test]
fn assert_char_pair_array_bijective_panic_message_names_the_helper_and_right_column() {
// PANIC-MESSAGE PROVENANCE PIN — RIGHT-column arm: the panic
// message MUST begin with the helper's own name AND identify
// the failed COLUMN as "RIGHT column". Column-symmetric
// sibling of the LEFT-column pin above — a regression that
// silently unified the two panic sites into ONE column-
// anonymous message would collapse THIS pin's RIGHT-column
// substring assertion.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_bijective(&[('a', 'x'), ('b', 'x')]);
});
let payload = outcome.expect_err(
"assert_char_pair_array_bijective must panic on a RIGHT-\
column duplicate — the reject-collision arm is the \
point of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_bijective panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_bijective"),
"assert_char_pair_array_bijective RIGHT-column panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("RIGHT column"),
"assert_char_pair_array_bijective RIGHT-column panic \
message {msg:?} must name the failed COLUMN (\"RIGHT \
column\") for column-provenance-preserving failure \
diagnostics",
);
}
// ── `assert_char_pair_array_pairwise_distinct` — the (char, char)
// product-element TUPLE-level pairwise-distinctness verifier that
// binds `∀ i < j. arr[i] ≠ arr[j]` at compile time on the paired-
// array vocabulary via CONJOINED-tuple equality, WEAKER peer of
// `assert_char_pair_array_bijective`'s column-INDEPENDENT
// INJECTIVITY axis on the SAME (char, char) row of the
// (element-type × contract-shape) matrix. Both bijective ⇒
// pairwise-distinct-as-tuples witnesses hold on the substrate's
// two family-wide `[(char, char); N]` arrays (NAMED_ESCAPE_TABLE
// + ESCAPE_TABLE), so the runtime test surface pins ONLY the
// helper's OWN reject-arm (tuple-collision at three (adjacent,
// non-adjacent, terminal) positions) + accept-arms (empty,
// singletons, per-column-alias-with-distinct-tuples, family-wide
// substrate arrays) + panic-message-provenance on the CHAR-PAIR-
// TUPLE-COLLISION axis so a regression that silently weakened
// the helper on ANY arm is caught by the helper's OWN test
// surface rather than only surfacing as a false-positive on
// some future tuple-level pairwise-distinct-but-NOT-bijective
// `[(char, char); N]` array's compound pin.
#[test]
fn assert_char_pair_array_pairwise_distinct_accepts_the_empty_array() {
// Empty array `arr = []` at the `[(char, char); 0]` corner —
// vacuously pairwise-distinct at the tuple level (no (i, j)
// pair with i < j exists to test). Pins the outer `while i <
// N` guard's short-circuit on `N == 0` — a regression that
// panicked on the empty array would collapse this pin.
assert_char_pair_array_pairwise_distinct::<0>(&[]);
}
#[test]
fn assert_char_pair_array_pairwise_distinct_accepts_a_singleton_array() {
// Singleton array `arr = [(a, b)]` — vacuously pairwise-
// distinct at the tuple level (no `j > i == 0` position
// exists to compare against). Cross-corner coverage on the
// trivial-array face of the const-N generic past the empty
// corner, closing the two edge cases (N == 0, N == 1) at
// which the inner sweep is vacuous.
assert_char_pair_array_pairwise_distinct(&[('a', 'x')]);
}
#[test]
fn assert_char_pair_array_pairwise_distinct_accepts_two_distinct_tuples() {
// Two-element array with two BYTE-FOR-BYTE-DISTINCT tuples —
// the smallest non-trivial well-formed case. Both column
// projections happen to be distinct too (`'a' ≠ 'b'` on the
// LEFT column, `'x' ≠ 'y'` on the RIGHT column) but the
// helper reads ONLY the CONJOINED-tuple gate, not the per-
// column gates — pinned in isolation from the sibling
// bijective helper's stricter column-independent axis.
assert_char_pair_array_pairwise_distinct(&[('a', 'x'), ('b', 'y')]);
}
#[test]
fn assert_char_pair_array_pairwise_distinct_accepts_per_column_alias_when_conjoined_tuple_differs(
) {
// Accept-corner load-bearing to the helper's DISTINCTION from
// the sibling `assert_char_pair_array_bijective`: a pair-
// array with LEFT-column collision (`'a'` at [0].0 and
// [1].0) but with DISTINCT RIGHT columns (`'x' ≠ 'y'`) has
// TWO CONJOINED-tuples `('a', 'x') ≠ ('a', 'y')` that DIFFER
// — this helper MUST accept it. The bijective sibling would
// REJECT this pair on its LEFT-column arm because
// bijectivity is per-column-INDEPENDENT. The two helpers'
// divergence here is THE point of opening the tuple-level
// INJECTIVITY axis as a distinct sub-shape past the column-
// INDEPENDENT INJECTIVITY axis.
assert_char_pair_array_pairwise_distinct(&[('a', 'x'), ('a', 'y')]);
// Symmetric RIGHT-column-alias corner with distinct LEFT
// columns — same accept posture on the OTHER column-alias
// sibling.
assert_char_pair_array_pairwise_distinct(&[('a', 'x'), ('b', 'x')]);
}
#[test]
fn assert_char_pair_array_pairwise_distinct_accepts_the_family_wide_substrate_arrays() {
// Positive pin on the TWO family-wide `[(char, char); N]`
// paired arrays this helper is applied to at compile time
// via the module-level `const _:` witnesses: `NAMED_ESCAPE_
// TABLE` (`[(char, char); 3]`) and `ESCAPE_TABLE` (`[(char,
// char); 5]`). Both bijective ⇒ pairwise-distinct-as-tuples
// WITNESSES the compile-time `const _:` pass at runtime for
// a second-stage safety net if the const-eval sweep is ever
// silently dropped. Sibling posture to
// `assert_char_pair_array_bijective`'s
// `_accepts_the_family_wide_substrate_bijections` on the
// SAME two arrays — this pin binds the WEAKER tuple-level
// axis; that pin binds the STRONGER column-independent axis.
assert_char_pair_array_pairwise_distinct(&Atom::NAMED_ESCAPE_TABLE);
assert_char_pair_array_pairwise_distinct(&Atom::ESCAPE_TABLE);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_pairwise_distinct")]
fn assert_char_pair_array_pairwise_distinct_panics_at_runtime_on_adjacent_tuple_collision() {
// NEGATIVE PIN — adjacent (0, 1) corner: two adjacent
// CONJOINED-tuples byte-for-byte equal (BOTH columns match
// in lockstep) MUST panic at runtime. Pins the helper's OWN
// reject-arm — a regression that silently returned without
// panicking on a tuple duplicate would slip through the
// compile-time witnesses' failure mode too.
assert_char_pair_array_pairwise_distinct(&[('a', 'x'), ('a', 'x')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_pairwise_distinct")]
fn assert_char_pair_array_pairwise_distinct_panics_at_runtime_on_non_adjacent_tuple_collision()
{
// NEGATIVE PIN — non-adjacent (0, 2) corner: the collision
// fires on ANY (i, j) pair with i < j, not just the
// adjacent (0, 1) corner. Pins the nested-loop shape of the
// helper — a regression that walked ONLY the adjacent pairs
// (i.e., swept `while i + 1 < N { if arr[i] == arr[i+1] {
// panic } … }`) would silently accept the non-adjacent
// collision at positions 0 and 2 tested here (a tuple
// collision at ('a', 'x') across [0] and [2], with the
// distinct ('b', 'y') at [1] breaking adjacency). Sibling
// posture to `assert_char_pair_array_bijective_panics_at_
// runtime_on_non_adjacent_collision` on the column-
// independent axis — the loop-shape pin is row-parallel.
assert_char_pair_array_pairwise_distinct(&[('a', 'x'), ('b', 'y'), ('a', 'x')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_pairwise_distinct")]
fn assert_char_pair_array_pairwise_distinct_panics_at_runtime_on_terminal_tuple_collision() {
// NEGATIVE PIN — terminal corner: the collision at the LAST
// pair (positions N-2 and N-1) MUST also fire. Pins the
// outer `while i < N` bound — a regression that walked
// `while i < N - 1` (dropping the last row) would silently
// accept a collision at the tail. Uses a tuple collision at
// the terminal pair (`('e', 'z')` at [3] and [4]).
assert_char_pair_array_pairwise_distinct(&[
('a', 'w'),
('b', 'x'),
('c', 'y'),
('e', 'z'),
('e', 'z'),
]);
}
#[test]
fn assert_char_pair_array_pairwise_distinct_panic_message_names_the_helper_and_char_pair_tuple_collision_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-PAIR-TUPLE-COLLISION
// arm: the panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "CHAR-PAIR-TUPLE-
// COLLISION" so downstream diagnostics route the drift back
// to (a) the helper by string search on
// `"assert_char_pair_array_pairwise_distinct"` and (b) the
// axis by string search on `"CHAR-PAIR-TUPLE-COLLISION"`.
// The axis-provenance string `"CHAR-PAIR-TUPLE-COLLISION"`
// is chosen DISTINCT from EVERY sibling helper's axis
// vocabulary (`"LEFT column"` / `"RIGHT column"` on the
// paired-array BIJECTIVITY sibling; `"CHAR-PAIR-SUBSET-
// VIOLATION"` on the paired-array SUBSET-embedding sibling;
// `"CHAR-PAIR-DISJOINTNESS-VIOLATION"` on the paired-array
// DISJOINTNESS sibling) so a diagnostic that names the
// failed axis routes UNAMBIGUOUSLY to (a) this specific
// paired-array TUPLE-LEVEL PAIRWISE-DISTINCTNESS helper,
// (b) the failed axis-shape by the `"TUPLE-COLLISION"`
// suffix stem distinguishing the CONJOINED-tuple axis from
// the column-INDEPENDENT axis names used by the bijective
// sibling.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_pairwise_distinct(&[('a', 'x'), ('a', 'x')]);
});
let payload = outcome.expect_err(
"assert_char_pair_array_pairwise_distinct must panic on \
a CONJOINED-tuple duplicate — the reject-collision arm \
is the sole CHAR-PAIR-TUPLE-COLLISION failure mode of \
the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_pairwise_distinct panic \
payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_pairwise_distinct"),
"assert_char_pair_array_pairwise_distinct panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("CHAR-PAIR-TUPLE-COLLISION"),
"assert_char_pair_array_pairwise_distinct panic message \
{msg:?} must name the failed AXIS (\"CHAR-PAIR-TUPLE-\
COLLISION\") for axis-provenance-preserving failure \
diagnostics",
);
}
// ── `assert_char_pair_array_columns_equal_char_arrays` — the
// `(char, char)` product-element COLUMN-PROJECTION-EQUALITY
// verifier that binds a JOINT (LEFT_col == left) ∧ (RIGHT_col ==
// right) POSITIONWISE-EQUALITY contract at compile time on the
// (paired-array, peer-scalar-LEFT, peer-scalar-RIGHT) three-way
// column bond. Opens the (column-projection-equality) column on
// the (char, char) row of the (element-type × contract-shape)
// matrix past the pre-existing (INJECTIVITY, SUBSET-EMBEDDING,
// DISJOINTNESS) triple. Runtime test surface pins each of the
// helper's arms (accept-empty, accept-singleton-equal, accept-
// multi-element-equal, accept-family-wide-substrate-triple on
// the pinned (`ESCAPE_TABLE`, `ESCAPE_SOURCES`, `ESCAPE_DECODED`)
// triple, reject-LEFT-divergence at head / middle / tail, reject-
// RIGHT-divergence at head / middle / tail, panic-message-
// provenance on BOTH the LEFT-COLUMN-DIVERGENCE and RIGHT-
// COLUMN-DIVERGENCE axes) so a regression that silently weakened
// the helper on ANY arm is caught by the helper's OWN test
// surface rather than only surfacing as a false-positive on some
// future column-bonded `[(char, char); N]` array's compound pin.
#[test]
fn assert_char_pair_array_columns_equal_char_arrays_accepts_the_empty_triple() {
// Empty arrays `pairs = []`, `left = []`, `right = []` at
// the `[(char, char); 0]` + two `[char; 0]` corner —
// vacuously column-equal (no `i` position exists to test).
// Pins the outer `while i < N` guard's short-circuit on
// `N == 0`. Turbofish binding required because there's no
// other cue for the const parameter on the three empty
// array literals.
assert_char_pair_array_columns_equal_char_arrays::<0>(&[], &[], &[]);
}
#[test]
fn assert_char_pair_array_columns_equal_char_arrays_accepts_a_singleton_triple() {
// Singleton triple `pairs = [('a', 'x')]`, `left = ['a']`,
// `right = ['x']` — the smallest non-trivial well-formed
// case. Both column-projections match position-for-position.
assert_char_pair_array_columns_equal_char_arrays(&[('a', 'x')], &['a'], &['x']);
}
#[test]
fn assert_char_pair_array_columns_equal_char_arrays_accepts_a_multi_element_triple() {
// Three-element triple with three BYTE-FOR-BYTE-EQUAL
// column projections — pins the inner loop's `i += 1`
// advancement and the sweep's coverage of BOTH clauses at
// EACH position (a regression that returned early after
// position 0 would silently accept a mismatch at position
// 1 or 2).
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['a', 'b', 'c'],
&['x', 'y', 'z'],
);
}
#[test]
fn assert_char_pair_array_columns_equal_char_arrays_accepts_the_family_wide_substrate_triple() {
// Positive pin on the family-wide (`ESCAPE_TABLE`,
// `ESCAPE_SOURCES`, `ESCAPE_DECODED`) triple this helper is
// applied to at compile time via the module-level `const _:`
// witness. Runtime pin as a second-stage safety net if the
// const-eval sweep is ever silently dropped. Sibling posture
// to the `_bijective` + `_pairwise_distinct` family-wide pins
// on the same paired array — the three pins bind
// complementary axes of the same substrate table.
assert_char_pair_array_columns_equal_char_arrays(
&Atom::ESCAPE_TABLE,
&Atom::ESCAPE_SOURCES,
&Atom::ESCAPE_DECODED,
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_equal_char_arrays")]
fn assert_char_pair_array_columns_equal_char_arrays_panics_at_runtime_on_left_head_divergence()
{
// NEGATIVE PIN — LEFT-column head-position (i == 0) corner:
// `pairs[0].0 = 'a'` diverges from `left[0] = 'z'` on the
// FIRST position. Pins the LEFT arm firing at the head — a
// regression that started the sweep at `i = 1` would
// silently accept a head-position divergence.
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y')],
&['z', 'b'],
&['x', 'y'],
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_equal_char_arrays")]
fn assert_char_pair_array_columns_equal_char_arrays_panics_at_runtime_on_left_middle_divergence(
) {
// NEGATIVE PIN — LEFT-column middle-position (i == 1)
// corner: divergence fires on ANY interior position, not
// just the head. Pins the loop-shape of the LEFT arm — a
// regression that walked ONLY the head would silently
// accept the middle-position divergence at position 1.
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['a', 'q', 'c'],
&['x', 'y', 'z'],
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_equal_char_arrays")]
fn assert_char_pair_array_columns_equal_char_arrays_panics_at_runtime_on_left_tail_divergence()
{
// NEGATIVE PIN — LEFT-column tail-position (i == N-1)
// corner: divergence at the LAST position MUST also fire.
// Pins the outer `while i < N` bound — a regression that
// walked `while i < N - 1` (dropping the last row) would
// silently accept a tail LEFT-column divergence.
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['a', 'b', 'q'],
&['x', 'y', 'z'],
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_equal_char_arrays")]
fn assert_char_pair_array_columns_equal_char_arrays_panics_at_runtime_on_right_head_divergence()
{
// NEGATIVE PIN — RIGHT-column head-position (i == 0) corner:
// symmetric to the LEFT arm at the head — pins the RIGHT
// arm firing at position 0 with the LEFT arm satisfied.
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y')],
&['a', 'b'],
&['q', 'y'],
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_equal_char_arrays")]
fn assert_char_pair_array_columns_equal_char_arrays_panics_at_runtime_on_right_middle_divergence(
) {
// NEGATIVE PIN — RIGHT-column middle-position (i == 1)
// corner: symmetric to the LEFT-middle arm — pins the
// RIGHT arm firing at an interior position with the LEFT
// arm satisfied at every position.
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['a', 'b', 'c'],
&['x', 'q', 'z'],
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_equal_char_arrays")]
fn assert_char_pair_array_columns_equal_char_arrays_panics_at_runtime_on_right_tail_divergence()
{
// NEGATIVE PIN — RIGHT-column tail-position (i == N-1)
// corner: symmetric to the LEFT-tail arm — pins the outer
// sweep bound on the RIGHT arm with the LEFT arm satisfied.
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['a', 'b', 'c'],
&['x', 'y', 'q'],
);
}
#[test]
fn assert_char_pair_array_columns_equal_char_arrays_panic_message_names_the_helper_and_left_column_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — LEFT-COLUMN-DIVERGENCE
// arm: the panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "LEFT-COLUMN-
// DIVERGENCE" so downstream diagnostics route the drift
// back to (a) the helper by string search on
// `"assert_char_pair_array_columns_equal_char_arrays"` and
// (b) the axis by string search on
// `"LEFT-COLUMN-DIVERGENCE"`. The axis-provenance string
// is chosen DISTINCT from every sibling helper's axis
// vocabulary — a diagnostic that names the failed axis
// routes UNAMBIGUOUSLY to this specific paired-array
// COLUMN-PROJECTION-EQUALITY helper's LEFT arm.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y')],
&['z', 'b'],
&['x', 'y'],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_columns_equal_char_arrays must \
panic on a LEFT-column POSITIONWISE-EQUALITY divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_columns_equal_char_arrays \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_columns_equal_char_arrays"),
"assert_char_pair_array_columns_equal_char_arrays panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("LEFT-COLUMN-DIVERGENCE"),
"assert_char_pair_array_columns_equal_char_arrays panic \
message {msg:?} must name the failed AXIS (\"LEFT-\
COLUMN-DIVERGENCE\") for axis-provenance-preserving \
failure diagnostics",
);
}
#[test]
fn assert_char_pair_array_columns_equal_char_arrays_panic_message_names_the_helper_and_right_column_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — RIGHT-COLUMN-DIVERGENCE
// arm: symmetric to the LEFT-column-divergence provenance
// pin. The panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "RIGHT-COLUMN-
// DIVERGENCE" — the two axis-provenance strings
// (`"LEFT-COLUMN-DIVERGENCE"` + `"RIGHT-COLUMN-DIVERGENCE"`)
// partition the helper's failure modes into TWO disjoint
// arms so a diagnostic that names the axis routes
// UNAMBIGUOUSLY to the specific COLUMN that diverged.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_columns_equal_char_arrays(
&[('a', 'x'), ('b', 'y')],
&['a', 'b'],
&['q', 'y'],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_columns_equal_char_arrays must \
panic on a RIGHT-column POSITIONWISE-EQUALITY \
divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_columns_equal_char_arrays \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_columns_equal_char_arrays"),
"assert_char_pair_array_columns_equal_char_arrays panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("RIGHT-COLUMN-DIVERGENCE"),
"assert_char_pair_array_columns_equal_char_arrays panic \
message {msg:?} must name the failed AXIS (\"RIGHT-\
COLUMN-DIVERGENCE\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_char_pair_array_columns_cross_disjoint` — the
// `(char, char)` product-element WITHIN-ARRAY CROSS-COLUMN
// disjointness verifier that binds `LEFT column ∩ RIGHT column
// = ∅` at compile time on a pattern-DISTINCT-from-value paired-
// array vocabulary. Peer to the four prior paired-array verifiers
// on the SAME row (`_pairwise_distinct` — CONJOINED-tuple
// INJECTIVITY; `_bijective` — per-column INJECTIVITY;
// `_within_char_pair_finite_set` — SUBSET-EMBEDDING;
// `_arrays_disjoint` — BETWEEN-ARRAY CONJOINED-tuple
// DISJOINTNESS): where the four siblings close within-tuple /
// within-column / between-array axes, this helper closes the
// WITHIN-ARRAY CROSS-COLUMN-CHARACTER axis. The runtime test
// surface pins each of the helper's arms (accept-empty-array,
// accept-singleton-when-left-disjoint-from-right, accept-multi-
// element-when-cross-disjoint, accept-substrate-family-wide-
// NAMED_ESCAPE_TABLE, accept-when-left-column-duplicates-with-
// cross-disjoint-preserved, reject-diagonal-collision, reject-
// head-left-matches-head-right-off-diagonal, reject-head-left-
// matches-tail-right, reject-tail-left-matches-head-right,
// reject-tail-left-matches-tail-right, panic-message-provenance
// on the CROSS-COLUMN-COLLISION axis) so a regression that
// silently weakened the helper on ANY arm is caught by the
// helper's OWN test surface rather than only surfacing as a
// false-positive on some future pattern-DISTINCT-from-value
// `[(char, char); N]` array's compound pin.
#[test]
fn assert_char_pair_array_columns_cross_disjoint_accepts_the_empty_array() {
// Empty array `arr = []` at the `[(char, char); 0]` corner —
// vacuously cross-column-disjoint (no `(i, j)` position pair
// exists to test). Pins the outer `while i < N` guard's
// short-circuit on `N == 0`. Turbofish binding required
// because there's no other cue for the const parameter on
// the empty array literal.
assert_char_pair_array_columns_cross_disjoint::<0>(&[]);
}
#[test]
fn assert_char_pair_array_columns_cross_disjoint_accepts_a_singleton_when_left_disjoint_from_right(
) {
// Singleton `arr = [('a', 'x')]` — LEFT column = {'a'},
// RIGHT column = {'x'}, disjoint. Pins the singleton corner
// where the ONLY `(i, j)` position pair is `(0, 0)` on the
// diagonal and `arr[0].0 != arr[0].1` so the diagonal arm
// does NOT fire.
assert_char_pair_array_columns_cross_disjoint(&[('a', 'x')]);
}
#[test]
fn assert_char_pair_array_columns_cross_disjoint_accepts_a_multi_element_when_cross_disjoint() {
// Three-element `arr = [('a', 'x'), ('b', 'y'), ('c', 'z')]`
// with LEFT = {'a', 'b', 'c'}, RIGHT = {'x', 'y', 'z'},
// disjoint. Pins the inner sweep's coverage of BOTH
// diagonal AND off-diagonal `(i, j)` position pairs at
// EACH `i` — a regression that returned early after
// position 0 would silently accept a cross-column collision
// at position 1 or 2 or an off-diagonal cross-column
// collision at `(0, 1)`, `(1, 0)`, `(0, 2)`, `(2, 0)`,
// `(1, 2)`, `(2, 1)`.
assert_char_pair_array_columns_cross_disjoint(&[('a', 'x'), ('b', 'y'), ('c', 'z')]);
}
#[test]
fn assert_char_pair_array_columns_cross_disjoint_accepts_the_family_wide_substrate_named_escape_table(
) {
// Positive pin on the family-wide `Atom::NAMED_ESCAPE_TABLE`
// paired array this helper is applied to at compile time via
// the module-level `const _:` witness. Runtime pin as a
// second-stage safety net if the const-eval sweep is ever
// silently dropped. Sibling posture to the `_bijective` +
// `_pairwise_distinct` family-wide pins on the same paired
// array — the three pins bind complementary INJECTIVITY axes
// (per-column, per-tuple, per-CROSS-column) of the same
// substrate table. LEFT column = {'n', 't', 'r'} (printable
// ASCII source chars), RIGHT column = {'\n', '\t', '\r'}
// (control character decoded values), disjoint by algebra
// design.
assert_char_pair_array_columns_cross_disjoint(&Atom::NAMED_ESCAPE_TABLE);
}
#[test]
fn assert_char_pair_array_columns_cross_disjoint_accepts_when_left_column_duplicates_but_cross_disjoint_preserved(
) {
// Orthogonality with `_bijective`: a table like
// `[('a', 'x'), ('a', 'y')]` VIOLATES per-column INJECTIVITY
// (LEFT column repeats 'a') but PASSES cross-column
// disjointness (LEFT = {'a'}, RIGHT = {'x', 'y'} are
// disjoint). Pins this helper's axis as INDEPENDENT of
// `_bijective` — a diagnostic that names CROSS-COLUMN-
// COLLISION routes UNAMBIGUOUSLY to a cross-column drift,
// not to a per-column duplicate.
assert_char_pair_array_columns_cross_disjoint(&[('a', 'x'), ('a', 'y')]);
// Symmetric orthogonality on the RIGHT column: a table like
// `[('a', 'x'), ('b', 'x')]` VIOLATES per-column INJECTIVITY
// (RIGHT column repeats 'x') but PASSES cross-column
// disjointness (LEFT = {'a', 'b'}, RIGHT = {'x'} are
// disjoint).
assert_char_pair_array_columns_cross_disjoint(&[('a', 'x'), ('b', 'x')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_cross_disjoint")]
fn assert_char_pair_array_columns_cross_disjoint_panics_at_runtime_on_diagonal_collision() {
// NEGATIVE PIN — diagonal `(i == j == 0)` corner: `arr[0] =
// ('a', 'a')` collides with itself across columns. Pins the
// inner sweep INCLUDING the `j == i` case — a regression that
// set `j = i + 1` (skipping the diagonal) would silently
// accept a `('a', 'a')` self-mapping pair, which is EXACTLY
// the SELF-arm identity-relation shape the pattern-DISTINCT-
// from-value sub-vocabulary MUST NOT carry.
assert_char_pair_array_columns_cross_disjoint(&[('a', 'a')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_cross_disjoint")]
fn assert_char_pair_array_columns_cross_disjoint_panics_at_runtime_on_diagonal_collision_at_interior_position(
) {
// NEGATIVE PIN — interior diagonal `(i == j == 1)` corner:
// pins the diagonal arm firing at ANY interior position,
// not just the head. A regression that started the sweep
// at `i = 1` for `j` (skipping the diagonal at each `i`)
// would silently accept a `('b', 'b')` self-mapping pair at
// position 1.
assert_char_pair_array_columns_cross_disjoint(&[('a', 'x'), ('b', 'b'), ('c', 'z')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_cross_disjoint")]
fn assert_char_pair_array_columns_cross_disjoint_panics_at_runtime_on_head_left_matches_tail_right(
) {
// NEGATIVE PIN — off-diagonal `(i, j) = (0, 1)` corner:
// `arr[0].0 == 'a'` collides with `arr[1].1 == 'a'` at
// an off-diagonal position pair. Pins the inner sweep
// covering `j > i` — a regression that only checked the
// diagonal `i == j` would silently accept the head LEFT
// aliasing the tail RIGHT.
assert_char_pair_array_columns_cross_disjoint(&[('a', 'x'), ('b', 'a')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_cross_disjoint")]
fn assert_char_pair_array_columns_cross_disjoint_panics_at_runtime_on_tail_left_matches_head_right(
) {
// NEGATIVE PIN — off-diagonal `(i, j) = (1, 0)` corner:
// `arr[1].0 == 'a'` collides with `arr[0].1 == 'a'` at the
// OTHER off-diagonal orientation. Pins the inner sweep
// covering `j < i` — a regression that only checked `j >=
// i` would silently accept the tail LEFT aliasing the head
// RIGHT.
assert_char_pair_array_columns_cross_disjoint(&[('x', 'a'), ('a', 'y')]);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_columns_cross_disjoint")]
fn assert_char_pair_array_columns_cross_disjoint_panics_at_runtime_on_tail_position_diagonal_collision(
) {
// NEGATIVE PIN — tail-position diagonal `(i == j == N-1)`
// corner: pins the outer `while i < N` bound INCLUDING the
// last row — a regression that walked `while i < N - 1`
// (dropping the last row) would silently accept a tail-
// position `('c', 'c')` diagonal collision.
assert_char_pair_array_columns_cross_disjoint(&[('a', 'x'), ('b', 'y'), ('c', 'c')]);
}
#[test]
fn assert_char_pair_array_columns_cross_disjoint_panic_message_names_the_helper_and_cross_column_collision_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CROSS-COLUMN-COLLISION arm:
// the panic message MUST begin with the helper's own name
// AND identify the failed AXIS as "CROSS-COLUMN-COLLISION"
// so downstream diagnostics route the drift back to (a) the
// helper by string search on
// `"assert_char_pair_array_columns_cross_disjoint"` and (b)
// the axis by string search on `"CROSS-COLUMN-COLLISION"`.
// The axis-provenance string is chosen DISTINCT from every
// sibling helper's axis vocabulary (`"CHAR-PAIR-TUPLE-
// COLLISION"` on `_pairwise_distinct`, `"LEFT column"` /
// `"RIGHT column"` on `_bijective`, `"CHAR-PAIR-SUBSET-
// VIOLATION"` on `_within_char_pair_finite_set`, `"CHAR-
// PAIR-DISJOINTNESS-VIOLATION"` on `_arrays_disjoint`,
// `"LEFT-COLUMN-DIVERGENCE"` / `"RIGHT-COLUMN-DIVERGENCE"`
// on `_columns_equal_char_arrays`) — a diagnostic that
// names the failed axis routes UNAMBIGUOUSLY to this
// specific cross-column-disjointness helper's arm.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_columns_cross_disjoint(&[('a', 'a')]);
});
let payload = outcome.expect_err(
"assert_char_pair_array_columns_cross_disjoint must \
panic on a diagonal `('a', 'a')` self-mapping pair",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_columns_cross_disjoint \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_columns_cross_disjoint"),
"assert_char_pair_array_columns_cross_disjoint panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("CROSS-COLUMN-COLLISION"),
"assert_char_pair_array_columns_cross_disjoint panic \
message {msg:?} must name the failed AXIS (\"CROSS-\
COLUMN-COLLISION\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_char_pair_array_is_concatenation_of_char_pair_array_
// and_char_array_diagonal` — the `(char, char)` product-element
// SEGMENTED-CONCATENATION-with-DIAGONAL-TAIL verifier that binds
// the composite-construction identity `arr == head ++
// diagonal(tail_diag)` at compile time on a paired-array
// vocabulary composed from a peer paired HEAD + a peer scalar
// DIAGONAL TAIL. Peer to the `_columns_equal_char_arrays` cross-
// row-bond sibling — where the sibling binds the FULL column-
// projection bond across TWO peer scalar arrays at EVERY position,
// this helper binds the SEGMENTED composite-construction bond
// across a peer paired vocabulary (head) and a peer scalar
// vocabulary (diagonally embedded tail). The runtime test surface
// pins each of the helper's arms (accept-empty-triple, accept-
// head-only, accept-diagonal-tail-only, accept-mixed-small-triple,
// accept-family-wide-substrate-triple, reject-head-left-head-
// position, reject-head-left-tail-position, reject-head-right-
// head-position, reject-head-right-tail-position, reject-
// diagonal-tail-left-head-position, reject-diagonal-tail-left-
// tail-position, reject-diagonal-tail-right-head-position, reject-
// diagonal-tail-right-tail-position, reject-cardinality-mismatch
// on `K + M != N`, panic-message-provenance on FIVE distinct
// AXES) so a regression that silently weakened the helper on ANY
// arm is caught by the helper's OWN test surface rather than only
// surfacing as a false-positive on some future composite-
// constructed `[(char, char); N]` array's compound pin.
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_accepts_the_empty_triple(
) {
// Empty arrays `arr = []`, `head = []`, `tail_diag = []` at
// the `[(char, char); 0]` + `[(char, char); 0]` + `[char; 0]`
// corner — vacuously composite (no position exists to test).
// Pins the outer sweep bounds' short-circuit on `N == K ==
// M == 0`. Turbofish binding required because there's no
// other cue for the const parameters on the three empty
// array literals.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<0, 0, 0>(
&[],
&[],
&[],
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_accepts_head_only_triple(
) {
// Head-only triple `arr = [('a','x')]`, `head = [('a','x')]`,
// `tail_diag = []` at the `M == 0` corner — the composite
// reduces to the peer paired HEAD verbatim, no diagonal-
// embedding. Pins the outer `while j < M` guard's short-
// circuit on empty tail. Turbofish binding required for the
// three const parameters.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<1, 1, 0>(
&[('a', 'x')],
&[('a', 'x')],
&[],
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_accepts_diagonal_tail_only_triple(
) {
// Diagonal-tail-only triple `arr = [('q','q')]`, `head = []`,
// `tail_diag = ['q']` at the `K == 0` corner — the composite
// reduces to the DIAGONAL-EMBEDDING of the peer scalar
// `tail_diag` verbatim, no head. Pins the outer `while i < K`
// guard's short-circuit on empty head. Turbofish binding
// required for the three const parameters.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<1, 0, 1>(
&[('q', 'q')],
&[],
&['q'],
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_accepts_mixed_small_triple(
) {
// Mixed small triple `arr = [('a','x'), ('q','q')]`, `head =
// [('a','x')]`, `tail_diag = ['q']` at the `K == 1, M == 1`
// corner — the smallest non-trivial case that exercises BOTH
// segments. Pins that BOTH sweeps advance and that BOTH arms
// cover their columns at their positions. A regression that
// silently walked ONLY the head OR ONLY the tail would
// silently accept a divergence on the un-swept segment.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<2, 1, 1>(
&[('a', 'x'), ('q', 'q')],
&[('a', 'x')],
&['q'],
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_accepts_the_family_wide_substrate_triple(
) {
// Positive pin on the family-wide (`Atom::ESCAPE_TABLE`,
// `Atom::NAMED_ESCAPE_TABLE`, `Atom::SELF_ESCAPE_TABLE`)
// triple this helper is applied to at compile time via the
// module-level `const _:` witness. Runtime pin as a second-
// stage safety net if the const-eval sweep is ever silently
// dropped. SIXTH witness posture on the same paired array in
// complementary posture to the FIVE prior sibling helper
// family-wide pins (`_pairwise_distinct`, `_bijective`,
// `_within_char_pair_finite_set`, `_arrays_disjoint`,
// `_columns_equal_char_arrays`) — the six pins bind six
// complementary axes of the same substrate table.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal(
&Atom::ESCAPE_TABLE,
&Atom::NAMED_ESCAPE_TABLE,
&Atom::SELF_ESCAPE_TABLE,
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_head_left_head_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT LEFT-column head-position
// (i == 0) corner: `arr[0].0 = 'z'` diverges from `head[0].0
// = 'a'` on the FIRST head-segment position. Pins the HEAD-
// LEFT arm firing at the head — a regression that started
// the head sweep at `i = 1` would silently accept a head-
// position divergence.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 2, 1>(
&[('z', 'x'), ('b', 'y'), ('q', 'q')],
&[('a', 'x'), ('b', 'y')],
&['q'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_head_left_tail_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT LEFT-column tail-position
// (i == K-1) corner: divergence at the LAST head-segment
// position MUST also fire. Pins the outer head-sweep bound
// `while i < K` — a regression that walked `while i < K - 1`
// (dropping the last head row) would silently accept a tail-
// of-head LEFT-column divergence.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 2, 1>(
&[('a', 'x'), ('z', 'y'), ('q', 'q')],
&[('a', 'x'), ('b', 'y')],
&['q'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_head_right_head_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT RIGHT-column head-position
// (i == 0) corner: symmetric to the HEAD-LEFT arm at the
// head — pins the HEAD-RIGHT arm firing at position 0 with
// the HEAD-LEFT arm satisfied.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 2, 1>(
&[('a', 'z'), ('b', 'y'), ('q', 'q')],
&[('a', 'x'), ('b', 'y')],
&['q'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_head_right_tail_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT RIGHT-column tail-position
// (i == K-1) corner: symmetric to the HEAD-LEFT-tail arm —
// pins the outer head-sweep bound on the RIGHT arm with the
// LEFT arm satisfied at every position.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 2, 1>(
&[('a', 'x'), ('b', 'z'), ('q', 'q')],
&[('a', 'x'), ('b', 'y')],
&['q'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_diagonal_tail_left_head_position_divergence(
) {
// NEGATIVE PIN — DIAGONAL-TAIL LEFT-column head-position
// (j == 0, arr[K + 0].0 diverges from `tail_diag[0]`) corner:
// pins the DIAGONAL-TAIL-LEFT arm firing at the tail segment's
// FIRST position — a regression that started the tail sweep
// at `j = 1` would silently accept a head-of-tail LEFT-column
// divergence.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 1, 2>(
&[('a', 'x'), ('z', 'q'), ('r', 'r')],
&[('a', 'x')],
&['q', 'r'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_diagonal_tail_left_tail_position_divergence(
) {
// NEGATIVE PIN — DIAGONAL-TAIL LEFT-column tail-position
// (j == M-1, arr[N-1].0 diverges from `tail_diag[M-1]`)
// corner: pins the outer tail-sweep bound `while j < M` — a
// regression that walked `while j < M - 1` (dropping the last
// tail row) would silently accept a tail-of-tail LEFT-column
// divergence.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 1, 2>(
&[('a', 'x'), ('q', 'q'), ('z', 'r')],
&[('a', 'x')],
&['q', 'r'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_diagonal_tail_right_head_position_divergence(
) {
// NEGATIVE PIN — DIAGONAL-TAIL RIGHT-column head-position
// (j == 0, arr[K + 0].1 diverges from `tail_diag[0]`) corner:
// symmetric to the DIAGONAL-TAIL-LEFT arm at the tail-head —
// pins the DIAGONAL-TAIL-RIGHT arm firing at the tail
// segment's FIRST position with the LEFT arm satisfied.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 1, 2>(
&[('a', 'x'), ('q', 'z'), ('r', 'r')],
&[('a', 'x')],
&['q', 'r'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_diagonal_tail_right_tail_position_divergence(
) {
// NEGATIVE PIN — DIAGONAL-TAIL RIGHT-column tail-position
// (j == M-1, arr[N-1].1 diverges from `tail_diag[M-1]`)
// corner: symmetric to the DIAGONAL-TAIL-LEFT-tail arm —
// pins the outer tail-sweep bound on the RIGHT arm with the
// LEFT arm satisfied at every position.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<3, 1, 2>(
&[('a', 'x'), ('q', 'q'), ('r', 'z')],
&[('a', 'x')],
&['q', 'r'],
);
}
#[test]
#[should_panic(
expected = "assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
)]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panics_at_runtime_on_cardinality_mismatch(
) {
// NEGATIVE PIN — CARDINALITY-MISMATCH corner: `K + M != N`
// (here `K == 3, M == 3, N == 5` so `K + M == 6 != 5`) fires
// the CARDINALITY-MISMATCH panic BEFORE any per-position
// sweep begins. Pins the FIRST guard arm — a regression that
// silently omitted the arity check would OOB-panic instead
// OR silently truncate the tail sweep, both of which would
// corrupt the AXIS-provenance signal downstream diagnostics
// depend on.
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<5, 3, 3>(
&[('a', 'x'), ('b', 'y'), ('c', 'z'), ('q', 'q'), ('r', 'r')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['q', 'r', 's'],
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panic_message_names_the_helper_and_head_left_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — HEAD-SEGMENT-LEFT-DIVERGENCE
// arm: the panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "HEAD-SEGMENT-LEFT-
// DIVERGENCE" so downstream diagnostics route the drift back
// to (a) the helper by string search AND (b) the axis by
// string search on `"HEAD-SEGMENT-LEFT-DIVERGENCE"`.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<
3,
2,
1,
>(
&[('z', 'x'), ('b', 'y'), ('q', 'q')],
&[('a', 'x'), ('b', 'y')],
&['q'],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
must panic on a HEAD-SEGMENT LEFT-column divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic payload must be a static &str or String",
);
assert!(
msg.contains(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal"
),
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic message {msg:?} must name the helper for \
provenance-preserving failure diagnostics",
);
assert!(
msg.contains("HEAD-SEGMENT-LEFT-DIVERGENCE"),
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic message {msg:?} must name the failed AXIS \
(\"HEAD-SEGMENT-LEFT-DIVERGENCE\") for axis-provenance-\
preserving failure diagnostics",
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panic_message_names_the_helper_and_head_right_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — HEAD-SEGMENT-RIGHT-
// DIVERGENCE arm: symmetric to the HEAD-LEFT arm's
// provenance pin.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<
3,
2,
1,
>(
&[('a', 'z'), ('b', 'y'), ('q', 'q')],
&[('a', 'x'), ('b', 'y')],
&['q'],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
must panic on a HEAD-SEGMENT RIGHT-column divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic payload must be a static &str or String",
);
assert!(
msg.contains("HEAD-SEGMENT-RIGHT-DIVERGENCE"),
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic message {msg:?} must name the failed AXIS \
(\"HEAD-SEGMENT-RIGHT-DIVERGENCE\") for axis-provenance-\
preserving failure diagnostics",
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panic_message_names_the_helper_and_diagonal_tail_left_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — DIAGONAL-TAIL-SEGMENT-LEFT-
// DIVERGENCE arm: partitions the failure vocabulary DISTINCT
// from the HEAD-SEGMENT-LEFT-DIVERGENCE arm — a diagnostic
// that reads the AXIS routes UNAMBIGUOUSLY to the TAIL
// segment's LEFT column rather than the HEAD segment's.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<
3,
1,
2,
>(
&[('a', 'x'), ('z', 'q'), ('r', 'r')],
&[('a', 'x')],
&['q', 'r'],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
must panic on a DIAGONAL-TAIL LEFT-column divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic payload must be a static &str or String",
);
assert!(
msg.contains("DIAGONAL-TAIL-SEGMENT-LEFT-DIVERGENCE"),
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic message {msg:?} must name the failed AXIS \
(\"DIAGONAL-TAIL-SEGMENT-LEFT-DIVERGENCE\") for axis-\
provenance-preserving failure diagnostics",
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panic_message_names_the_helper_and_diagonal_tail_right_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — DIAGONAL-TAIL-SEGMENT-RIGHT-
// DIVERGENCE arm: symmetric to the DIAGONAL-TAIL-LEFT arm's
// provenance pin. The FOUR positionwise axes together
// (HEAD-LEFT, HEAD-RIGHT, DIAGONAL-TAIL-LEFT, DIAGONAL-TAIL-
// RIGHT) partition the helper's positionwise failure surface
// into FOUR disjoint arms so a diagnostic reading the AXIS
// routes UNAMBIGUOUSLY to the specific (segment, column)
// corner that diverged.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<
3,
1,
2,
>(
&[('a', 'x'), ('q', 'z'), ('r', 'r')],
&[('a', 'x')],
&['q', 'r'],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
must panic on a DIAGONAL-TAIL RIGHT-column divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic payload must be a static &str or String",
);
assert!(
msg.contains("DIAGONAL-TAIL-SEGMENT-RIGHT-DIVERGENCE"),
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic message {msg:?} must name the failed AXIS \
(\"DIAGONAL-TAIL-SEGMENT-RIGHT-DIVERGENCE\") for axis-\
provenance-preserving failure diagnostics",
);
}
#[test]
fn assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal_panic_message_names_the_helper_and_cardinality_mismatch_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CARDINALITY-MISMATCH arm:
// fires BEFORE any per-position sweep, at a distinct axis
// vocabulary. Pins the FIRST guard's provenance so a
// diagnostic reading the axis distinguishes ARITY drift
// (mistyped turbofish) from CONTENT drift (segment / column
// divergence).
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal::<
5,
3,
3,
>(
&[('a', 'x'), ('b', 'y'), ('c', 'z'), ('q', 'q'), ('r', 'r')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['q', 'r', 's'],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
must panic on a CARDINALITY-MISMATCH `K + M != N`",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic payload must be a static &str or String",
);
assert!(
msg.contains("CARDINALITY-MISMATCH"),
"assert_char_pair_array_is_concatenation_of_char_pair_array_and_char_array_diagonal \
panic message {msg:?} must name the failed AXIS \
(\"CARDINALITY-MISMATCH\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_char_pair_array_slice_equals_char_pair_array` — the
// `(char, char)` product-element row's SLICE-EQUALS-ARRAY verifier
// that binds the sub-slice `full[START..START + M) == sub[..]`
// paired-positionwise-composition contract at compile time. Row-
// dual peer to `assert_u8_array_slice_equals_u8_array`,
// `assert_char_array_slice_equals_char_array`, and
// `assert_str_array_slice_equals_str_array` on the (element-type)
// axis of the SAME (SUB-SLICE ARRAY-image) column of the (element-
// type × contract-shape) matrix. The runtime test surface pins
// each of the helper's arms (accept-canonical-middle-slice,
// accept-empty-sub-array-at-three-start-positions, accept-full-
// array-degenerate-at-two-arities, accept-substrate-escape-table-
// head-segment-decomposition, reject-left-column-drift, reject-
// right-column-drift, reject-start-out-of-bounds, reject-slice-
// length-out-of-bounds, panic-message-provenance on the LEFT-
// COLUMN + RIGHT-COLUMN axes) so a regression that silently
// weakened the helper on ANY arm (e.g. dropping the LEFT-column
// check, dropping the RIGHT-column check, dropping the `START`
// offset from the `full[START + i]` read, returning early past
// ANY bounds gate, or dropping the `as u32` char-to-scalar bridge
// that lets the const-eval sweep proceed byte-for-byte on each
// column) is caught by the helper's OWN test surface rather than
// only surfacing as a false-positive on some future paired
// container-array sub-slice equality.
#[test]
fn assert_char_pair_array_slice_equals_char_pair_array_accepts_a_canonical_middle_slice() {
// Canonical paired sub-slice `full[START..START + M) == sub[..]`
// inside a longer paired array `full` whose ENDPOINTS carry
// DIFFERENT pairs than the peer sub-array. Pins the outer
// `while i < M` sweep reads `full[START + i]` at the OFFSET
// position (not `full[i]`) on BOTH columns — a regression that
// dropped the `START` offset would compare `full[0..M)`
// against `sub[..]` and panic on the wrong axis. `START = 1`
// pins the sweep skips position `[0..START)` and reads only
// `[1..1+3) = [1..4)` on both columns of the paired sub-array.
assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 1>(
&[('z', 'Z'), ('a', 'x'), ('b', 'y'), ('c', 'z'), ('z', 'Z')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
fn assert_char_pair_array_slice_equals_char_pair_array_accepts_the_empty_sub_array() {
// LEGAL degenerate: `M == 0` collapses the paired sub-array
// into an empty listing `[]`. The sweep never enters the loop
// body and the helper accepts. Cross-position coverage pins
// the empty-sub-array acceptance at THREE distinct `START`
// positions (`START == 0` at the left endpoint, `START == 2`
// in the interior, `START == N` at the right endpoint — the
// latter is the corner `START == N` combined with `M == 0`
// that the START-OUT-OF-BOUNDS gate's inclusive upper bound
// must accept). A regression that hard-coded `START < N` OR
// panicked on the `M == 0` corner is caught on ALL THREE
// arms.
assert_char_pair_array_slice_equals_char_pair_array::<5, 0, 0>(
&[('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X')],
&[],
);
assert_char_pair_array_slice_equals_char_pair_array::<5, 0, 2>(
&[('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X')],
&[],
);
assert_char_pair_array_slice_equals_char_pair_array::<5, 0, 5>(
&[('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X')],
&[],
);
}
#[test]
fn assert_char_pair_array_slice_equals_char_pair_array_accepts_the_full_array_degenerate() {
// Full-array-covering slice `M == N, START == 0` collapses
// to the ALL-positions-equal-peer-array shape `full == sub`
// pointwise on BOTH columns. Pins that the sweep proceeds
// through EVERY position of the outer paired array when
// `START = 0` and `M = N`. Cross-arity coverage on `N ∈ {2,
// 3}` pins the sweep's terminal-position visit across the
// small arities the substrate's paired escape-table
// vocabulary spans (`N = 2` for a hypothetical two-slot
// paired table, `N = 3` for `NAMED_ESCAPE_TABLE`).
assert_char_pair_array_slice_equals_char_pair_array::<2, 2, 0>(
&[('a', 'x'), ('b', 'y')],
&[('a', 'x'), ('b', 'y')],
);
assert_char_pair_array_slice_equals_char_pair_array::<3, 3, 0>(
&[('n', '\n'), ('t', '\t'), ('r', '\r')],
&[('n', '\n'), ('t', '\t'), ('r', '\r')],
);
}
#[test]
fn assert_char_pair_array_slice_equals_char_pair_array_accepts_the_substrate_escape_table_head_segment(
) {
// Runtime cross-check that the substrate's (ESCAPE_TABLE,
// NAMED_ESCAPE_TABLE) HEAD-segment positionwise-composition
// identity `ESCAPE_TABLE[0..3] == NAMED_ESCAPE_TABLE` holds
// pointwise on BOTH columns. Runs the SAME helper the module-
// level `const _` witness runs at rustc time — a runtime
// safety net enforcing the theorem at BOTH stages of the
// toolchain (const at `cargo check`, runtime at `cargo
// test`). A regression that renamed one of the three
// NAMED-escape SOURCE or DECODED entries (or drifted the
// ordering across ESCAPE_TABLE's first three initializer
// slots) fails HERE at the substrate callsite AND at the
// const witness above. Peer of
// `assert_char_array_slice_equals_char_array_accepts_each_family_wide_substrate_array`
// on the (char) row — that witness carries the FULL-ARRAY
// per-position ORDER theorem for the EIGHT reader-boundary
// `[char; N]` arrays; this witness carries the HEAD-segment
// per-position ORDER theorem for the substrate's SINGLE
// paired-composite pair on the `(char, char)` product-
// element row.
assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 0>(
&Atom::ESCAPE_TABLE,
&Atom::NAMED_ESCAPE_TABLE,
);
}
#[test]
#[should_panic(expected = "CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN-VIOLATION")]
fn assert_char_pair_array_slice_equals_char_pair_array_panics_at_runtime_on_left_column_drift()
{
// NEGATIVE PIN — CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN-
// VIOLATION corner: a LEFT-column entry at some position in
// `full[START..START + M)` that does NOT byte-equal the peer
// sub-array `sub` at the offset-matched position MUST panic
// at runtime with the axis-named message. Pins the helper's
// LEFT-column reject arm — a regression that silently
// dropped the LEFT-column check while retaining the RIGHT-
// column check would slip through the compile-time witness's
// LEFT-drift failure mode too. The offending LEFT-column
// char `'!'` at outer position `3` (interior of the sub-
// slice `[1..4)`, offset `2` inside `sub`) pins the middle-
// of-slice LEFT-column drift mode.
assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 1>(
&[('z', 'Z'), ('a', 'x'), ('b', 'y'), ('!', 'z'), ('z', 'Z')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
#[should_panic(expected = "CHAR-PAIR-SLICE-EQUALS-ARRAY-RIGHT-COLUMN-VIOLATION")]
fn assert_char_pair_array_slice_equals_char_pair_array_panics_at_runtime_on_right_column_drift()
{
// NEGATIVE PIN — CHAR-PAIR-SLICE-EQUALS-ARRAY-RIGHT-COLUMN-
// VIOLATION corner: a RIGHT-column entry at some position in
// `full[START..START + M)` that does NOT byte-equal the peer
// sub-array `sub` at the offset-matched position MUST panic
// at runtime with the axis-named message. Pins the helper's
// RIGHT-column reject arm — a regression that silently
// dropped the RIGHT-column check while retaining the LEFT-
// column check would slip through the compile-time witness's
// RIGHT-drift failure mode too. The LEFT column matches
// exactly on every position so ONLY the RIGHT column drift
// (`'!'` at outer position `3`, offset `2` inside `sub`)
// fires the reject arm — routing the diagnostic to the
// RIGHT-COLUMN-* axis rather than the sibling LEFT-COLUMN-*
// axis.
assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 1>(
&[('z', 'Z'), ('a', 'x'), ('b', 'y'), ('c', '!'), ('z', 'Z')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
#[should_panic(expected = "START-OUT-OF-BOUNDS")]
fn assert_char_pair_array_slice_equals_char_pair_array_panics_at_runtime_on_start_out_of_bounds(
) {
// NEGATIVE PIN — START-OUT-OF-BOUNDS gate: a caller-side
// turbofish arity slip on the `START` const-generic where
// `START > N` MUST panic at runtime with the START-OUT-OF-
// BOUNDS-named message BEFORE the peer SLICE-LENGTH-OUT-OF-
// BOUNDS gate reads `N - START` (which would `usize`-
// underflow had this gate not caught the slip first). Pins
// the gate's placement at the TOP of the helper — a
// regression that dropped the gate would either underflow
// subtraction at the peer gate OR panic deeper in
// `full[START + i]` bounds-checking with a helper-name-less
// panic message. The offending `START = 7` against `N = 5`
// pins the strict `START > N` reject arm; the LEGAL
// `START == N` empty-slice-at-right-endpoint corner is
// covered by the peer acceptance test above.
assert_char_pair_array_slice_equals_char_pair_array::<5, 0, 7>(
&[('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X')],
&[],
);
}
#[test]
#[should_panic(expected = "SLICE-LENGTH-OUT-OF-BOUNDS")]
fn assert_char_pair_array_slice_equals_char_pair_array_panics_at_runtime_on_slice_length_out_of_bounds(
) {
// NEGATIVE PIN — SLICE-LENGTH-OUT-OF-BOUNDS gate: a peer
// sub-array arity `M` that exceeds the outer array's tail
// cardinality `N - START` MUST panic at runtime with the
// slice-length-out-of-bounds-named message. Peer gate to the
// START-OUT-OF-BOUNDS arm above — the two gates jointly
// enforce `START ≤ N` and `M ≤ N - START` before any content
// sweep. The offending `M = 5` against `N - START = 5 - 3 =
// 2` pins the strict `M > N - START` reject arm; the LEGAL
// exact-fit corner `M == N - START` is covered by the
// middle-slice acceptance test above.
assert_char_pair_array_slice_equals_char_pair_array::<5, 5, 3>(
&[('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X')],
&[('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X'), ('x', 'X')],
);
}
#[test]
fn assert_char_pair_array_slice_equals_char_pair_array_panic_message_names_the_helper_and_left_column_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-PAIR-SLICE-EQUALS-
// ARRAY-LEFT-COLUMN-VIOLATION arm: the panic message MUST
// begin with the helper's own name AND identify the failed
// AXIS as "CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN-
// VIOLATION" so downstream diagnostics route the drift back
// to (a) the helper by string search on
// `"assert_char_pair_array_slice_equals_char_pair_array"`
// and (b) the failed COLUMN of the paired sweep by string
// search on `"CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN-
// VIOLATION"`. Sibling posture to the (u8) / (char) / (str)
// row peers' provenance pins — the FOUR pins together bind
// the (helper, failed-axis) provenance pair at ONE test per
// corner of the (SUB-SLICE ARRAY-image) column across the
// FOUR element-type rows of the matrix.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 1>(
&[('z', 'Z'), ('a', 'x'), ('b', 'y'), ('!', 'z'), ('z', 'Z')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_slice_equals_char_pair_array must \
panic on a LEFT-column drift — the reject-left-column-\
drift arm is a CONTENT failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_slice_equals_char_pair_array \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_slice_equals_char_pair_array"),
"assert_char_pair_array_slice_equals_char_pair_array panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("CHAR-PAIR-SLICE-EQUALS-ARRAY-LEFT-COLUMN-VIOLATION"),
"assert_char_pair_array_slice_equals_char_pair_array panic \
message {msg:?} must name the failed AXIS (\"CHAR-PAIR-\
SLICE-EQUALS-ARRAY-LEFT-COLUMN-VIOLATION\") for axis-\
provenance-preserving failure diagnostics",
);
}
#[test]
fn assert_char_pair_array_slice_equals_char_pair_array_panic_message_names_the_helper_and_right_column_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-PAIR-SLICE-EQUALS-
// ARRAY-RIGHT-COLUMN-VIOLATION arm: the panic message MUST
// begin with the helper's own name AND identify the failed
// AXIS as "CHAR-PAIR-SLICE-EQUALS-ARRAY-RIGHT-COLUMN-
// VIOLATION" so downstream diagnostics route the drift back
// to (a) the helper by string search AND (b) the failed
// COLUMN of the paired sweep by string search on the
// RIGHT-COLUMN-* axis. Peer pin to the LEFT-COLUMN
// provenance pin above — the two pins bind the (LEFT,
// RIGHT) column-axis provenance pair at ONE test per column.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_slice_equals_char_pair_array::<5, 3, 1>(
&[('z', 'Z'), ('a', 'x'), ('b', 'y'), ('c', '!'), ('z', 'Z')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_slice_equals_char_pair_array must \
panic on a RIGHT-column drift — the reject-right-column-\
drift arm is a CONTENT failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_slice_equals_char_pair_array \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_slice_equals_char_pair_array"),
"assert_char_pair_array_slice_equals_char_pair_array panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("CHAR-PAIR-SLICE-EQUALS-ARRAY-RIGHT-COLUMN-VIOLATION"),
"assert_char_pair_array_slice_equals_char_pair_array panic \
message {msg:?} must name the failed AXIS (\"CHAR-PAIR-\
SLICE-EQUALS-ARRAY-RIGHT-COLUMN-VIOLATION\") for axis-\
provenance-preserving failure diagnostics",
);
}
// ── `assert_char_array_is_concatenation_of_char_pair_array_column_
// and_char_array` — the (char) scalar-row SEGMENTED-CONCATENATION-
// through-PAIRED-COLUMN-PROJECTION verifier that binds `arr ==
// col(head_table) ++ tail` at compile time on the substrate's Str-
// payload escape-table (`ESCAPE_SOURCES`, `NAMED_ESCAPE_TABLE`,
// `SELF_ESCAPE_TABLE`) LEFT-column-projection triple AND the
// (`ESCAPE_DECODED`, `NAMED_ESCAPE_TABLE`, `SELF_ESCAPE_TABLE`)
// RIGHT-column-projection triple, CROSS-ROW peer to the (char, char)
// paired-row (`_is_concatenation_of_char_pair_array_and_char_array_
// diagonal`) sibling on the (segmented-concatenation) column of the
// (element-type × contract-shape) matrix. The runtime test surface
// pins each of the helper's arms — accept the empty triple with
// BOTH `take_right_column` values, accept a head-only + tail-only +
// mixed small triple, accept the two family-wide substrate triples
// for each `take_right_column` value, reject at every failure-arm
// corner (CARDINALITY-MISMATCH, HEAD-SEGMENT-LEFT/RIGHT-COLUMN-
// DIVERGENCE at head/tail positions, TAIL-SEGMENT-DIVERGENCE at
// head/tail positions), pin panic-message provenance on the four
// axes — so a regression that silently weakened the helper on ANY
// arm is caught by the helper's OWN test surface rather than only
// surfacing as a false-positive on some future scalar-composite
// pin.
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_the_empty_triple_left_column(
) {
// Empty arrays at `N == K == M == 0` with `take_right_column ==
// false` — vacuously composite (no position exists to test).
// Pins the outer sweep bounds' short-circuit and the LEFT-column
// branch's dispatch on the empty head sweep.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<0, 0, 0>(
&[],
&[],
&[],
false,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_the_empty_triple_right_column(
) {
// Empty arrays at `N == K == M == 0` with `take_right_column ==
// true` — vacuously composite. Pins the RIGHT-column branch's
// dispatch on the empty head sweep.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<0, 0, 0>(
&[],
&[],
&[],
true,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_head_only_triple_left_column(
) {
// Head-only triple `arr = ['a']`, `head_table = [('a','x')]`,
// `tail = []` with `take_right_column == false` — LEFT column
// projection at position 0. Pins the `while j < M` guard's
// short-circuit on empty tail and the LEFT-column arm firing.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<1, 1, 0>(
&['a'],
&[('a', 'x')],
&[],
false,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_head_only_triple_right_column(
) {
// Head-only triple `arr = ['x']`, `head_table = [('a','x')]`,
// `tail = []` with `take_right_column == true` — RIGHT column
// projection at position 0. Pins the RIGHT-column arm firing on
// the empty-tail short-circuit.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<1, 1, 0>(
&['x'],
&[('a', 'x')],
&[],
true,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_tail_only_triple(
) {
// Tail-only triple `arr = ['q']`, `head_table = []`, `tail =
// ['q']` at the `K == 0` corner — the composite reduces to
// `tail` verbatim, no head-column projection to perform. Pins
// the outer `while i < K` guard's short-circuit on empty head
// (identical behavior on both `take_right_column` values —
// exercised here at `false`; the peer at `true` at the empty-
// triple test above already covers the RIGHT branch's empty-K
// dispatch).
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<1, 0, 1>(
&['q'],
&[],
&['q'],
false,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_mixed_small_triple_left_column(
) {
// Mixed small triple `arr = ['a', 'q']`, `head_table =
// [('a','x')]`, `tail = ['q']` at `K == 1, M == 1` with
// `take_right_column == false` — the smallest non-trivial case
// exercising BOTH the LEFT-column head-projection arm and the
// tail-verbatim arm. Pins that BOTH sweeps advance.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<2, 1, 1>(
&['a', 'q'],
&[('a', 'x')],
&['q'],
false,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_mixed_small_triple_right_column(
) {
// Mixed small triple `arr = ['x', 'q']`, `head_table =
// [('a','x')]`, `tail = ['q']` at `K == 1, M == 1` with
// `take_right_column == true` — the smallest non-trivial case
// exercising BOTH the RIGHT-column head-projection arm and the
// tail-verbatim arm.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<2, 1, 1>(
&['x', 'q'],
&[('a', 'x')],
&['q'],
true,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_the_family_wide_substrate_left_column_triple(
) {
// Positive pin on the family-wide (`Atom::ESCAPE_SOURCES`,
// `Atom::NAMED_ESCAPE_TABLE`, `Atom::SELF_ESCAPE_TABLE`,
// `take_right_column: false`) LEFT-column triple this helper
// is applied to at compile time via the module-level `const
// _:` witness. Runtime pin as a second-stage safety net if the
// const-eval sweep is ever silently dropped. Complementary to
// the pre-existing (`_pairwise_distinct`, `_within_char_
// finite_set`) witnesses on the SAME scalar array — those
// pins bind SET-level axes (INJECTIVITY, SUBSET-EMBEDDING);
// this pin binds the SEGMENTED-CONCATENATION structural
// identity axis at the (char) scalar-row cross-row bond.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array(
&Atom::ESCAPE_SOURCES,
&Atom::NAMED_ESCAPE_TABLE,
&Atom::SELF_ESCAPE_TABLE,
false,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_accepts_the_family_wide_substrate_right_column_triple(
) {
// Positive pin on the family-wide (`Atom::ESCAPE_DECODED`,
// `Atom::NAMED_ESCAPE_TABLE`, `Atom::SELF_ESCAPE_TABLE`,
// `take_right_column: true`) RIGHT-column triple this helper is
// applied to at compile time via the SECOND module-level
// `const _:` witness. Runtime pin as a second-stage safety net.
// The two family-wide RUNTIME pins (LEFT above, RIGHT here)
// mirror the two module-level `const _:` witnesses at ONE
// runtime posture per column.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array(
&Atom::ESCAPE_DECODED,
&Atom::NAMED_ESCAPE_TABLE,
&Atom::SELF_ESCAPE_TABLE,
true,
);
}
#[test]
#[should_panic(
expected = "assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"
)]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panics_at_runtime_on_head_left_column_head_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT LEFT-COLUMN head-position
// (i == 0) corner: `arr[0] = 'z'` diverges from `head_table[0].0
// = 'a'` on the FIRST head-segment position with
// `take_right_column == false`. Pins the HEAD-LEFT-COLUMN arm
// firing at the head.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 2, 1>(
&['z', 'b', 'q'],
&[('a', 'x'), ('b', 'y')],
&['q'],
false,
);
}
#[test]
#[should_panic(
expected = "assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"
)]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panics_at_runtime_on_head_left_column_tail_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT LEFT-COLUMN tail-position
// (i == K-1) corner: divergence at the LAST head-segment
// position MUST also fire. Pins the outer head-sweep bound
// `while i < K` — a regression that walked `while i < K - 1`
// would silently accept a tail-of-head divergence.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 2, 1>(
&['a', 'z', 'q'],
&[('a', 'x'), ('b', 'y')],
&['q'],
false,
);
}
#[test]
#[should_panic(
expected = "assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"
)]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panics_at_runtime_on_head_right_column_head_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT RIGHT-COLUMN head-position
// (i == 0) corner: symmetric to the HEAD-LEFT-COLUMN arm at
// the head with `take_right_column == true`. Pins the HEAD-
// RIGHT-COLUMN arm firing at position 0.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 2, 1>(
&['z', 'y', 'q'],
&[('a', 'x'), ('b', 'y')],
&['q'],
true,
);
}
#[test]
#[should_panic(
expected = "assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"
)]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panics_at_runtime_on_head_right_column_tail_position_divergence(
) {
// NEGATIVE PIN — HEAD-SEGMENT RIGHT-COLUMN tail-position
// (i == K-1) corner: divergence at the LAST head-segment
// RIGHT-column position MUST also fire. Symmetric to the
// LEFT-column tail-position arm.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 2, 1>(
&['x', 'z', 'q'],
&[('a', 'x'), ('b', 'y')],
&['q'],
true,
);
}
#[test]
#[should_panic(
expected = "assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"
)]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panics_at_runtime_on_tail_head_position_divergence(
) {
// NEGATIVE PIN — TAIL-SEGMENT head-position (j == 0) corner:
// divergence at `arr[K + 0] = 'z'` vs `tail[0] = 'q'` fires
// after the head-sweep succeeds. Pins the outer tail-sweep's
// `while j < M` guard firing at j == 0 and correctly using
// `K + j` for `arr` indexing. INDEPENDENT of
// `take_right_column` — the tail is scalar-verbatim, not
// column-projected.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 1, 2>(
&['a', 'z', 'r'],
&[('a', 'x')],
&['q', 'r'],
false,
);
}
#[test]
#[should_panic(
expected = "assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"
)]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panics_at_runtime_on_tail_tail_position_divergence(
) {
// NEGATIVE PIN — TAIL-SEGMENT tail-position (j == M-1) corner:
// divergence at the LAST tail-segment position MUST also fire.
// Pins the outer tail-sweep bound `while j < M` — a regression
// that walked `while j < M - 1` (dropping the last tail entry)
// would silently accept a tail-of-tail divergence.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 1, 2>(
&['a', 'q', 'z'],
&[('a', 'x')],
&['q', 'r'],
false,
);
}
#[test]
#[should_panic(
expected = "assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array"
)]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panics_at_runtime_on_cardinality_mismatch(
) {
// NEGATIVE PIN — CARDINALITY-MISMATCH corner: fires BEFORE any
// per-position sweep at the FIRST guard. `K + M == 3 + 3 == 6`
// vs `N == 5` — the caller's turbofish is inconsistent. A
// mistyped ARITY doesn't degenerate into a silent truncation
// of the segment sweep.
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<5, 3, 3>(
&['a', 'b', 'c', 'q', 'r'],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['q', 'r', 's'],
false,
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panic_message_names_the_helper_and_head_left_column_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — HEAD-SEGMENT-LEFT-COLUMN-
// DIVERGENCE arm: distinct axis vocabulary distinguishing this
// helper's LEFT-column head-divergence from the paired-row
// diagonal-tail sibling's `HEAD-SEGMENT-LEFT-DIVERGENCE` axis
// (this helper's `-COLUMN-` infix distinguishes them on any
// downstream substring search) AND from the sibling
// `_columns_equal_char_arrays`'s `LEFT-COLUMN-DIVERGENCE`
// axis (this helper's `HEAD-SEGMENT-` prefix distinguishes
// them).
let outcome = std::panic::catch_unwind(|| {
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 2, 1>(
&['z', 'b', 'q'],
&[('a', 'x'), ('b', 'y')],
&['q'],
false,
);
});
let payload = outcome.expect_err(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
must panic on a HEAD-SEGMENT LEFT-COLUMN head-position \
divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic payload must be a static &str or String",
);
assert!(
msg.contains("HEAD-SEGMENT-LEFT-COLUMN-DIVERGENCE"),
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic message {msg:?} must name the failed AXIS \
(\"HEAD-SEGMENT-LEFT-COLUMN-DIVERGENCE\") for axis-\
provenance-preserving failure diagnostics",
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panic_message_names_the_helper_and_head_right_column_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — HEAD-SEGMENT-RIGHT-COLUMN-
// DIVERGENCE arm: distinct axis vocabulary at the RIGHT-column
// dual of the LEFT-column head-divergence provenance arm.
let outcome = std::panic::catch_unwind(|| {
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 2, 1>(
&['z', 'y', 'q'],
&[('a', 'x'), ('b', 'y')],
&['q'],
true,
);
});
let payload = outcome.expect_err(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
must panic on a HEAD-SEGMENT RIGHT-COLUMN head-position \
divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic payload must be a static &str or String",
);
assert!(
msg.contains("HEAD-SEGMENT-RIGHT-COLUMN-DIVERGENCE"),
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic message {msg:?} must name the failed AXIS \
(\"HEAD-SEGMENT-RIGHT-COLUMN-DIVERGENCE\") for axis-\
provenance-preserving failure diagnostics",
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panic_message_names_the_helper_and_tail_segment_divergence_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — TAIL-SEGMENT-DIVERGENCE arm:
// distinct axis vocabulary distinguishing this helper's tail-
// arm from the paired-row diagonal-tail sibling's `DIAGONAL-
// TAIL-SEGMENT-{LEFT,RIGHT}-DIVERGENCE` axes (this helper's
// tail arm omits `DIAGONAL-` and `-{LEFT,RIGHT}` — the scalar
// tail is column-invariant).
let outcome = std::panic::catch_unwind(|| {
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<3, 1, 2>(
&['a', 'z', 'r'],
&[('a', 'x')],
&['q', 'r'],
false,
);
});
let payload = outcome.expect_err(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
must panic on a TAIL-SEGMENT head-position divergence",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic payload must be a static &str or String",
);
assert!(
msg.contains("TAIL-SEGMENT-DIVERGENCE"),
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic message {msg:?} must name the failed AXIS \
(\"TAIL-SEGMENT-DIVERGENCE\") for axis-provenance-\
preserving failure diagnostics",
);
}
#[test]
fn assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array_panic_message_names_the_helper_and_cardinality_mismatch_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CARDINALITY-MISMATCH arm:
// fires BEFORE any per-position sweep at a distinct axis
// vocabulary. Pins the FIRST guard's provenance so a
// diagnostic reading the axis distinguishes ARITY drift from
// CONTENT drift.
let outcome = std::panic::catch_unwind(|| {
assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array::<5, 3, 3>(
&['a', 'b', 'c', 'q', 'r'],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&['q', 'r', 's'],
false,
);
});
let payload = outcome.expect_err(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
must panic on a CARDINALITY-MISMATCH `K + M != N`",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic payload must be a static &str or String",
);
assert!(
msg.contains("CARDINALITY-MISMATCH"),
"assert_char_array_is_concatenation_of_char_pair_array_column_and_char_array \
panic message {msg:?} must name the failed AXIS \
(\"CARDINALITY-MISMATCH\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_char_pair_array_within_char_pair_finite_set` — the
// `(char, char)` product-element SUBSET-EMBEDDING verifier that
// binds `arr ⊆ set` at compile time on the paired-array vocabulary
// via CONJOINED-pair equality, peer to the (char) + (u8) +
// (`&'static str`) scalar rows' SUBSET-EMBEDDING helpers on the
// (element-type × contract-shape) matrix at the (subset-embedding)
// column. The runtime test surface pins each of the helper's arms
// (accept-empty, accept-singleton-in-set at three positions,
// accept-arr-equals-set, accept-family-wide-substrate-subset on
// the pinned `NAMED_ESCAPE_TABLE ⊆ ESCAPE_TABLE` pair, accept-
// repeated-array-entries-in-set, reject-out-of-set-pair, reject-
// terminal-out-of-set-pair, reject-cross-row-alias, panic-message-
// provenance on the CHAR-PAIR-SUBSET-VIOLATION axis, negative pin
// on the DELEGATED SET-side BIJECTIVITY well-formedness arm at
// BOTH the LEFT-column and RIGHT-column collision corners) so a
// regression that silently weakened the helper on ANY arm is
// caught by the helper's OWN test surface rather than only
// surfacing as a false-positive on some future subset-embedded
// `[(char, char); N]` array's compound pin.
#[test]
fn assert_char_pair_array_within_char_pair_finite_set_accepts_the_empty_array_within_any_set() {
// Empty array `arr = []` at the `[(char, char); 0]` corner —
// vacuously a subset of every well-formed BIJECTIVE set (no
// `i` position exists to test). Cross-arity coverage on the
// trivial ARRAY corner of the const-N generic across three
// witness-set widths (empty, singleton, multi-entry) to pin
// the helper's OUTER-sweep arm across the whole (`N == 0` ×
// `M`) axis. Turbofish binding required because there's no
// other cue for the const parameters on the empty array
// literal. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_the_empty_array_within_any_set`
// on the (char) scalar row-dual peer — the two share the
// trivial-arity arm across the (scalar, paired) element-type
// partition on the (subset-embedding) column.
assert_char_pair_array_within_char_pair_finite_set::<0, 0>(&[], &[]);
assert_char_pair_array_within_char_pair_finite_set::<0, 1>(&[], &[('a', 'x')]);
assert_char_pair_array_within_char_pair_finite_set::<0, 3>(
&[],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
fn assert_char_pair_array_within_char_pair_finite_set_accepts_singleton_array_when_pair_in_set()
{
// Singleton array `arr = [P]` at the `[(char, char); 1]`
// corner MUST pass when `P ∈ set` by CONJOINED-pair equality.
// Cross-position coverage: the pair can sit at the FIRST,
// MIDDLE, or LAST position of the `set` — pins the INNER
// `while j < M` sweep terminates at the first-match position
// rather than always at position `0` OR always at position
// `M - 1`. A regression that narrowed the inner sweep to
// `j == 0` would silently reject singleton arrays hitting
// non-first set positions. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_singleton_array_when_char_in_set`
// on the (char) scalar row-dual peer — the two share the
// FIRST/MIDDLE/LAST sweep-position arm across the (scalar,
// paired) element-type partition.
assert_char_pair_array_within_char_pair_finite_set::<1, 3>(
&[('a', 'x')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
assert_char_pair_array_within_char_pair_finite_set::<1, 3>(
&[('b', 'y')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
assert_char_pair_array_within_char_pair_finite_set::<1, 3>(
&[('c', 'z')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
fn assert_char_pair_array_within_char_pair_finite_set_accepts_arr_equals_set() {
// Boundary corner where `arr` and `set` cover pair-for-pair
// identical distinct-value sets — the SUBSET relation
// degenerates to EQUALITY. Pins that the helper does NOT
// gratuitously require the SUBSET to be PROPER (strict):
// equal-multisets pass the SUBSET check. Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_arr_equals_set`
// on the (char) scalar row-dual peer.
assert_char_pair_array_within_char_pair_finite_set(&[('a', 'x')], &[('a', 'x')]);
assert_char_pair_array_within_char_pair_finite_set(
&[('a', 'x'), ('b', 'y')],
&[('a', 'x'), ('b', 'y')],
);
}
#[test]
fn assert_char_pair_array_within_char_pair_finite_set_accepts_the_family_wide_substrate_subset()
{
// Runtime cross-check that the ONE (subset, superset)
// paired-array pair the substrate's module-level `const _`
// witness pins at COMPILE time is a proper SUBSET embedding
// at runtime too. The pair enforces the theorem at TWO stages
// of the toolchain: the const witness fires FIRST at `cargo
// check` (through the module-level `const _: () =
// assert_char_pair_array_within_char_pair_finite_set::<3, 5>(...)`
// line), this runtime pin catches the drift at `cargo test`
// as a safety net. Sibling posture to
// `assert_char_pair_array_bijective_accepts_every_family_wide_substrate_array`
// which sweeps the two family-wide `[(char, char); N]` arrays
// at the paired-array INJECTIVITY axis; this pin sweeps the
// ONE (subset, superset) PAIR at the paired-array SUBSET-
// EMBEDDING axis. Together the two pins bind the (paired
// array, paired subset-embedding) 2-corner face on the
// `(char, char)` row of the (element-type × contract-shape)
// matrix.
assert_char_pair_array_within_char_pair_finite_set::<3, 5>(
&Atom::NAMED_ESCAPE_TABLE,
&Atom::ESCAPE_TABLE,
);
}
#[test]
fn assert_char_pair_array_within_char_pair_finite_set_accepts_repeated_array_entries_in_set() {
// Peer corner to a (future-lift) `_covers_char_pair_finite_
// set`: this helper permits duplicates in `arr` because
// SUBSET-membership is a DISTINCT-value predicate — the
// pair-multiset `[('a', 'x'), ('a', 'x'), ('b', 'y')]` is a
// subset of the bijective set `{('a', 'x'), ('b', 'y'),
// ('c', 'z')}` even though the array is not pairwise-
// distinct. Pins that the helper does NOT gratuitously
// require BIJECTIVITY on `arr` (the BIJECTIVITY axis is a
// DIFFERENT compile-time contract bound by
// `assert_char_pair_array_bijective`; combining both binds
// BOTH axes). Sibling posture to
// `assert_char_array_within_char_finite_set_accepts_repeated_array_entries_in_set`
// on the (char) scalar row-dual peer.
assert_char_pair_array_within_char_pair_finite_set(
&[('a', 'x'), ('a', 'x'), ('b', 'y')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
#[should_panic(expected = "CHAR-PAIR-SUBSET-VIOLATION")]
fn assert_char_pair_array_within_char_pair_finite_set_panics_at_runtime_on_out_of_set_pair() {
// NEGATIVE PIN — CHAR-PAIR-SUBSET-VIOLATION corner: an array
// carrying a single pair NOT in the target set MUST panic at
// runtime with the CHAR-PAIR-SUBSET-VIOLATION-named message.
// Pins the helper's OWN reject arm — a regression that
// silently returned without panicking on an out-of-set pair
// would slip through the compile-time witness's failure mode
// too. The offending pair `('z', 'w')` is intentionally
// chosen OUTSIDE the target set to pin the OUT-OF-SET drift
// mode.
assert_char_pair_array_within_char_pair_finite_set(
&[('a', 'x'), ('z', 'w')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
#[should_panic(expected = "CHAR-PAIR-SUBSET-VIOLATION")]
fn assert_char_pair_array_within_char_pair_finite_set_panics_at_runtime_on_terminal_out_of_set_pair(
) {
// NEGATIVE PIN — terminal-position drift: an out-of-set pair
// at the LAST array position MUST panic — pins that the
// outer `while i < N` loop reaches `i = N - 1` (else the
// terminal drift would slip through). A regression that
// narrowed the outer sweep to `while i < N - 1` (off-by-one
// on the OUTER bound) would silently accept this array.
// Sibling posture to
// `assert_char_array_within_char_finite_set_panics_at_runtime_on_terminal_out_of_set_entry`
// on the (char) scalar row-dual peer — both bind the outer-
// sweep terminal bound at the ONE array-side outer loop the
// helper carries.
assert_char_pair_array_within_char_pair_finite_set(
&[('a', 'x'), ('b', 'y'), ('c', 'z'), ('z', 'w')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
#[should_panic(expected = "CHAR-PAIR-SUBSET-VIOLATION")]
fn assert_char_pair_array_within_char_pair_finite_set_panics_at_runtime_on_cross_row_alias_pair(
) {
// KEY LOAD-BEARING NEGATIVE PIN — CONJOINED-pair equality
// gate corner: a pair whose LEFT column matches ONE set
// entry's LEFT column AND whose RIGHT column matches a
// DIFFERENT set entry's RIGHT column but the CONJOINED pair
// itself is NOT in the set MUST panic. This is the exact
// property that distinguishes the CONJOINED-pair SUBSET
// helper from a per-column-membership check: a regression
// that silently split the CONJOINED equality gate into TWO
// separate per-column membership sweeps (one over the LEFT
// column, one over the RIGHT column) would accept the pair
// `('a', 'y')` here (`'a'` appears in the set's LEFT column
// via `('a', 'x')`, `'y'` appears in the set's RIGHT column
// via `('b', 'y')`), but the CONJOINED pair `('a', 'y')` is
// NOT in the set. A drift from `&&` to `||` on the CONJOINED
// gate would silently accept this cross-row aliasing pair.
assert_char_pair_array_within_char_pair_finite_set(
&[('a', 'y')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
}
#[test]
fn assert_char_pair_array_within_char_pair_finite_set_panic_message_names_the_helper_and_char_pair_subset_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-PAIR-SUBSET-VIOLATION
// arm: the panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "CHAR-PAIR-SUBSET-
// VIOLATION" so downstream diagnostics route the drift back
// to (a) the helper by string search on
// `"assert_char_pair_array_within_char_pair_finite_set"` and
// (b) the axis by string search on `"CHAR-PAIR-SUBSET-
// VIOLATION"`. Sibling posture to
// `assert_char_array_within_char_finite_set_panic_message_names_the_helper_and_char_subset_violation_axis`
// on the (char) scalar row-dual peer's provenance pin — the
// two pins together bind the (helper, failed-axis)
// provenance pair at ONE test per SUBSET helper on the
// (element-type × contract-shape) matrix's SUBSET column.
// The axis-provenance string `"CHAR-PAIR-SUBSET-VIOLATION"`
// is chosen DISTINCT from EVERY sibling helper's axis
// vocabulary (`"CHAR-SUBSET-VIOLATION"` on the (char) scalar
// row-dual SUBSET peer; `"SUBSET-VIOLATION"` on the (u8)
// scalar row-dual finite-set SUBSET peer; `"STR-SUBSET-
// VIOLATION"` on the (`&'static str`) scalar row-dual
// SUBSET peer; `"RANGE-SUBSET-VIOLATION"` on the (u8) range
// SUBSET peer; `"CHAR-DISJOINTNESS-VIOLATION"` / `"U8-
// DISJOINTNESS-VIOLATION"` / `"STR-DISJOINTNESS-VIOLATION"`
// on the DISJOINTNESS-column row peers; `"LEFT column"` /
// `"RIGHT column"` on the paired-array BIJECTIVITY sibling)
// so a diagnostic that names the failed axis routes
// UNAMBIGUOUSLY to (a) this specific paired-array SUBSET-
// embedding helper, (b) the `arr` argument as the drift
// site rather than the `set` argument specifying the target
// paired superset.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_array_within_char_pair_finite_set(
&[('a', 'x'), ('z', 'w')],
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
);
});
let payload = outcome.expect_err(
"assert_char_pair_array_within_char_pair_finite_set must \
panic on an out-of-set pair — the reject-out-of-set arm \
is the sole CHAR-PAIR-SUBSET-VIOLATION failure mode of \
the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_array_within_char_pair_finite_set \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_array_within_char_pair_finite_set"),
"assert_char_pair_array_within_char_pair_finite_set \
panic message {msg:?} must name the helper for \
provenance-preserving failure diagnostics",
);
assert!(
msg.contains("CHAR-PAIR-SUBSET-VIOLATION"),
"assert_char_pair_array_within_char_pair_finite_set \
panic message {msg:?} must name the failed AXIS \
(\"CHAR-PAIR-SUBSET-VIOLATION\") for axis-provenance-\
preserving failure diagnostics",
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_bijective")]
fn assert_char_pair_array_within_char_pair_finite_set_panics_on_malformed_target_set_left_column_collision(
) {
// NEGATIVE PIN — DELEGATED SET-side BIJECTIVITY well-
// formedness at the LEFT-column collision corner: a
// malformed target-set spec `[('a', 'x'), ('a', 'y')]`
// (LEFT-column duplicate `'a'`) fed into the ARRAY-side
// within helper MUST panic on the DELEGATED bijectivity arm
// BEFORE the CHAR-PAIR-SUBSET-VIOLATION arm fires. Pins the
// delegation chain: a regression that dropped the
// `assert_char_pair_array_bijective(set)` call at the top of
// `assert_char_pair_array_within_char_pair_finite_set` would
// silently accept a malformed set and produce a false-
// positive verdict on any `arr` embedded in the distinct-
// value bijective subset. The panic message here surfaces
// from the SIBLING helper (containing the paired-array
// BIJECTIVITY helper's `"assert_char_pair_array_bijective"`
// panic-name prefix rather than a bespoke `"SET-NOT-
// BIJECTIVE"` axis string) because the paired row's
// delegation reuses the ARRAY-side BIJECTIVITY helper
// directly per the design choice documented on the SET-side-
// well-formedness section of the helper's docstring. Sibling
// posture to
// `assert_char_array_within_char_finite_set_panics_on_malformed_target_set_spec`
// on the (char) scalar row-dual peer's delegated-SET-well-
// formedness pin. Peer corner to the RIGHT-column companion
// pin below.
assert_char_pair_array_within_char_pair_finite_set::<1, 2>(
&[('a', 'x')],
&[('a', 'x'), ('a', 'y')],
);
}
#[test]
#[should_panic(expected = "assert_char_pair_array_bijective")]
fn assert_char_pair_array_within_char_pair_finite_set_panics_on_malformed_target_set_right_column_collision(
) {
// NEGATIVE PIN — DELEGATED SET-side BIJECTIVITY well-
// formedness at the RIGHT-column collision corner: a
// malformed target-set spec `[('a', 'x'), ('b', 'x')]`
// (RIGHT-column duplicate `'x'`) fed into the ARRAY-side
// within helper MUST panic on the DELEGATED bijectivity arm
// BEFORE the CHAR-PAIR-SUBSET-VIOLATION arm fires. Column-
// symmetric sibling to the LEFT-column pin above — a
// regression that silently narrowed the delegated
// bijectivity sweep to only the LEFT column (dropping the
// RIGHT-column injectivity half) would slip a RIGHT-column-
// colliding set past the delegation while still binding a
// LEFT-column-colliding one. The two pins together bind the
// FULL bijectivity delegation across BOTH columns of the
// paired-array well-formedness contract.
assert_char_pair_array_within_char_pair_finite_set::<1, 2>(
&[('a', 'x')],
&[('a', 'x'), ('b', 'x')],
);
}
// ── `assert_char_pair_arrays_disjoint` — the CHAR-PAIR-DISJOINTNESS-
// VIOLATION verifier that binds `a ∩ b = ∅` at compile time on the
// paired-array vocabulary via CONJOINED-pair equality, peer to the
// (char) + (u8) + (`&'static str`) SCALAR rows' DISJOINTNESS helpers
// on the (element-type × contract-shape) matrix at the (disjointness)
// column. Contract-orthogonal peer to
// `assert_char_pair_array_within_char_pair_finite_set` on the
// (SUBSET-EMBEDDING, DISJOINTNESS) axis of the (contract-shape)
// column on the SAME paired-array row. The runtime test surface
// pins each of the helper's arms (accept-empty × 3, accept-disjoint
// singletons, accept-family-wide-substrate-pair on the pinned
// `NAMED_ESCAPE_TABLE` disjoint from SELF-as-pairs partition,
// accept-per-column-alias-only corner (the CONJOINED-gate load-
// bearing NON-INSTANCE of the stricter per-column disjointness
// contract), reject-full-pair-collision, reject-terminal-position
// collision, argument-order symmetry, panic-message provenance on
// the CHAR-PAIR-DISJOINTNESS-VIOLATION axis) so a regression that
// silently weakened the helper on ANY arm is caught by the helper's
// OWN test surface rather than only surfacing as a false-positive on
// some future disjoint `[(char, char); N]` paired-array pair's
// compound pin.
#[test]
fn assert_char_pair_arrays_disjoint_accepts_both_empty_arrays() {
// Empty × empty at the `[(char, char); 0] × [(char, char); 0]`
// corner — vacuously disjoint (no `(i, j)` position pair exists
// to test). The module-level `const _: () =
// assert_char_pair_arrays_disjoint(&[], &[])` witness would bind
// this at compile time; this runtime pin catches the drift a
// second time at test-run stage as a safety net. Turbofish
// binding required because there's no other cue for the const
// parameters on the two empty array literals. Sibling posture
// to `assert_char_arrays_disjoint_accepts_both_empty_arrays` on
// the (char) SCALAR row-dual peer.
assert_char_pair_arrays_disjoint::<0, 0>(&[], &[]);
}
#[test]
fn assert_char_pair_arrays_disjoint_accepts_either_side_empty() {
// Empty × non-empty (and non-empty × empty) at the outer-loop-
// vacuous corners — the outer `while i < N` sweep terminates
// immediately when `N == 0`, and the outer sweep executing with
// a non-empty `a` against an empty `b` finds no `j` to test
// (inner sweep vacuous). Cross-position coverage on the two
// vacuous outer arms. Sibling posture to
// `assert_char_arrays_disjoint_accepts_either_side_empty` on the
// (char) SCALAR row-dual peer — the two share the vacuous-arm
// arm across the (scalar, paired) element-type partition on the
// (disjointness) column.
assert_char_pair_arrays_disjoint::<0, 3>(&[], &[('a', 'x'), ('b', 'y'), ('c', 'z')]);
assert_char_pair_arrays_disjoint::<3, 0>(&[('a', 'x'), ('b', 'y'), ('c', 'z')], &[]);
}
#[test]
fn assert_char_pair_arrays_disjoint_accepts_disjoint_singletons() {
// Singleton × singleton at the `[(char, char); 1] × [(char,
// char); 1]` corner with the two pairs distinct across BOTH
// columns — the minimal non-vacuous accept arm. Pins the
// CONJOINED-pair equality gate does NOT gratuitously match when
// BOTH columns differ. Sibling posture to
// `assert_char_arrays_disjoint_accepts_disjoint_singletons` on
// the (char) SCALAR row-dual peer.
assert_char_pair_arrays_disjoint(&[('a', 'x')], &[('b', 'y')]);
}
#[test]
fn assert_char_pair_arrays_disjoint_accepts_the_family_wide_substrate_pair() {
// Runtime cross-check that the ONE (a, b) paired-array pair the
// substrate's module-level `const _` witness pins at COMPILE
// time is a proper DISJOINT relation at runtime too. The pair
// enforces the theorem at TWO stages of the toolchain: the
// const witness fires FIRST at `cargo check` (through the
// module-level `const _: () = assert_char_pair_arrays_disjoint::
// <3, 2>(...)` line), this runtime pin catches the drift at
// `cargo test` as a safety net. Sibling posture to
// `assert_char_pair_array_within_char_pair_finite_set_accepts_
// the_family_wide_substrate_subset` which sweeps the ONE (arr,
// set) pair at the paired-array SUBSET-EMBEDDING axis; this pin
// sweeps the ONE (a, b) pair at the paired-array DISJOINTNESS
// axis. Together the two pins bind the (paired subset-
// embedding, paired disjointness) 2-corner face on the
// `(char, char)` row of the (element-type × contract-shape)
// matrix. The `NAMED_ESCAPE_TABLE` disjoint from SELF-as-pairs
// partition of `ESCAPE_TABLE` is the substrate-load-bearing
// instance: a NAMED escape source `('n' / 't' / 'r')` cannot
// simultaneously ALSO be a SELF-escape source `STR_DELIMITER /
// STR_ESCAPE_LEAD` — the two sub-vocabularies of
// `Atom::decode_str_escape` MUST partition disjointly to route
// each escape byte through EXACTLY ONE arm.
assert_char_pair_arrays_disjoint::<3, 2>(
&Atom::NAMED_ESCAPE_TABLE,
&[
(Atom::SELF_ESCAPE_TABLE[0], Atom::SELF_ESCAPE_TABLE[0]),
(Atom::SELF_ESCAPE_TABLE[1], Atom::SELF_ESCAPE_TABLE[1]),
],
);
}
#[test]
fn assert_char_pair_arrays_disjoint_accepts_per_column_alias_when_conjoined_pair_differs() {
// KEY LOAD-BEARING ACCEPT PIN — CONJOINED-pair equality gate
// NON-INSTANCE corner: two paired arrays whose LEFT columns
// share an entry OR whose RIGHT columns share an entry but the
// CONJOINED pairs themselves differ MUST be accepted as
// disjoint. This is the exact property that distinguishes the
// CONJOINED-pair DISJOINTNESS helper from a stricter per-column
// disjointness check: a regression that split the CONJOINED
// equality gate into TWO separate per-column membership sweeps
// (one over the LEFT column, one over the RIGHT column) would
// REJECT the pair `(&[('a', 'x')], &[('a', 'y')])` here as a
// false-positive collision (`'a'` appears in BOTH arrays' LEFT
// columns via `('a', 'x')` and `('a', 'y')` respectively), but
// the CONJOINED pairs `('a', 'x')` and `('a', 'y')` themselves
// differ so the paired arrays ARE disjoint. A drift from `&&`
// to `||` on the CONJOINED gate would silently REJECT this
// per-column-alias corner as a false-positive collision.
// Symmetric pin on the RIGHT-column-alias-only sibling corner
// — the two together bind the CONJOINED-gate semantics across
// BOTH column-alias arms. Peer to
// `assert_char_pair_array_within_char_pair_finite_set_panics_at_
// runtime_on_cross_row_alias_pair` on the SUBSET-EMBEDDING
// sibling's dual corner — where the SUBSET helper REJECTS the
// cross-row alias pair as NOT-in-set, this DISJOINTNESS helper
// ACCEPTS the analogous per-column alias as disjoint (the two
// contract shapes flip the accept/reject arm across the
// CONJOINED-gate corner).
assert_char_pair_arrays_disjoint(&[('a', 'x')], &[('a', 'y')]);
assert_char_pair_arrays_disjoint(&[('a', 'x')], &[('b', 'x')]);
}
#[test]
#[should_panic(expected = "CHAR-PAIR-DISJOINTNESS-VIOLATION")]
fn assert_char_pair_arrays_disjoint_panics_at_runtime_on_collision() {
// NEGATIVE PIN — CHAR-PAIR-DISJOINTNESS-VIOLATION corner: two
// paired arrays sharing a CONJOINED pair MUST panic at runtime
// with the CHAR-PAIR-DISJOINTNESS-VIOLATION-named message.
// Pins the helper's OWN reject arm — a regression that
// silently returned without panicking on a shared pair would
// slip through the compile-time witness's failure mode too.
// The offending pair `('b', 'y')` is intentionally chosen to
// appear in BOTH arrays at their MIDDLE positions to pin that
// the reject arm fires from an interior-position collision (not
// only a first-position or last-position degenerate corner).
assert_char_pair_arrays_disjoint(
&[('a', 'x'), ('b', 'y'), ('c', 'z')],
&[('p', 'q'), ('b', 'y'), ('r', 's')],
);
}
#[test]
#[should_panic(expected = "CHAR-PAIR-DISJOINTNESS-VIOLATION")]
fn assert_char_pair_arrays_disjoint_panics_at_runtime_on_terminal_position_collision() {
// NEGATIVE PIN — terminal-position drift: a shared CONJOINED
// pair at the LAST position of BOTH arrays MUST panic — pins
// that BOTH the outer `while i < N` and inner `while j < M`
// loops reach their terminal indices (else the terminal drift
// would slip through). A regression that narrowed EITHER
// bound to `< N - 1` / `< M - 1` (off-by-one on the OUTER or
// INNER bound) would silently accept this array pair. Peer
// sibling posture to
// `assert_char_pair_array_within_char_pair_finite_set_panics_
// at_runtime_on_terminal_out_of_set_pair` on the SUBSET-
// EMBEDDING helper — both bind the terminal-position sweep
// arm on the paired-array row.
assert_char_pair_arrays_disjoint(&[('a', 'x'), ('z', 'w')], &[('p', 'q'), ('z', 'w')]);
}
#[test]
fn assert_char_pair_arrays_disjoint_is_symmetric_in_argument_order() {
// SYMMETRY PIN — the disjointness relation is symmetric in
// `(a, b)` so swapping arguments at the call site MUST produce
// the SAME verdict (accept remains accept, reject remains
// reject). Pins the two-loop sweep visits every `(i, j) ∈
// [0, N) × [0, M)` pair without gratuitous argument-order
// preference. Sibling posture to
// `assert_char_arrays_disjoint_is_symmetric_in_argument_order`
// on the (char) SCALAR row-dual peer — the two share the
// symmetric-relation arm across the (scalar, paired) element-
// type partition on the (disjointness) column.
assert_char_pair_arrays_disjoint(&[('a', 'x'), ('b', 'y')], &[('c', 'z'), ('d', 'w')]);
assert_char_pair_arrays_disjoint(&[('c', 'z'), ('d', 'w')], &[('a', 'x'), ('b', 'y')]);
let swap_left_rejects = std::panic::catch_unwind(|| {
assert_char_pair_arrays_disjoint(&[('a', 'x')], &[('a', 'x')]);
})
.is_err();
let swap_right_rejects = std::panic::catch_unwind(|| {
assert_char_pair_arrays_disjoint(&[('a', 'x')], &[('a', 'x')]);
})
.is_err();
assert!(
swap_left_rejects && swap_right_rejects,
"assert_char_pair_arrays_disjoint must reject a shared \
CONJOINED pair regardless of which argument carries the \
`a` role vs. the `b` role — the disjointness relation \
is symmetric in argument order",
);
}
#[test]
fn assert_char_pair_arrays_disjoint_panic_message_names_the_helper_and_char_pair_disjointness_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — CHAR-PAIR-DISJOINTNESS-
// VIOLATION arm: the panic message MUST begin with the
// helper's own name AND identify the failed AXIS as "CHAR-
// PAIR-DISJOINTNESS-VIOLATION" so downstream diagnostics
// route the drift back to (a) the helper by string search on
// `"assert_char_pair_arrays_disjoint"` and (b) the axis by
// string search on `"CHAR-PAIR-DISJOINTNESS-VIOLATION"`.
// Sibling posture to
// `assert_char_arrays_disjoint_panic_message_names_the_helper_
// and_char_disjointness_violation_axis` +
// `assert_str_arrays_disjoint_panic_message_names_the_helper_
// and_str_disjointness_violation_axis` +
// `assert_u8_arrays_disjoint_panic_message_names_the_helper_
// and_u8_disjointness_violation_axis` on the SCALAR row-dual
// provenance pins. The axis-provenance string `"CHAR-PAIR-
// DISJOINTNESS-VIOLATION"` is chosen DISTINCT from EVERY
// sibling helper's axis vocabulary (`"CHAR-DISJOINTNESS-
// VIOLATION"` on the (char) SCALAR row-dual DISJOINTNESS
// peer; `"U8-DISJOINTNESS-VIOLATION"` on the (u8) SCALAR row-
// dual peer; `"STR-DISJOINTNESS-VIOLATION"` on the
// (`&'static str`) SCALAR row-dual peer; `"CHAR-PAIR-SUBSET-
// VIOLATION"` on the paired-array SUBSET-embedding sibling;
// `"LEFT column"` / `"RIGHT column"` on the paired-array
// BIJECTIVITY sibling) so a diagnostic that names the failed
// axis routes UNAMBIGUOUSLY to (a) this specific paired-array
// DISJOINTNESS helper, (b) the failed axis-shape by the
// `"DISJOINTNESS-VIOLATION"` suffix stem shared with the
// three SCALAR row-dual siblings.
let outcome = std::panic::catch_unwind(|| {
assert_char_pair_arrays_disjoint(&[('a', 'x')], &[('a', 'x')]);
});
let payload = outcome.expect_err(
"assert_char_pair_arrays_disjoint must panic on a shared \
CONJOINED pair — the reject-on-collision arm is the sole \
CHAR-PAIR-DISJOINTNESS-VIOLATION failure mode of the \
helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_char_pair_arrays_disjoint panic payload must \
be a static &str or String",
);
assert!(
msg.contains("assert_char_pair_arrays_disjoint"),
"assert_char_pair_arrays_disjoint panic message {msg:?} \
must name the helper for provenance-preserving failure \
diagnostics",
);
assert!(
msg.contains("CHAR-PAIR-DISJOINTNESS-VIOLATION"),
"assert_char_pair_arrays_disjoint panic message {msg:?} \
must name the failed AXIS (\"CHAR-PAIR-DISJOINTNESS-\
VIOLATION\") for axis-provenance-preserving failure \
diagnostics",
);
}
// ── `assert_u8_array_covers_inclusive_range` — the SURJECTIVITY-
// onto-a-range peer of `assert_u8_array_pairwise_distinct`'s
// INJECTIVITY axis on the SAME `u8` cache-key element type. Where
// the four sibling distinctness/bijectivity helpers close the
// pairwise-DISTINCTNESS axis of the substrate's typed-array
// vocabulary, this range-coverage helper opens the SURJECTIVITY-
// onto-a-range axis at four family-wide `[u8; N]` arrays whose
// distinct-value sets are intentionally-closed inclusive ranges
// (`AtomKind::HASH_DISCRIMINATORS` covers `{0..=5}`, `QuoteForm::
// HASH_DISCRIMINATORS` covers `{3..=6}`, `UnquoteForm::HASH_
// DISCRIMINATORS` covers `{5..=6}`, `SexpShape::HASH_DISCRIMINATORS`
// covers `{0..=6}` with a load-bearing six-fold collapse at `1u8`).
// The runtime test surface matches the sibling-helpers' shape
// (accept-singleton, accept-with-duplicates, accept-every-family-
// wide-substrate-array, reject-above-HI, reject-below-LO, reject-
// missing-range-byte, panic-message-provenance on the RANGE-BOUND
// axis, panic-message-provenance on the FULL-COVERAGE axis) split
// across BOTH axes so a regression that silently weakens the
// helper on EITHER axis (e.g. dropping the `arr[i] < LO || arr[i]
// > HI` guard, or dropping the `while cur <= HI` full-coverage
// sweep) is caught by the helper's OWN test surface rather than
// only surfacing as a false-positive on some future range-
// covering `[u8; N]` array's coverage pin.
#[test]
fn assert_u8_array_covers_inclusive_range_accepts_the_singleton_range() {
// Singleton range `{K..=K}` at the `[u8; 1]` corner —
// vacuously covering (the one entry MUST equal the one range
// byte). Cross-arity coverage on the trivial-range corner of
// the const-N generic; simultaneously pins BOTH axes (RANGE-
// BOUND: `K in [K, K]`; FULL-COVERAGE: `K` appears in the
// singleton array) at the smallest witness.
assert_u8_array_covers_inclusive_range::<1, 7, 7>(&[7u8]);
assert_u8_array_covers_inclusive_range::<1, 0, 0>(&[0u8]);
assert_u8_array_covers_inclusive_range::<1, 255, 255>(&[255u8]);
}
#[test]
fn assert_u8_array_covers_inclusive_range_accepts_arrays_with_duplicates() {
// KEY LOAD-BEARING PIN: duplicates in the entries are ACCEPTED
// — the range-coverage contract is non-injective on the
// ENTRIES axis, only requires each RANGE byte to appear. This
// is the exact property that distinguishes this helper from
// its `assert_u8_array_pairwise_distinct` sibling and lets
// `SexpShape::HASH_DISCRIMINATORS`'s six-fold collapse at
// `1u8` bind a compile-time coverage witness despite failing
// distinctness. A regression that added a pairwise-distinct
// guard on the entries axis (accidentally merging the two
// sibling helpers' contracts) would fail-loudly here.
assert_u8_array_covers_inclusive_range::<4, 0, 2>(&[0u8, 1u8, 1u8, 2u8]);
assert_u8_array_covers_inclusive_range::<7, 0, 2>(&[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 2u8]);
}
#[test]
fn assert_u8_array_covers_inclusive_range_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME four range-covering arrays
// the module-level `const _: () = ...` witnesses cover at
// COMPILE time are range-covering. A regression that removes
// ONE of the `const _` witnesses would still leave THIS
// runtime pin as a safety net; the const witness fires FIRST
// at `cargo check`, this runtime pin catches the drift at
// `cargo test`. The pair enforces the theorem at TWO stages of
// the toolchain. Sibling posture to
// `assert_char_pair_array_bijective_accepts_every_family_wide_
// substrate_array` at the paired-array vocabulary.
assert_u8_array_covers_inclusive_range::<12, 0, 6>(
&crate::error::SexpShape::HASH_DISCRIMINATORS,
);
assert_u8_array_covers_inclusive_range::<6, 0, 5>(&AtomKind::HASH_DISCRIMINATORS);
assert_u8_array_covers_inclusive_range::<4, 3, 6>(&QuoteForm::HASH_DISCRIMINATORS);
assert_u8_array_covers_inclusive_range::<2, 5, 6>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
);
}
#[test]
#[should_panic(expected = "OUT-OF-RANGE")]
fn assert_u8_array_covers_inclusive_range_panics_at_runtime_on_entry_above_hi() {
// NEGATIVE PIN — RANGE-BOUND above-HI corner: an entry
// `HI + 1` MUST panic at runtime with the RANGE-BOUND-named
// message. Pins the helper's OWN reject-above-HI arm — a
// regression that silently returned without panicking on an
// out-of-range entry above the upper bound would slip through
// the compile-time witnesses' failure mode too.
assert_u8_array_covers_inclusive_range::<3, 0, 2>(&[0u8, 1u8, 3u8]);
}
#[test]
#[should_panic(expected = "OUT-OF-RANGE")]
fn assert_u8_array_covers_inclusive_range_panics_at_runtime_on_entry_below_lo() {
// NEGATIVE PIN — RANGE-BOUND below-LO corner: an entry
// `LO - 1` MUST panic at runtime with the RANGE-BOUND-named
// message. Symmetric sibling to the above-HI pin — a
// regression that dropped the `arr[i] < LO` half of the
// OR-disjunction guard (leaving only the `arr[i] > HI` half)
// would silently accept below-LO entries.
assert_u8_array_covers_inclusive_range::<3, 1, 3>(&[0u8, 1u8, 2u8]);
}
#[test]
#[should_panic(expected = "MISSING")]
fn assert_u8_array_covers_inclusive_range_panics_at_runtime_on_missing_range_byte() {
// NEGATIVE PIN — FULL-COVERAGE corner: a range byte NOT
// reached by any entry MUST panic at runtime with the FULL-
// COVERAGE-named message. Pins the helper's OWN reject-
// incomplete-coverage arm — a regression that silently
// returned without panicking on an incomplete-coverage array
// (e.g. dropping the `while cur <= HI` sweep entirely, or
// narrowing it to `while cur < HI`) would slip through the
// compile-time witnesses' failure mode too. The three entries
// stay within `[0, 3]` (satisfying RANGE-BOUND) but skip the
// middle byte `2u8` — the panic MUST fire specifically on
// the FULL-COVERAGE axis, not on the RANGE-BOUND axis.
assert_u8_array_covers_inclusive_range::<3, 0, 3>(&[0u8, 1u8, 3u8]);
}
#[test]
fn assert_u8_array_covers_inclusive_range_panic_message_names_the_helper_and_range_bound_axis()
{
// PANIC-MESSAGE PROVENANCE PIN — RANGE-BOUND arm: the panic
// message MUST begin with the helper's own name AND identify
// the failed AXIS as "OUT-OF-RANGE" so downstream diagnostics
// route the drift back to (a) the helper by string search on
// `"assert_u8_array_covers_inclusive_range"` and (b) the axis
// by string search on `"OUT-OF-RANGE"`. Sibling posture to
// `assert_char_pair_array_bijective_panic_message_names_the_
// helper_and_left_column` on the paired-array bijectivity
// helper's LEFT-column arm — both bind the (helper, failed-
// axis) provenance pair at ONE test per axis.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_covers_inclusive_range::<3, 0, 2>(&[0u8, 1u8, 3u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_covers_inclusive_range must panic on an \
out-of-range entry — the reject-out-of-range arm is one \
of the two failure modes of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_covers_inclusive_range panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_covers_inclusive_range"),
"assert_u8_array_covers_inclusive_range RANGE-BOUND panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("OUT-OF-RANGE"),
"assert_u8_array_covers_inclusive_range RANGE-BOUND panic \
message {msg:?} must name the failed AXIS (\"OUT-OF-\
RANGE\") for axis-provenance-preserving failure \
diagnostics",
);
}
#[test]
fn assert_u8_array_covers_inclusive_range_panic_message_names_the_helper_and_full_coverage_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — FULL-COVERAGE arm: the panic
// message MUST begin with the helper's own name AND identify
// the failed AXIS as "MISSING" so downstream diagnostics route
// the drift back to (a) the helper by string search and (b)
// the axis by string search on `"MISSING"`. Axis-symmetric
// sibling of the RANGE-BOUND panic-message provenance pin
// above — a regression that silently unified the two panic
// sites into ONE axis-anonymous message would collapse EITHER
// this pin's `"MISSING"` substring assertion OR the sibling
// pin's `"OUT-OF-RANGE"` substring assertion.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_covers_inclusive_range::<3, 0, 3>(&[0u8, 1u8, 3u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_covers_inclusive_range must panic on a \
missing range byte — the reject-incomplete-coverage arm \
is one of the two failure modes of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_covers_inclusive_range panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_covers_inclusive_range"),
"assert_u8_array_covers_inclusive_range FULL-COVERAGE panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("MISSING"),
"assert_u8_array_covers_inclusive_range FULL-COVERAGE panic \
message {msg:?} must name the failed AXIS (\"MISSING\") \
for axis-provenance-preserving failure diagnostics",
);
}
// ── `assert_u8_array_covers_finite_set` — the non-contiguous-
// finite-set peer of `assert_u8_array_covers_inclusive_range` on
// the (contiguity) axis of the substrate's SURJECTIVITY-axis
// coverage helpers. Where the sibling range-coverage helper closes
// the contiguous corner of the target-partition axis at four
// range-covering `[u8; N]` HASH_DISCRIMINATORS arrays, this helper
// closes the non-contiguous corner at
// `StructuralKind::HASH_DISCRIMINATORS` (`[u8; 2]` covering
// `{0, 2}` with a load-bearing gap at `1u8` where the atomic-
// carve outer marker lives). The runtime test surface matches
// the sibling-helpers' shape (accept-singleton, accept-with-
// duplicates, accept-every-family-wide-substrate-array, reject-
// out-of-set, reject-set-byte-missing, panic-message-provenance
// on the OUT-OF-SET axis, panic-message-provenance on the SET-
// BYTE-MISSING axis) split across BOTH axes so a regression that
// silently weakens the helper on EITHER axis (e.g. dropping the
// `found` guard on the set-membership sweep, or dropping the
// outer `while j < M` set-coverage sweep entirely) is caught by
// the helper's OWN test surface rather than only surfacing as a
// false-positive on some future finite-set-covering `[u8; N]`
// array's coverage pin.
#[test]
fn assert_u8_array_covers_finite_set_accepts_the_singleton_set() {
// Singleton set `{K}` at the `[u8; 1]` × `[u8; 1]` corner —
// vacuously covering (the one entry MUST equal the one set
// byte). Cross-arity coverage on the trivial-set corner of
// the const-M generic; simultaneously pins BOTH axes (OUT-OF-
// SET: `K in {K}`; SET-BYTE-MISSING: `K` appears in the
// singleton array) at the smallest witness.
assert_u8_array_covers_finite_set::<1, 1>(&[7u8], &[7u8]);
assert_u8_array_covers_finite_set::<1, 1>(&[0u8], &[0u8]);
assert_u8_array_covers_finite_set::<1, 1>(&[255u8], &[255u8]);
}
#[test]
fn assert_u8_array_covers_finite_set_accepts_arrays_with_duplicates() {
// KEY LOAD-BEARING PIN: duplicates in the entries are ACCEPTED
// — the finite-set-coverage contract is non-injective on the
// ENTRIES axis, only requires each SET byte to appear. This
// is the exact property that distinguishes this helper from
// its `assert_u8_array_pairwise_distinct` sibling and lets
// any future array with a load-bearing collapse bind a
// compile-time coverage witness despite failing distinctness.
// A regression that added a pairwise-distinct guard on the
// entries axis (accidentally merging the two sibling
// helpers' contracts) would fail-loudly here.
assert_u8_array_covers_finite_set::<4, 3>(&[0u8, 1u8, 1u8, 2u8], &[0u8, 1u8, 2u8]);
assert_u8_array_covers_finite_set::<7, 3>(
&[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 2u8],
&[0u8, 1u8, 2u8],
);
}
#[test]
fn assert_u8_array_covers_finite_set_accepts_the_non_contiguous_partition() {
// KEY LOAD-BEARING PIN: a non-contiguous target set `{0, 2}`
// (with a gap at `1u8`) is ACCEPTED — a two-element array
// hitting exactly those two bytes binds the finite-set-
// coverage contract even though NO contiguous `[LO..=HI]`
// range describes the target partition. This is the exact
// property that distinguishes this helper from its
// `assert_u8_array_covers_inclusive_range` sibling on the
// (contiguity) axis and lets
// `StructuralKind::HASH_DISCRIMINATORS`'s `{0, 2}` gap-
// partition bind a compile-time coverage witness where the
// range sibling cannot. A regression that narrowed the
// helper's target-set semantics to contiguous ranges only
// (e.g. re-derived the `while cur <= HI` sweep instead of
// the per-set-byte membership sweep) would fail-loudly here.
assert_u8_array_covers_finite_set::<2, 2>(&[0u8, 2u8], &[0u8, 2u8]);
assert_u8_array_covers_finite_set::<3, 3>(&[0u8, 2u8, 5u8], &[0u8, 2u8, 5u8]);
}
#[test]
fn assert_u8_array_covers_finite_set_accepts_every_family_wide_substrate_array() {
// Runtime cross-check that the SAME array the module-level
// `const _: () = ...` witness covers at COMPILE time is
// finite-set-covering. A regression that removes the
// `const _` witness would still leave THIS runtime pin as a
// safety net; the const witness fires FIRST at `cargo check`,
// this runtime pin catches the drift at `cargo test`. The
// pair enforces the theorem at TWO stages of the toolchain.
// Sibling posture to
// `assert_u8_array_covers_inclusive_range_accepts_every_
// family_wide_substrate_array` at the contiguous-range peer.
assert_u8_array_covers_finite_set::<2, 2>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&[0u8, 2u8],
);
}
#[test]
#[should_panic(expected = "OUT-OF-SET")]
fn assert_u8_array_covers_finite_set_panics_at_runtime_on_out_of_set_entry() {
// NEGATIVE PIN — SET-MEMBERSHIP corner: an entry NOT in the
// target set MUST panic at runtime with the OUT-OF-SET-named
// message. Pins the helper's OWN reject-out-of-set arm — a
// regression that silently returned without panicking on an
// entry outside the target set would slip through the
// compile-time witnesses' failure mode too. The two set
// bytes `{0, 2}` witness that the FULL-COVERAGE axis is
// INTACT — the panic MUST fire specifically on the SET-
// MEMBERSHIP disjointness failure at the drift entry `3u8`.
assert_u8_array_covers_finite_set::<3, 2>(&[0u8, 2u8, 3u8], &[0u8, 2u8]);
}
#[test]
#[should_panic(expected = "OUT-OF-SET")]
fn assert_u8_array_covers_finite_set_panics_on_gap_byte_drift() {
// NEGATIVE PIN — GAP-BYTE corner: an entry that drifts INTO
// the intentional gap of a non-contiguous target set MUST
// panic — this is the exact regression the archetype
// `StructuralKind::HASH_DISCRIMINATORS` witness catches. A
// regression that lifted a fresh `1u8` entry into the
// `{0, 2}`-partitioned array would silently collide with
// `AtomKind::OUTER_HASH_DISCRIMINATOR = 1u8` on the outer-
// `Sexp` cache-key partition; this pin binds that failure
// mode as an OUT-OF-SET rejection at the const-eval site.
assert_u8_array_covers_finite_set::<3, 2>(&[0u8, 1u8, 2u8], &[0u8, 2u8]);
}
#[test]
#[should_panic(expected = "SET-BYTE-MISSING")]
fn assert_u8_array_covers_finite_set_panics_at_runtime_on_missing_set_byte() {
// NEGATIVE PIN — FULL-COVERAGE corner: a set byte NOT
// reached by any entry MUST panic at runtime with the SET-
// BYTE-MISSING-named message. Pins the helper's OWN reject-
// incomplete-coverage arm — a regression that silently
// returned without panicking on an incomplete-coverage array
// (e.g. dropping the outer `while j < M` sweep entirely, or
// narrowing it to `while j < M - 1`) would slip through the
// compile-time witnesses' failure mode too. The two entries
// stay within `{0, 2, 5}` (satisfying OUT-OF-SET) but skip
// the middle byte `2u8` — the panic MUST fire specifically
// on the FULL-COVERAGE axis, not on the SET-MEMBERSHIP axis.
assert_u8_array_covers_finite_set::<2, 3>(&[0u8, 5u8], &[0u8, 2u8, 5u8]);
}
#[test]
fn assert_u8_array_covers_finite_set_panic_message_names_the_helper_and_out_of_set_axis() {
// PANIC-MESSAGE PROVENANCE PIN — OUT-OF-SET arm: the panic
// message MUST begin with the helper's own name AND identify
// the failed AXIS as "OUT-OF-SET" so downstream diagnostics
// route the drift back to (a) the helper by string search on
// `"assert_u8_array_covers_finite_set"` and (b) the axis by
// string search on `"OUT-OF-SET"`. Sibling posture to
// `assert_u8_array_covers_inclusive_range_panic_message_
// names_the_helper_and_range_bound_axis` on the contiguous-
// range peer's RANGE-BOUND arm — both bind the (helper,
// failed-axis) provenance pair at ONE test per axis. The
// axis-provenance strings ("OUT-OF-SET" here vs. "OUT-OF-
// RANGE" on the range sibling) are chosen DISTINCT so a
// diagnostic that names the failed axis routes UNAMBIGUOUSLY
// to the failed HELPER too — a regression that unified the
// two helpers' axis-provenance strings would collapse either
// this substring assertion or the sibling helper's.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_covers_finite_set::<3, 2>(&[0u8, 2u8, 3u8], &[0u8, 2u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_covers_finite_set must panic on an out-\
of-set entry — the reject-out-of-set arm is one of the \
two failure modes of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_covers_finite_set panic payload must \
be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_covers_finite_set"),
"assert_u8_array_covers_finite_set OUT-OF-SET panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("OUT-OF-SET"),
"assert_u8_array_covers_finite_set OUT-OF-SET panic \
message {msg:?} must name the failed AXIS (\"OUT-OF-\
SET\") for axis-provenance-preserving failure \
diagnostics",
);
}
#[test]
fn assert_u8_array_covers_finite_set_panic_message_names_the_helper_and_missing_set_byte_axis()
{
// PANIC-MESSAGE PROVENANCE PIN — SET-BYTE-MISSING arm: the
// panic message MUST begin with the helper's own name AND
// identify the failed AXIS as "SET-BYTE-MISSING" so
// downstream diagnostics route the drift back to (a) the
// helper by string search and (b) the axis by string search
// on `"SET-BYTE-MISSING"`. Axis-symmetric sibling of the
// OUT-OF-SET panic-message provenance pin above — a
// regression that silently unified the two panic sites into
// ONE axis-anonymous message would collapse EITHER this
// pin's `"SET-BYTE-MISSING"` substring assertion OR the
// sibling pin's `"OUT-OF-SET"` substring assertion. The
// axis-provenance string ("SET-BYTE-MISSING" here vs.
// "MISSING" on the range sibling) is chosen DISTINCT so a
// diagnostic that names the failed axis routes UNAMBIGUOUSLY
// to the failed HELPER too.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_covers_finite_set::<2, 3>(&[0u8, 5u8], &[0u8, 2u8, 5u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_covers_finite_set must panic on a \
missing set byte — the reject-incomplete-coverage arm \
is one of the two failure modes of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_covers_finite_set panic payload must \
be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_covers_finite_set"),
"assert_u8_array_covers_finite_set SET-BYTE-MISSING panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics",
);
assert!(
msg.contains("SET-BYTE-MISSING"),
"assert_u8_array_covers_finite_set SET-BYTE-MISSING panic \
message {msg:?} must name the failed AXIS (\"SET-BYTE-\
MISSING\") for axis-provenance-preserving failure \
diagnostics",
);
}
// ── `assert_u8_finite_set_pairwise_distinct` — the caller-side
// SET-WELL-FORMEDNESS verifier that closes the pre-lift docstring-
// level "assuming `set` is itself pairwise-distinct" caveat on
// both `assert_u8_array_covers_finite_set` and
// `assert_u8_array_permutes_finite_set` into a compile-time
// theorem the substrate carries per call site. The runtime test
// surface pins each of the helper's arms (accept-empty, accept-
// singleton, accept-every-family-wide-substrate-target-set,
// reject-binary-collision, reject-non-adjacent-collision, reject-
// terminal-collision, panic-message-provenance on the SET-NOT-
// PAIRWISE-DISTINCT axis, negative pins on BOTH downstream
// covers/permutes helpers exercising the SET-side delegation
// chain) so a regression that silently weakened the helper on
// ANY arm is caught by the helper's OWN test surface rather than
// only surfacing as a false-positive on some future finite-set-
// covering `[u8; N]` array's compound pin.
#[test]
fn assert_u8_finite_set_pairwise_distinct_accepts_the_empty_set() {
// Empty set `{}` at the `[u8; 0]` corner — vacuously pairwise-
// distinct (no `(i, j)` pair with `i < j` exists to test).
// Cross-arity coverage on the trivial corner of the const-M
// generic; a regression that fired on an empty set (e.g. by
// computing `M - 1` and wrapping to `usize::MAX`) would
// fail-loudly here. Turbofish binding required because there's
// no other cue for the `M` const parameter on the empty array
// literal.
assert_u8_finite_set_pairwise_distinct::<0>(&[]);
}
#[test]
fn assert_u8_finite_set_pairwise_distinct_accepts_singleton_sets() {
// Singleton set `{K}` at the `[u8; 1]` corner — vacuously
// pairwise-distinct (no `(i, j)` pair with `i < j` exists).
// Cross-value coverage on the singleton corner at THREE byte
// widths (`0u8`, `7u8`, `255u8`) to pin the helper's SINGLETON
// arm across the whole `u8` domain.
assert_u8_finite_set_pairwise_distinct(&[0u8]);
assert_u8_finite_set_pairwise_distinct(&[7u8]);
assert_u8_finite_set_pairwise_distinct(&[255u8]);
}
#[test]
fn assert_u8_finite_set_pairwise_distinct_accepts_every_family_wide_target_set() {
// Runtime cross-check that the ONE target-SET spec the
// substrate's `const _` witness (at
// `assert_u8_array_permutes_finite_set::<2, 2>(
// &StructuralKind::HASH_DISCRIMINATORS, &[0u8, 2u8])`)
// passes through this helper's SET-side delegation at
// compile time is ALSO well-formed at runtime. The pair
// enforces the theorem at TWO stages of the toolchain: the
// const witness fires FIRST at `cargo check` (through the
// delegated call chain), this runtime pin catches the drift
// at `cargo test` as a safety net. Sibling posture to
// `assert_u8_array_covers_finite_set_accepts_every_family_
// wide_substrate_array` — the two pins together verify the
// (ARRAY, SET) pair at BOTH sides of the finite-set-coverage
// compound contract.
assert_u8_finite_set_pairwise_distinct(&[0u8, 2u8]);
}
#[test]
fn assert_u8_finite_set_pairwise_distinct_accepts_the_structural_kind_hash_discriminators() {
// Runtime cross-check that
// `StructuralKind::HASH_DISCRIMINATORS` itself is pairwise-
// distinct WHEN VIEWED AS A TARGET-SET SPEC (i.e. this
// helper accepts arrays that would themselves be valid
// target-set specs). While the SUBSTRATE'S primary call
// site passes the caller-provided `&[0u8, 2u8]` literal as
// the target-set spec (with `StructuralKind::HASH_
// DISCRIMINATORS` as the ARRAY under verification), the two
// arrays HAPPEN to have byte-equal contents by design (the
// ARRAY is a permutation of the target SET); a regression
// that silently unified two `StructuralKind` arms' cache-
// key bytes would fail-loudly here on the ARRAY-as-SET
// interpretation TOO, providing a redundant safety net past
// the primary compound witness at the module level.
assert_u8_finite_set_pairwise_distinct(&crate::error::StructuralKind::HASH_DISCRIMINATORS);
}
#[test]
#[should_panic(expected = "SET-NOT-PAIRWISE-DISTINCT")]
fn assert_u8_finite_set_pairwise_distinct_panics_at_runtime_on_binary_collision() {
// NEGATIVE PIN — binary-collision corner: the smallest
// duplicate-carrying set `[K, K]` MUST panic at runtime with
// the SET-NOT-PAIRWISE-DISTINCT-named message. Pins the
// helper's OWN reject arm — a regression that silently
// returned without panicking on an adjacent duplicate would
// slip through the compile-time witnesses' failure mode too.
assert_u8_finite_set_pairwise_distinct(&[42u8, 42u8]);
}
#[test]
#[should_panic(expected = "SET-NOT-PAIRWISE-DISTINCT")]
fn assert_u8_finite_set_pairwise_distinct_panics_at_runtime_on_non_adjacent_collision() {
// NEGATIVE PIN — non-adjacent-collision corner: a duplicate
// separated by ONE intervening element MUST panic — pins
// that the `(i, j)` pair-walk sweeps the FULL upper-triangle
// rather than only adjacent pairs. A regression that
// narrowed the inner `while j < M` loop to `j == i + 1`
// would silently accept this set. Positions `(0, 2)` witness
// a non-adjacent collision through the middle `2u8`
// separator.
assert_u8_finite_set_pairwise_distinct(&[1u8, 2u8, 1u8]);
}
#[test]
#[should_panic(expected = "SET-NOT-PAIRWISE-DISTINCT")]
fn assert_u8_finite_set_pairwise_distinct_panics_at_runtime_on_terminal_collision() {
// NEGATIVE PIN — terminal-collision corner: a duplicate at
// the LAST two positions MUST panic — pins that the outer
// `while i < M` loop reaches `i = M - 2` (else the terminal
// duplicate at positions `(M - 2, M - 1)` would slip
// through). A regression that narrowed the outer sweep to
// `while i < M - 1` (off-by-one on the OUTER bound) would
// silently accept this set.
assert_u8_finite_set_pairwise_distinct(&[0u8, 1u8, 2u8, 3u8, 3u8]);
}
#[test]
fn assert_u8_finite_set_pairwise_distinct_panic_message_names_the_helper_and_set_axis() {
// PANIC-MESSAGE PROVENANCE PIN — SET-NOT-PAIRWISE-DISTINCT
// arm: the panic message MUST begin with the helper's own
// name AND identify the failed AXIS as "SET-NOT-PAIRWISE-
// DISTINCT" so downstream diagnostics route the drift back
// to (a) the helper by string search on `"assert_u8_finite_
// set_pairwise_distinct"` and (b) the axis by string search
// on `"SET-NOT-PAIRWISE-DISTINCT"`. Sibling posture to
// `assert_u8_array_covers_finite_set_panic_message_names_
// the_helper_and_out_of_set_axis` on the ARRAY-side covers
// helper's OUT-OF-SET arm — both bind the (helper, failed-
// axis) provenance pair at ONE test per axis. The axis-
// provenance string "SET-NOT-PAIRWISE-DISTINCT" is chosen
// DISTINCT from EVERY sibling helper's axis vocabulary
// (`"duplicate"` on the ARRAY-side pairwise-distinct
// sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"` on the
// covers-finite-set sibling; `"OUT-OF-RANGE"` / `"MISSING"`
// on the covers-inclusive-range sibling; `"ARITY-MISMATCH"`
// on both `_permutes_*` compound helpers) so a diagnostic
// that names the failed axis routes UNAMBIGUOUSLY to (a)
// this specific SET-side helper, (b) the CALLER'S TARGET-
// SET SPEC as the drift site rather than the downstream
// `arr` under verification.
let outcome = std::panic::catch_unwind(|| {
assert_u8_finite_set_pairwise_distinct(&[42u8, 42u8]);
});
let payload = outcome.expect_err(
"assert_u8_finite_set_pairwise_distinct must panic on a \
malformed target-set spec — the reject-duplicate arm \
is the sole failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_finite_set_pairwise_distinct panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_finite_set_pairwise_distinct"),
"assert_u8_finite_set_pairwise_distinct panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("SET-NOT-PAIRWISE-DISTINCT"),
"assert_u8_finite_set_pairwise_distinct panic message \
{msg:?} must name the failed AXIS (\"SET-NOT-PAIRWISE-\
DISTINCT\") for axis-provenance-preserving failure \
diagnostics",
);
}
#[test]
#[should_panic(expected = "SET-NOT-PAIRWISE-DISTINCT")]
fn assert_u8_array_covers_finite_set_panics_on_malformed_target_set_spec() {
// NEGATIVE PIN — DELEGATED SET-side well-formedness: a
// malformed target-set spec `[0, 2, 2]` fed into the
// ARRAY-side covers-finite-set helper MUST panic on the
// DELEGATED SET-NOT-PAIRWISE-DISTINCT arm BEFORE the OUT-
// OF-SET / SET-BYTE-MISSING arms fire. Pins the
// delegation chain: a regression that dropped the
// `assert_u8_finite_set_pairwise_distinct(set)` call at
// the top of `assert_u8_array_covers_finite_set` would
// silently accept a malformed set and produce a false-
// positive verdict on any `arr` covering the DISTINCT-
// value subset (`arr = [0, 2, 2]` here matches BOTH the
// OUT-OF-SET and SET-BYTE-MISSING sweeps because every
// entry appears in `set` and every set byte appears in
// `arr`, so without the SET-well-formedness delegation
// the intended cardinality-3 contract would silently
// verify against a really-cardinality-2 set). The
// `SET-NOT-PAIRWISE-DISTINCT` axis-provenance string
// routes the operator to the CALLER'S SPEC.
assert_u8_array_covers_finite_set::<3, 3>(&[0u8, 2u8, 2u8], &[0u8, 2u8, 2u8]);
}
#[test]
#[should_panic(expected = "SET-NOT-PAIRWISE-DISTINCT")]
fn assert_u8_array_permutes_finite_set_panics_on_malformed_target_set_spec() {
// NEGATIVE PIN — DELEGATED SET-side well-formedness on
// the COMPOUND helper: a malformed target-set spec `[0, 2,
// 2]` fed into `assert_u8_array_permutes_finite_set` MUST
// panic on the DELEGATED SET-NOT-PAIRWISE-DISTINCT arm
// BEFORE the ARITY-MISMATCH / pairwise-distinct-on-arr /
// covers-finite-set arms fire. Pins the delegation chain at
// the compound helper's ENTRY point: a regression that
// dropped the `assert_u8_finite_set_pairwise_distinct(set)`
// call at the top of the compound helper would silently
// route a malformed set through the ARITY check (`N == M`
// holds on the substrate's cardinality-3 pair, since BOTH
// the array and the phantom-3 set have cardinality `3` at
// the type level even though the SET really has DISTINCT-
// cardinality `2`) and produce a false-positive permutation
// verdict. The `SET-NOT-PAIRWISE-DISTINCT` panic here MUST
// fire BEFORE the sibling `ARITY-MISMATCH` panic on the
// same input (both arms would fire independently but
// ordering routes the operator to the CALLER'S SPEC first,
// not to a downstream arithmetic symptom).
assert_u8_array_permutes_finite_set::<3, 3>(&[0u8, 2u8, 5u8], &[0u8, 2u8, 2u8]);
}
// ── `assert_u8_array_within_u8_finite_set` — the SET-MEMBERSHIP-
// ONLY subset-embedding verifier that binds `arr ⊆ set` at compile
// time (WITHOUT the additional `set ⊆ arr's entries` full-coverage
// clause the sibling `_covers_finite_set` binds). The runtime test
// surface pins each of the helper's arms (accept-empty, accept-
// singleton-in-set, accept-arr-equals-set, accept-the-family-wide
// substitution-subset substrate embedding, reject-single-out-of-
// set-entry, reject-terminal-out-of-set-entry, panic-message-
// provenance on the SUBSET-VIOLATION axis, negative pin on the
// DELEGATED SET-side well-formedness arm) so a regression that
// silently weakened the helper on ANY arm is caught by the
// helper's OWN test surface rather than only surfacing as a
// false-positive on some future subset-embedded `[u8; N]` array's
// compound pin.
#[test]
fn assert_u8_array_within_u8_finite_set_accepts_the_empty_array_within_any_set() {
// Empty array `arr = []` at the `[u8; 0]` corner — vacuously
// a subset of every set (no `i` position exists to test). Cross-
// arity coverage on the trivial ARRAY corner of the const-N
// generic across three witness-set widths (empty, singleton,
// multi-element) to pin the helper's OUTER-sweep arm across
// the whole (`N == 0` × `M`) axis. Turbofish binding required
// because there's no other cue for the const parameters on
// the empty array literal.
assert_u8_array_within_u8_finite_set::<0, 0>(&[], &[]);
assert_u8_array_within_u8_finite_set::<0, 1>(&[], &[42u8]);
assert_u8_array_within_u8_finite_set::<0, 4>(&[], &[3u8, 4u8, 5u8, 6u8]);
}
#[test]
fn assert_u8_array_within_u8_finite_set_accepts_singleton_array_when_byte_in_set() {
// Singleton array `arr = [K]` at the `[u8; 1]` corner MUST
// pass when `K ∈ set`. Cross-position coverage: the byte can
// sit at the FIRST, MIDDLE, or LAST position of the `set` —
// pins the INNER `while j < M` sweep terminates at the
// first-match position rather than always at position `0`
// OR always at position `M - 1`. A regression that narrowed
// the inner sweep to `j == 0` would silently reject singleton
// arrays hitting non-first set positions.
assert_u8_array_within_u8_finite_set::<1, 4>(&[3u8], &[3u8, 4u8, 5u8, 6u8]);
assert_u8_array_within_u8_finite_set::<1, 4>(&[5u8], &[3u8, 4u8, 5u8, 6u8]);
assert_u8_array_within_u8_finite_set::<1, 4>(&[6u8], &[3u8, 4u8, 5u8, 6u8]);
}
#[test]
fn assert_u8_array_within_u8_finite_set_accepts_arr_equals_set() {
// Boundary corner where `arr` and `set` cover byte-for-byte
// identical distinct-value sets — the SUBSET relation degenerates
// to EQUALITY. Pins that the helper does NOT gratuitously
// require the SUBSET to be PROPER (strict): equal-multisets
// pass the SUBSET check. Sibling posture to the covers-finite-
// set peer whose SET-BYTE-MISSING arm would ALSO accept this
// input — the two helpers agree on the EQUAL-SETS corner
// while disagreeing on the PROPER-SUBSET corner (only this
// helper accepts proper subsets; the covers helper rejects
// them at the SET-BYTE-MISSING arm).
assert_u8_array_within_u8_finite_set(&[3u8, 4u8, 5u8, 6u8], &[3u8, 4u8, 5u8, 6u8]);
assert_u8_array_within_u8_finite_set(&[0u8, 2u8], &[0u8, 2u8]);
}
#[test]
fn assert_u8_array_within_u8_finite_set_accepts_the_substitution_subset_embedding() {
// Runtime cross-check that the ONE (subset, superset) pair
// the substrate's module-level `const _` witness pins at
// COMPILE time is a PROPER SUBSET embedding at runtime too.
// The pair enforces the theorem at TWO stages of the
// toolchain: the const witness fires FIRST at `cargo check`
// (through the module-level `const _: () = assert_u8_array_
// within_u8_finite_set::<2, 4>(...)` line), this runtime pin
// catches the drift at `cargo test` as a safety net. Sibling
// posture to
// `assert_u8_finite_set_pairwise_distinct_accepts_every_family_wide_target_set`
// (which runtime-checks the SAME `QuoteForm::HASH_DISCRIMINATORS`
// superset viewed as a SET-side well-formedness input) — the
// two pins together verify the (UnquoteForm subset, QuoteForm
// superset) pair at BOTH sides of the subset-embedding
// contract.
assert_u8_array_within_u8_finite_set::<2, 4>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
}
#[test]
fn assert_u8_array_within_u8_finite_set_accepts_repeated_array_entries_in_set() {
// Peer corner to `_covers_finite_set`: this helper permits
// duplicates in `arr` because SUBSET-membership is a
// DISTINCT-value predicate — `[3, 3, 5]` is a subset of
// `{3, 4, 5, 6}` even though the array is not pairwise-
// distinct. Pins that the helper does NOT gratuitously
// require INJECTIVITY on `arr` (the injectivity axis is a
// DIFFERENT compile-time contract bound by
// `assert_u8_array_pairwise_distinct`; combining both binds
// BOTH axes). Sibling posture to
// `assert_u8_array_covers_inclusive_range` which ALSO
// permits array duplicates on its RANGE-BOUND arm.
assert_u8_array_within_u8_finite_set(&[3u8, 3u8, 5u8], &[3u8, 4u8, 5u8, 6u8]);
}
#[test]
#[should_panic(expected = "SUBSET-VIOLATION")]
fn assert_u8_array_within_u8_finite_set_panics_at_runtime_on_out_of_set_entry() {
// NEGATIVE PIN — SUBSET-VIOLATION corner: an array carrying
// a single entry NOT in the target set MUST panic at runtime
// with the SUBSET-VIOLATION-named message. Pins the helper's
// OWN reject arm — a regression that silently returned
// without panicking on an out-of-set entry would slip through
// the compile-time witness's failure mode too. The offending
// byte `7u8` is intentionally chosen ONE PAST the superset's
// maximum (`QuoteForm::HASH_DISCRIMINATORS`'s upper endpoint
// is `6u8`) to pin the OVERSHOOT drift mode.
assert_u8_array_within_u8_finite_set(&[5u8, 7u8], &[3u8, 4u8, 5u8, 6u8]);
}
#[test]
#[should_panic(expected = "SUBSET-VIOLATION")]
fn assert_u8_array_within_u8_finite_set_panics_at_runtime_on_terminal_out_of_set_entry() {
// NEGATIVE PIN — terminal-position drift: an out-of-set entry
// at the LAST array position MUST panic — pins that the outer
// `while i < N` loop reaches `i = N - 1` (else the terminal
// drift would slip through). A regression that narrowed the
// outer sweep to `while i < N - 1` (off-by-one on the OUTER
// bound) would silently accept this array.
assert_u8_array_within_u8_finite_set(&[3u8, 4u8, 5u8, 6u8, 7u8], &[3u8, 4u8, 5u8, 6u8]);
}
#[test]
#[should_panic(expected = "SUBSET-VIOLATION")]
fn assert_u8_array_within_u8_finite_set_panics_at_runtime_on_undershoot_out_of_set_entry() {
// NEGATIVE PIN — undershoot drift mode complementary to the
// OVERSHOOT drift mode `_panics_at_runtime_on_out_of_set_entry`
// above: an offending byte BELOW the superset's minimum
// (`QuoteForm::HASH_DISCRIMINATORS`'s lower endpoint is `3u8`;
// this array carries a `0u8` entry NOT in the set) MUST panic.
// Pins that the helper's SET-MEMBERSHIP sweep does NOT
// silently accept bytes UNDER the target set's minimum on
// some misapplied range-min assumption — the helper binds a
// FINITE-SET subset relation, not a RANGE subset relation.
assert_u8_array_within_u8_finite_set(&[0u8, 5u8], &[3u8, 4u8, 5u8, 6u8]);
}
#[test]
fn assert_u8_array_within_u8_finite_set_panic_message_names_the_helper_and_subset_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — SUBSET-VIOLATION arm: the
// panic message MUST begin with the helper's own name AND
// identify the failed AXIS as "SUBSET-VIOLATION" so
// downstream diagnostics route the drift back to (a) the
// helper by string search on
// `"assert_u8_array_within_u8_finite_set"` and (b) the axis
// by string search on `"SUBSET-VIOLATION"`. Sibling posture
// to
// `assert_u8_finite_set_pairwise_distinct_panic_message_names_the_helper_and_set_axis`
// on the SET-side well-formedness sibling and
// `assert_u8_array_covers_finite_set_panic_message_names_the_helper_and_out_of_set_axis`
// on the ARRAY-side covers helper — all three bind the
// (helper, failed-axis) provenance pair at ONE test per
// helper. The axis-provenance string "SUBSET-VIOLATION" is
// chosen DISTINCT from EVERY sibling helper's axis
// vocabulary (`"duplicate"` on the ARRAY-side pairwise-
// distinct sibling; `"OUT-OF-SET"` / `"SET-BYTE-MISSING"`
// on the covers-finite-set sibling; `"OUT-OF-RANGE"` /
// `"MISSING"` on the covers-inclusive-range sibling;
// `"ARITY-MISMATCH"` on both `_permutes_*` compound helpers;
// `"SET-NOT-PAIRWISE-DISTINCT"` on the SET-side well-
// formedness sibling) so a diagnostic that names the failed
// axis routes UNAMBIGUOUSLY to (a) this specific SUBSET-
// embedding helper, (b) the `arr` argument as the drift
// site rather than the `set` argument specifying the target
// superset.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_within_u8_finite_set(&[5u8, 7u8], &[3u8, 4u8, 5u8, 6u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_within_u8_finite_set must panic on an \
out-of-set entry — the reject-out-of-set arm is the \
sole SUBSET-VIOLATION failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_within_u8_finite_set panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_within_u8_finite_set"),
"assert_u8_array_within_u8_finite_set panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("SUBSET-VIOLATION"),
"assert_u8_array_within_u8_finite_set panic message \
{msg:?} must name the failed AXIS (\"SUBSET-VIOLATION\") \
for axis-provenance-preserving failure diagnostics",
);
}
#[test]
#[should_panic(expected = "SET-NOT-PAIRWISE-DISTINCT")]
fn assert_u8_array_within_u8_finite_set_panics_on_malformed_target_set_spec() {
// NEGATIVE PIN — DELEGATED SET-side well-formedness: a
// malformed target-set spec `[3, 4, 4]` fed into the ARRAY-
// side within helper MUST panic on the DELEGATED SET-NOT-
// PAIRWISE-DISTINCT arm BEFORE the SUBSET-VIOLATION arm
// fires. Pins the delegation chain: a regression that
// dropped the `assert_u8_finite_set_pairwise_distinct(set)`
// call at the top of `assert_u8_array_within_u8_finite_set`
// would silently accept a malformed set and produce a
// false-positive verdict on any `arr` embedded in the
// DISTINCT-value subset. Sibling posture to
// `assert_u8_array_covers_finite_set_panics_on_malformed_target_set_spec`
// and
// `assert_u8_array_permutes_finite_set_panics_on_malformed_target_set_spec`
// — the three DELEGATED tests pin the SET-side well-
// formedness arm at the top of ALL THREE finite-set-family
// ARRAY-side helpers.
assert_u8_array_within_u8_finite_set::<2, 3>(&[3u8, 4u8], &[3u8, 4u8, 4u8]);
}
// ── `assert_u8_array_within_inclusive_range` — the RANGE-MEMBERSHIP-
// ONLY subset-embedding verifier that binds `arr ⊆ [LO..=HI]` at
// compile time (WITHOUT the additional `[LO..=HI] ⊆ arr's entries`
// full-coverage clause the sibling `_covers_inclusive_range` binds).
// Contiguity-axis peer to `_within_u8_finite_set` on the (contiguity)
// axis of the substrate's SUBSET-only verifiers. The runtime test
// surface pins each of the helper's arms (accept-empty, accept-
// singleton-in-range, accept-arr-equals-range-endpoints, accept-the-
// family-wide structural-residual substrate embedding, accept-with-
// duplicates, reject-above-HI-entry, reject-below-LO-entry, reject-
// terminal-out-of-range-entry, panic-message-provenance on the
// RANGE-SUBSET-VIOLATION axis) so a regression that silently weakens
// the helper on ANY arm is caught by the helper's OWN test surface
// rather than only surfacing as a false-positive on some future
// range-subset-embedded `[u8; N]` array's compound pin.
#[test]
fn assert_u8_array_within_inclusive_range_accepts_the_empty_array_within_any_range() {
// Empty array `arr = []` at the `[u8; 0]` corner — vacuously a
// subset of every inclusive range (no `i` position exists to
// test). Cross-range coverage on the trivial ARRAY corner of
// the const-N generic across three witness-range widths
// (singleton, small, whole-`u8`-space) to pin the helper's
// OUTER-sweep arm across the whole (`N == 0` × `[LO..=HI]`)
// axis. Turbofish binding required because there's no other
// cue for the const parameters on the empty array literal.
assert_u8_array_within_inclusive_range::<0, 0, 0>(&[]);
assert_u8_array_within_inclusive_range::<0, 0, 6>(&[]);
assert_u8_array_within_inclusive_range::<0, 0, 255>(&[]);
}
#[test]
fn assert_u8_array_within_inclusive_range_accepts_singleton_array_when_byte_in_range() {
// Singleton array `arr = [K]` at the `[u8; 1]` corner MUST pass
// when `K in [LO..=HI]`. Cross-position coverage: the byte can
// sit at the LO endpoint, an INTERIOR position, or the HI
// endpoint — pins the OUTER-sweep's OR-disjunction guard
// handles all three cases without gratuitously narrowing to
// strict-inequality on either endpoint. A regression that
// narrowed the guard to `arr[i] <= LO || arr[i] >= HI` (strict
// endpoint exclusion) would silently reject singleton arrays
// hitting the endpoints — this test catches BOTH endpoint
// regressions in ONE forward sweep.
assert_u8_array_within_inclusive_range::<1, 0, 6>(&[0u8]);
assert_u8_array_within_inclusive_range::<1, 0, 6>(&[3u8]);
assert_u8_array_within_inclusive_range::<1, 0, 6>(&[6u8]);
}
#[test]
fn assert_u8_array_within_inclusive_range_accepts_singleton_range_when_byte_equals_endpoint() {
// Degenerate singleton-range corner `[K..=K]` where LO == HI —
// the ONLY accepting arrays are those whose every entry equals
// `K`. Pins the helper does NOT gratuitously reject the LO ==
// HI degenerate case (a regression that narrowed `LO <= HI` to
// `LO < HI` at some downstream bounds check would surface here
// if this helper ever grew such a check; today it does not,
// and this test locks it out).
assert_u8_array_within_inclusive_range::<1, 42, 42>(&[42u8]);
assert_u8_array_within_inclusive_range::<3, 42, 42>(&[42u8, 42u8, 42u8]);
assert_u8_array_within_inclusive_range::<1, 0, 0>(&[0u8]);
assert_u8_array_within_inclusive_range::<1, 255, 255>(&[255u8]);
}
#[test]
fn assert_u8_array_within_inclusive_range_accepts_arrays_with_duplicates() {
// Peer corner to `_covers_inclusive_range`: this helper permits
// duplicates in `arr` because RANGE-membership is a DISTINCT-
// value predicate — `[3, 3, 5]` embeds in `[0..=6]` even
// though the array is not pairwise-distinct. Pins that the
// helper does NOT gratuitously require INJECTIVITY on `arr`
// (the injectivity axis is a DIFFERENT compile-time contract
// bound by `assert_u8_array_pairwise_distinct`; combining both
// binds BOTH axes). Sibling posture to
// `assert_u8_array_within_u8_finite_set_accepts_repeated_array_entries_in_set`
// on the finite-set peer.
assert_u8_array_within_inclusive_range::<3, 0, 6>(&[3u8, 3u8, 5u8]);
assert_u8_array_within_inclusive_range::<4, 0, 6>(&[0u8, 0u8, 6u8, 6u8]);
}
#[test]
fn assert_u8_array_within_inclusive_range_accepts_the_structural_residual_subset_embedding() {
// Runtime cross-check that the ONE (array, range) pair the
// substrate's module-level `const _` witness pins at COMPILE
// time is a PROPER SUBSET embedding at runtime too. The pair
// enforces the theorem at TWO stages of the toolchain: the
// const witness fires FIRST at `cargo check` (through the
// module-level `const _: () = assert_u8_array_within_inclusive_
// range::<2, 0, 6>(&StructuralKind::HASH_DISCRIMINATORS)`
// line), this runtime pin catches the drift at `cargo test`
// as a safety net. Sibling posture to
// `assert_u8_array_within_u8_finite_set_accepts_the_substitution_subset_embedding`
// on the finite-set-subset peer's substrate cross-check —
// both pin the substrate's ONE-witness embedding at BOTH
// stages of the toolchain.
assert_u8_array_within_inclusive_range::<2, 0, 6>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
);
}
#[test]
#[should_panic(expected = "RANGE-SUBSET-VIOLATION")]
fn assert_u8_array_within_inclusive_range_panics_at_runtime_on_entry_above_hi() {
// NEGATIVE PIN — above-HI overshoot corner: an array carrying
// a single entry `HI + 1` MUST panic at runtime with the
// RANGE-SUBSET-VIOLATION-named message. Pins the helper's OWN
// reject-above-HI arm — a regression that silently returned
// without panicking on an out-of-range entry above the upper
// bound would slip through the compile-time witness's failure
// mode too. The offending byte `7u8` is intentionally chosen
// ONE PAST the outer-`Sexp` partition's upper endpoint (`6u8`)
// to pin the OVERSHOOT drift mode against the substrate's
// load-bearing partition.
assert_u8_array_within_inclusive_range::<2, 0, 6>(&[0u8, 7u8]);
}
#[test]
#[should_panic(expected = "RANGE-SUBSET-VIOLATION")]
fn assert_u8_array_within_inclusive_range_panics_at_runtime_on_entry_below_lo() {
// NEGATIVE PIN — below-LO undershoot corner symmetric to the
// OVERSHOOT drift mode above: an offending byte BELOW the
// range's minimum (`LO = 3u8`; this array carries a `0u8`
// entry NOT in the range) MUST panic. Pins that the helper's
// OR-disjunction guard does NOT drop the `arr[i] < LO` half
// (leaving only the `arr[i] > HI` half) — a regression that
// silently accepted below-LO entries would surface here.
assert_u8_array_within_inclusive_range::<2, 3, 6>(&[0u8, 5u8]);
}
#[test]
#[should_panic(expected = "RANGE-SUBSET-VIOLATION")]
fn assert_u8_array_within_inclusive_range_panics_at_runtime_on_terminal_out_of_range_entry() {
// NEGATIVE PIN — terminal-position drift: an out-of-range
// entry at the LAST array position MUST panic — pins that the
// outer `while i < N` loop reaches `i = N - 1` (else the
// terminal drift would slip through). A regression that
// narrowed the outer sweep to `while i < N - 1` (off-by-one on
// the OUTER bound) would silently accept this array. Sibling
// posture to
// `assert_u8_array_within_u8_finite_set_panics_at_runtime_on_terminal_out_of_set_entry`
// on the finite-set-subset peer's terminal-position pin —
// both bind the outer-sweep terminal bound at the ONE array-
// side outer loop the helper carries.
assert_u8_array_within_inclusive_range::<4, 0, 6>(&[0u8, 3u8, 6u8, 7u8]);
}
#[test]
fn assert_u8_array_within_inclusive_range_panic_message_names_the_helper_and_range_subset_violation_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — RANGE-SUBSET-VIOLATION arm:
// the panic message MUST begin with the helper's own name AND
// identify the failed AXIS as "RANGE-SUBSET-VIOLATION" so
// downstream diagnostics route the drift back to (a) the
// helper by string search on
// `"assert_u8_array_within_inclusive_range"` and (b) the axis
// by string search on `"RANGE-SUBSET-VIOLATION"`. Sibling
// posture to
// `assert_u8_array_within_u8_finite_set_panic_message_names_the_helper_and_subset_violation_axis`
// on the finite-set-subset peer's provenance pin — the two
// pins together bind the (helper, failed-axis) provenance
// pair at ONE test per SUBSET helper on the (contiguity)
// 2×2 face. The axis-provenance string
// `"RANGE-SUBSET-VIOLATION"` is chosen DISTINCT from EVERY
// sibling helper's axis vocabulary (`"duplicate"` on the
// ARRAY-side pairwise-distinct sibling; `"OUT-OF-SET"` /
// `"SET-BYTE-MISSING"` on the covers-finite-set sibling;
// `"OUT-OF-RANGE"` / `"MISSING"` on the covers-inclusive-
// range sibling; `"SUBSET-VIOLATION"` on the finite-set
// SUBSET-only sibling; `"ARITY-MISMATCH"` on both
// `_permutes_*` compound helpers; `"SET-NOT-PAIRWISE-
// DISTINCT"` on the SET-side well-formedness sibling) so a
// diagnostic that names the failed axis routes UNAMBIGUOUSLY
// to (a) this specific range SUBSET-embedding helper, (b)
// the `arr` argument as the drift site rather than the
// `LO`/`HI` const parameters specifying the target range.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_within_inclusive_range::<2, 0, 6>(&[0u8, 7u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_within_inclusive_range must panic on an \
out-of-range entry — the reject-out-of-range arm is the \
sole RANGE-SUBSET-VIOLATION failure mode of the helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_within_inclusive_range panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_within_inclusive_range"),
"assert_u8_array_within_inclusive_range panic message \
{msg:?} must name the helper for provenance-preserving \
failure diagnostics",
);
assert!(
msg.contains("RANGE-SUBSET-VIOLATION"),
"assert_u8_array_within_inclusive_range panic message \
{msg:?} must name the failed AXIS (\"RANGE-SUBSET-\
VIOLATION\") for axis-provenance-preserving failure \
diagnostics",
);
}
// ── `assert_u8_array_permutes_inclusive_range` — the compound
// (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) permutation-of-range
// verifier that collapses the pre-existing weak-witness pair
// (`assert_u8_array_pairwise_distinct` +
// `assert_u8_array_covers_inclusive_range`) into ONE `const _`
// line per array on the three permutation-shaped
// HASH_DISCRIMINATORS arrays (`AtomKind`, `QuoteForm`,
// `UnquoteForm`). The runtime test surface matches the sibling-
// helpers' shape (accept-singleton, accept-every-family-wide-
// substrate-array, reject-arity-below-cardinality, reject-
// arity-above-cardinality, reject-duplicate, reject-out-of-range,
// panic-message-provenance on the ARITY-MISMATCH axis, panic-
// message-provenance on the DELEGATED range-coverage axis,
// panic-message-provenance on the DELEGATED pairwise-distinct
// axis) split across the THREE failure arms so a regression that
// silently weakens the helper on ANY arm (e.g. dropping the arity
// check, dropping the range-coverage delegation, or dropping the
// pairwise-distinct delegation) is caught by the helper's OWN
// test surface rather than only surfacing as a false-positive on
// some future permutation-shaped `[u8; N]` array's compound pin.
#[test]
fn assert_u8_array_permutes_inclusive_range_accepts_the_singleton_range() {
// Singleton range `{K..=K}` at the `[u8; 1]` corner — a
// singleton array `[K]` is vacuously a permutation of `{K}`.
// Cross-arity coverage on the trivial-range corner of the
// const-N generic; simultaneously pins ALL THREE arms
// (ARITY: `1 == 1`; RANGE-MEMBERSHIP: `K in [K, K]`;
// PAIRWISE-DISTINCT: vacuously true on a singleton) at the
// smallest witness. Sibling posture to
// `assert_u8_array_covers_inclusive_range_accepts_the_
// singleton_range` on the delegated range-coverage helper.
assert_u8_array_permutes_inclusive_range::<1, 7, 7>(&[7u8]);
assert_u8_array_permutes_inclusive_range::<1, 0, 0>(&[0u8]);
assert_u8_array_permutes_inclusive_range::<1, 255, 255>(&[255u8]);
}
#[test]
fn assert_u8_array_permutes_inclusive_range_accepts_every_family_wide_permutation_array() {
// Runtime cross-check that the SAME three permutation-shaped
// HASH_DISCRIMINATORS arrays the module-level `const _: () =
// ...` witnesses cover at COMPILE time are permutations of
// their target ranges. A regression that removes ONE of the
// `const _` witnesses would still leave THIS runtime pin as
// a safety net; the const witness fires FIRST at `cargo
// check`, this runtime pin catches the drift at `cargo test`.
// The pair enforces the theorem at TWO stages of the
// toolchain. Sibling posture to
// `assert_u8_array_covers_inclusive_range_accepts_every_
// family_wide_substrate_array` on the delegated range-
// coverage helper; where that pin sweeps FOUR arrays
// (`SexpShape` + `AtomKind` + `QuoteForm` + `UnquoteForm`)
// on the single-axis SURJECTIVITY corner, this pin sweeps
// the THREE permutation-shaped arrays on the compound
// (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) corner —
// `SexpShape::HASH_DISCRIMINATORS` is intentionally OMITTED
// per the twelve-shape → seven-byte collapse rule
// (DISTINCTNESS does not hold; it binds SURJECTIVITY-only
// on the sibling helper).
assert_u8_array_permutes_inclusive_range::<6, 0, 5>(&AtomKind::HASH_DISCRIMINATORS);
assert_u8_array_permutes_inclusive_range::<4, 3, 6>(&QuoteForm::HASH_DISCRIMINATORS);
assert_u8_array_permutes_inclusive_range::<2, 5, 6>(
&crate::error::UnquoteForm::HASH_DISCRIMINATORS,
);
}
#[test]
#[should_panic(expected = "ARITY-MISMATCH")]
fn assert_u8_array_permutes_inclusive_range_panics_at_runtime_on_arity_below_cardinality() {
// NEGATIVE PIN — ARITY-MISMATCH below-cardinality corner: an
// array of arity `N < HI - LO + 1` MUST panic at runtime with
// the ARITY-MISMATCH-named message. Pins the compound
// helper's OWN reject-below-cardinality arm — a regression
// that silently dropped the arity-check gate would let this
// array reach the delegated `assert_u8_array_covers_
// inclusive_range` call, which would then panic with the
// sibling helper's `"MISSING"` message on the range byte
// absent from the too-short array — masking the ARITY-
// provenance behind the coverage-provenance downstream.
assert_u8_array_permutes_inclusive_range::<2, 0, 2>(&[0u8, 2u8]);
}
#[test]
#[should_panic(expected = "ARITY-MISMATCH")]
fn assert_u8_array_permutes_inclusive_range_panics_at_runtime_on_arity_above_cardinality() {
// NEGATIVE PIN — ARITY-MISMATCH above-cardinality corner: an
// array of arity `N > HI - LO + 1` MUST panic at runtime with
// the ARITY-MISMATCH-named message. Symmetric sibling to the
// below-cardinality pin — a regression that dropped the
// arity-check gate would let this array reach the delegated
// `assert_u8_array_pairwise_distinct` call, which would then
// panic with the sibling helper's generic-duplicate message
// on the pigeonhole-forced collision, masking the ARITY-
// provenance behind the pairwise-distinct-provenance
// downstream. The three entries stay within `[0, 1]` and are
// pairwise-distinct on the first two positions, so the arity
// check is the ONLY axis that can distinguish this from a
// valid permutation.
assert_u8_array_permutes_inclusive_range::<3, 0, 1>(&[0u8, 1u8, 0u8]);
}
#[test]
#[should_panic(expected = "duplicate")]
fn assert_u8_array_permutes_inclusive_range_panics_at_runtime_on_duplicate() {
// NEGATIVE PIN — PAIRWISE-DISTINCT arm: an array whose arity
// matches the range cardinality but which contains a
// duplicate entry (necessarily missing a range byte by
// pigeonhole) MUST panic at runtime. Pins the delegated
// `assert_u8_array_pairwise_distinct` arm — a regression
// that silently dropped the delegation would leave the
// duplicate uncaught. Note: the panic message here surfaces
// from the SIBLING helper (containing `"duplicate"`) rather
// than a compound-helper-namespaced string, per the
// delegation-based body design; the compound helper's OWN
// name still appears in the const-eval panic trace for a
// caller debugging a `cargo check` failure.
assert_u8_array_permutes_inclusive_range::<3, 0, 2>(&[0u8, 1u8, 1u8]);
}
#[test]
#[should_panic(expected = "OUT-OF-RANGE")]
fn assert_u8_array_permutes_inclusive_range_panics_at_runtime_on_out_of_range() {
// NEGATIVE PIN — RANGE-MEMBERSHIP arm: an array whose arity
// matches the range cardinality but which contains an
// out-of-range entry MUST panic at runtime with the
// delegated `assert_u8_array_covers_inclusive_range`'s
// `"OUT-OF-RANGE"` axis-provenance message. Pins the
// delegated range-membership arm — a regression that
// silently dropped the delegation would leave the
// out-of-range entry uncaught. The three entries `[0, 1, 3]`
// exhaust the arity of `[0..=2]` (3 entries for a 3-byte
// range) but include `3u8` outside the target range;
// pairwise-distinct is satisfied so this array can ONLY be
// rejected on the range-membership axis.
assert_u8_array_permutes_inclusive_range::<3, 0, 2>(&[0u8, 1u8, 3u8]);
}
#[test]
fn assert_u8_array_permutes_inclusive_range_panic_message_names_the_helper_and_arity_mismatch_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — ARITY-MISMATCH arm: the
// panic message MUST begin with the compound helper's own
// name AND identify the failed AXIS as "ARITY-MISMATCH" so
// downstream diagnostics route the drift back to (a) THIS
// compound helper by string search on
// `"assert_u8_array_permutes_inclusive_range"` and (b) the
// ARITY axis by string search on `"ARITY-MISMATCH"`. This
// string is chosen DISTINCT from every sibling helper's axis
// strings ("OUT-OF-RANGE" / "MISSING" on the range-coverage
// helper; "OUT-OF-SET" / "SET-BYTE-MISSING" on the finite-
// set-coverage helper) so a drift's axis-provenance routes
// UNAMBIGUOUSLY to (helper, axis) even in the presence of
// the multiple sibling helpers. Sibling posture to
// `assert_u8_array_covers_inclusive_range_panic_message_
// names_the_helper_and_range_bound_axis` on the range-
// coverage helper — both bind the (helper, failed-axis)
// provenance pair at ONE test per axis.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_permutes_inclusive_range::<2, 0, 2>(&[0u8, 2u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_permutes_inclusive_range must panic on \
an arity-cardinality mismatch — the reject-arity-\
mismatch arm is one of the three failure modes of the \
compound helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_permutes_inclusive_range panic \
payload must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_permutes_inclusive_range"),
"assert_u8_array_permutes_inclusive_range ARITY-MISMATCH \
panic message {msg:?} must name the helper for \
provenance-preserving failure diagnostics",
);
assert!(
msg.contains("ARITY-MISMATCH"),
"assert_u8_array_permutes_inclusive_range ARITY-MISMATCH \
panic message {msg:?} must name the failed AXIS \
(\"ARITY-MISMATCH\") for axis-provenance-preserving \
failure diagnostics — the string is chosen DISTINCT \
from every sibling helper's axis strings so downstream \
diagnostics route UNAMBIGUOUSLY to this compound \
helper's arity arm",
);
}
// ── `assert_u8_array_permutes_finite_set` — the compound
// (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) permutation-of-finite-set
// verifier on the NON-CONTIGUOUS-FINITE-SET corner of the
// (contiguity) axis peer to the pre-existing
// `assert_u8_array_permutes_inclusive_range` (contiguous-
// inclusive-range corner) sibling. Ships `StructuralKind::HASH_
// DISCRIMINATORS` from the pre-lift weak-witness pair
// (`assert_u8_array_pairwise_distinct` + `assert_u8_array_covers_
// finite_set`) into the compound tier at ONE `const _` line while
// adding the arity-cardinality-equality contract that neither
// weak sibling carries alone. The runtime test surface mirrors
// the sibling `assert_u8_array_permutes_inclusive_range` compound
// helper's shape (accept-singleton-set, accept-every-family-wide-
// substrate-array, reject-arity-below-cardinality, reject-arity-
// above-cardinality, reject-duplicate, reject-out-of-set, panic-
// message-provenance on the ARITY-MISMATCH axis) split across the
// three failure arms so a regression that silently weakens the
// helper on ANY arm (e.g. dropping the arity check, dropping the
// covers-finite-set delegation, or dropping the pairwise-distinct
// delegation) is caught by the helper's OWN test surface rather
// than only surfacing as a false-positive on some future
// permutation-of-finite-set-shaped `[u8; N]` array's compound pin.
#[test]
fn assert_u8_array_permutes_finite_set_accepts_the_singleton_set() {
// Singleton set `{K}` at the `[u8; 1]` corner — a singleton
// array `[K]` is vacuously a permutation of `{K}`. Cross-arity
// coverage on the trivial-set corner of the const-N generic;
// simultaneously pins ALL THREE arms (ARITY: `1 == 1`; SET-
// MEMBERSHIP: `K in {K}`; PAIRWISE-DISTINCT: vacuously true on
// a singleton) at the smallest witness. Sibling posture to
// `assert_u8_array_permutes_inclusive_range_accepts_the_
// singleton_range` on the contiguous-range corner peer.
assert_u8_array_permutes_finite_set::<1, 1>(&[7u8], &[7u8]);
assert_u8_array_permutes_finite_set::<1, 1>(&[0u8], &[0u8]);
assert_u8_array_permutes_finite_set::<1, 1>(&[255u8], &[255u8]);
}
#[test]
fn assert_u8_array_permutes_finite_set_accepts_every_family_wide_permutation_of_finite_set_array(
) {
// Runtime cross-check that the SAME
// `StructuralKind::HASH_DISCRIMINATORS` array the module-level
// `const _: () = ...` witness covers at COMPILE time is a
// permutation of the non-contiguous target set `{0, 2}`. A
// regression that removes the `const _` witness would still
// leave THIS runtime pin as a safety net; the const witness
// fires FIRST at `cargo check`, this runtime pin catches the
// drift at `cargo test`. The pair enforces the theorem at TWO
// stages of the toolchain. Sibling posture to
// `assert_u8_array_permutes_inclusive_range_accepts_every_
// family_wide_permutation_array` on the contiguous-range
// corner: where that pin sweeps THREE range-covering arrays
// (`AtomKind` + `QuoteForm` + `UnquoteForm`), this pin binds
// the ONE non-contiguous-covering permutation-shaped array
// (`StructuralKind`). Together the two runtime pins close the
// whole compound tier of the substrate's `[u8; N]`
// HASH_DISCRIMINATORS vocabulary at runtime symmetrically to
// the compile-time compound witnesses.
assert_u8_array_permutes_finite_set::<2, 2>(
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&[0u8, 2u8],
);
}
#[test]
fn assert_u8_array_permutes_finite_set_accepts_a_synthetic_non_contiguous_partition() {
// POSITIVE — a synthetic `[u8; 3]` permutation of the non-
// contiguous partition `{0, 2, 5}` (two gaps: at `{1}` and at
// `{3, 4}`). Isolates the helper's INJECTIVITY-∧-SURJECTIVITY-
// ∧-ARITY verdict from the substrate constants: a green here
// plus a red on any of the negative pins below constrains the
// helper's behavior structurally on the non-contiguous corner,
// independent of the substrate's specific byte layout. Sibling
// posture to `assert_u8_array_covers_finite_set_accepts_the_
// non_contiguous_partition` on the single-axis SURJECTIVITY
// sibling — where that pin binds the (SET-MEMBERSHIP + FULL-
// COVERAGE) axes on a non-contiguous set, THIS pin binds the
// compound (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY) contract on
// the same shape.
assert_u8_array_permutes_finite_set::<3, 3>(&[0u8, 2u8, 5u8], &[0u8, 2u8, 5u8]);
assert_u8_array_permutes_finite_set::<3, 3>(&[5u8, 0u8, 2u8], &[0u8, 2u8, 5u8]);
}
#[test]
#[should_panic(expected = "ARITY-MISMATCH")]
fn assert_u8_array_permutes_finite_set_panics_at_runtime_on_arity_below_cardinality() {
// NEGATIVE PIN — ARITY-MISMATCH below-cardinality corner: an
// array of arity `N < M` MUST panic at runtime with the ARITY-
// MISMATCH-named message. Pins the compound helper's OWN
// reject-below-cardinality arm — a regression that silently
// dropped the arity-check gate would let this array reach the
// delegated `assert_u8_array_covers_finite_set` call, which
// would then panic with the sibling helper's `"SET-BYTE-
// MISSING"` message on the set byte absent from the too-short
// array — masking the ARITY-provenance behind the coverage-
// provenance downstream. The array `[0]` covers set byte `0`
// but is missing set byte `2`. Sibling posture to
// `assert_u8_array_permutes_inclusive_range_panics_at_runtime_
// on_arity_below_cardinality` on the contiguous-range corner.
assert_u8_array_permutes_finite_set::<1, 2>(&[0u8], &[0u8, 2u8]);
}
#[test]
#[should_panic(expected = "ARITY-MISMATCH")]
fn assert_u8_array_permutes_finite_set_panics_at_runtime_on_arity_above_cardinality() {
// NEGATIVE PIN — ARITY-MISMATCH above-cardinality corner: an
// array of arity `N > M` MUST panic at runtime with the
// ARITY-MISMATCH-named message. Symmetric sibling to the
// below-cardinality pin — a regression that dropped the arity-
// check gate would let this array reach the delegated
// `assert_u8_array_pairwise_distinct` call, which would then
// panic with the sibling helper's generic-duplicate message on
// the pigeonhole-forced collision, masking the ARITY-
// provenance behind the pairwise-distinct-provenance
// downstream. The three entries `[0, 2, 0]` stay within
// `{0, 2}` (satisfying SET-MEMBERSHIP) but WOULD fail
// pairwise-distinct downstream on the duplicate `0u8` —
// however, the ARITY-check FIRES FIRST so the panic message
// routes to the ARITY axis with the compound helper's own
// name.
assert_u8_array_permutes_finite_set::<3, 2>(&[0u8, 2u8, 0u8], &[0u8, 2u8]);
}
#[test]
#[should_panic(expected = "duplicate")]
fn assert_u8_array_permutes_finite_set_panics_at_runtime_on_duplicate() {
// NEGATIVE PIN — PAIRWISE-DISTINCT arm: an array whose arity
// matches the set cardinality but which contains a duplicate
// entry (necessarily missing a set byte by pigeonhole) MUST
// panic at runtime. Pins the delegated
// `assert_u8_array_pairwise_distinct` arm — a regression that
// silently dropped the delegation would leave the duplicate
// uncaught. Note: the panic message here surfaces from the
// SIBLING helper (containing `"duplicate"`) rather than a
// compound-helper-namespaced string, per the delegation-based
// body design; the compound helper's OWN name still appears
// in the const-eval panic trace for a caller debugging a
// `cargo check` failure. Sibling posture to
// `assert_u8_array_permutes_inclusive_range_panics_at_runtime_
// on_duplicate` on the contiguous-range corner.
assert_u8_array_permutes_finite_set::<3, 3>(&[0u8, 2u8, 2u8], &[0u8, 2u8, 5u8]);
}
#[test]
#[should_panic(expected = "OUT-OF-SET")]
fn assert_u8_array_permutes_finite_set_panics_at_runtime_on_out_of_set() {
// NEGATIVE PIN — SET-MEMBERSHIP arm: an array whose arity
// matches the set cardinality but which contains an entry
// outside the target set MUST panic at runtime with the
// delegated `assert_u8_array_covers_finite_set`'s `"OUT-OF-
// SET"` axis-provenance message. Pins the delegated set-
// membership arm — a regression that silently dropped the
// delegation would leave the out-of-set entry uncaught. The
// three entries `[0, 2, 3]` exhaust the arity of `{0, 2, 5}`
// (3 entries for a 3-byte set) but include `3u8` outside the
// target set; pairwise-distinct is satisfied so this array
// can ONLY be rejected on the set-membership axis. Sibling
// posture to `assert_u8_array_permutes_inclusive_range_panics_
// at_runtime_on_out_of_range` on the contiguous-range corner
// (`"OUT-OF-SET"` here vs. `"OUT-OF-RANGE"` there — chosen
// DISTINCT so downstream diagnostics route UNAMBIGUOUSLY to
// the failed contiguity corner).
assert_u8_array_permutes_finite_set::<3, 3>(&[0u8, 2u8, 3u8], &[0u8, 2u8, 5u8]);
}
#[test]
#[should_panic(expected = "OUT-OF-SET")]
fn assert_u8_array_permutes_finite_set_panics_on_gap_byte_drift() {
// NEGATIVE PIN — ARCHETYPE GAP-BYTE corner: an entry that
// drifts INTO the intentional gap of a non-contiguous target
// set MUST panic — this is the exact regression the archetype
// `StructuralKind::HASH_DISCRIMINATORS` witness catches. A
// regression that lifted a fresh `1u8` entry into the
// `{0, 2}`-partitioned array would silently collide with
// `AtomKind::OUTER_HASH_DISCRIMINATOR = 1u8` on the outer-
// `Sexp` cache-key partition; this pin binds that failure mode
// as an OUT-OF-SET rejection at the delegated covers-finite-
// set arm's panic site. Sibling posture to `assert_u8_array_
// covers_finite_set_panics_on_gap_byte_drift` at the single-
// axis SURJECTIVITY sibling — where that pin binds the gap-
// byte-drift failure at the (SET-MEMBERSHIP) axis alone, THIS
// pin binds the SAME drift on the compound (INJECTIVITY ∧
// SURJECTIVITY ∧ ARITY) contract. The four-entry witness
// `[0, 1, 2, 5]` stays pairwise-distinct and matches the set
// cardinality of `{0, 2, 1, 5}` but the middle `1u8` — if the
// set were `{0, 2, 5}` and `[0, 1, 2]` were the array — would
// fire the OUT-OF-SET arm; here the arity is aligned to test
// the middle-gap drift with `1u8` in `arr` but NOT in `set`.
assert_u8_array_permutes_finite_set::<3, 3>(&[0u8, 1u8, 2u8], &[0u8, 2u8, 5u8]);
}
#[test]
fn assert_u8_array_permutes_finite_set_panic_message_names_the_helper_and_arity_mismatch_axis()
{
// PANIC-MESSAGE PROVENANCE PIN — ARITY-MISMATCH arm: the panic
// message MUST begin with the compound helper's own name AND
// identify the failed AXIS as "ARITY-MISMATCH" so downstream
// diagnostics route the drift back to (a) THIS compound helper
// by string search on
// `"assert_u8_array_permutes_finite_set"` and (b) the ARITY
// axis by string search on `"ARITY-MISMATCH"`. The
// "ARITY-MISMATCH" axis-name is SHARED with the contiguous-
// range sibling `assert_u8_array_permutes_inclusive_range`
// (both compound permutation helpers share the arity axis),
// but the HELPER-name distinguishes the two: string search on
// (`"assert_u8_array_permutes_finite_set"`, `"ARITY-MISMATCH"`)
// routes UNAMBIGUOUSLY to the (non-contiguous corner, arity
// arm) pair. Sibling posture to
// `assert_u8_array_permutes_inclusive_range_panic_message_
// names_the_helper_and_arity_mismatch_axis` on the contiguous-
// range corner — both bind the (helper, failed-axis)
// provenance pair at ONE test per axis.
let outcome = std::panic::catch_unwind(|| {
assert_u8_array_permutes_finite_set::<1, 2>(&[0u8], &[0u8, 2u8]);
});
let payload = outcome.expect_err(
"assert_u8_array_permutes_finite_set must panic on an \
arity-cardinality mismatch — the reject-arity-mismatch \
arm is one of the three failure modes of the compound \
helper",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_u8_array_permutes_finite_set panic payload \
must be a static &str or String",
);
assert!(
msg.contains("assert_u8_array_permutes_finite_set"),
"assert_u8_array_permutes_finite_set ARITY-MISMATCH panic \
message {msg:?} must name the helper for provenance-\
preserving failure diagnostics — the HELPER-name is the \
axis-name-tie-breaker between this helper and the \
contiguous-range sibling which SHARES the \
\"ARITY-MISMATCH\" axis-provenance string",
);
assert!(
msg.contains("ARITY-MISMATCH"),
"assert_u8_array_permutes_finite_set ARITY-MISMATCH panic \
message {msg:?} must name the failed AXIS \
(\"ARITY-MISMATCH\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── `assert_scalar_plus_two_u8_arrays_permute_inclusive_range` —
// the compound JOINT (INJECTIVITY ∧ SURJECTIVITY ∧ ARITY)
// permutation-of-range verifier on the (scalar-plus-two-arrays)
// corner of the (carving-shape) axis peer to the pre-existing
// (single-array) corner. The runtime test surface matches the
// sibling `assert_u8_array_permutes_inclusive_range` compound
// helper's shape (accept-canonical-outer-Sexp-partition, accept-
// synthetic-valid-partition, reject-arity-below-cardinality,
// reject-arity-above-cardinality, reject-scalar-out-of-range,
// reject-first-array-out-of-range, reject-second-array-out-of-
// range, reject-cross-carving-duplicate, reject-intra-carving-
// duplicate, panic-message-provenance on the JOINT ARITY-
// MISMATCH axis, panic-message-provenance on the JOINT SCALAR-
// OUT-OF-RANGE axis) split across the six failure arms so a
// regression that silently weakens the helper on ANY arm is
// caught by the helper's OWN test surface rather than only
// surfacing as a false-positive on some future permutation-
// shaped joint carving's compound pin.
#[test]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_accepts_canonical_outer_sexp_partition(
) {
// Runtime cross-check that the SAME joint carving the
// module-level `const _: () = ...` witness covers at COMPILE
// time is a permutation of the outer-`Sexp` cache-key
// discriminator range `{0..=6}`. A regression that removes
// the `const _` witness would still leave THIS runtime pin as
// a safety net; the const witness fires FIRST at `cargo
// check`, this runtime pin catches the drift at `cargo test`.
// The pair enforces the joint theorem at TWO stages of the
// toolchain. Sibling posture to
// `assert_u8_array_permutes_inclusive_range_accepts_every_
// family_wide_permutation_array` on the (single-array)
// corner — where that pin sweeps THREE arrays on the
// single-array corner, THIS pin binds the ONE joint carving
// on the (scalar-plus-two-arrays) corner.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
AtomKind::OUTER_HASH_DISCRIMINATOR,
&crate::error::StructuralKind::HASH_DISCRIMINATORS,
&QuoteForm::HASH_DISCRIMINATORS,
);
}
#[test]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_accepts_synthetic_valid_partition()
{
// POSITIVE — a valid `(scalar, [u8; 2], [u8; 4])` permutation
// of `{0..=6}` byte-identical in shape to the outer-`Sexp`
// partition but with the scalar at `1u8` remapped through
// literals rather than the substrate constant. Isolates the
// helper's INJECTIVITY-∧-SURJECTIVITY-∧-ARITY verdict from
// the substrate constants: a green here plus a red on any
// of the negative pins below constrains the helper's
// behavior structurally, independent of the substrate's
// specific byte layout.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
1u8,
&[0u8, 2u8],
&[3u8, 4u8, 5u8, 6u8],
);
}
#[test]
#[should_panic(expected = "ARITY-MISMATCH")]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panics_at_runtime_on_arity_below_cardinality(
) {
// NEGATIVE PIN — ARITY-MISMATCH below-cardinality corner: a
// joint carving of arity `1 + M + N < HI - LO + 1` MUST
// panic at runtime with the ARITY-MISMATCH-named message.
// Pins the helper's OWN reject-below-cardinality arm — a
// regression that silently dropped the arity-check gate
// would let this triple reach the sweep-and-count loop,
// which would then panic with `"MISSING"` on the range byte
// absent from the too-short joint carving — masking the
// JOINT ARITY-provenance behind the JOINT SURJECTIVITY-
// provenance downstream. Sibling posture to
// `assert_u8_array_permutes_inclusive_range_panics_at_
// runtime_on_arity_below_cardinality` on the (single-array)
// corner.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 3, 0, 6>(
1u8,
&[0u8, 2u8],
&[3u8, 4u8, 5u8],
);
}
#[test]
#[should_panic(expected = "ARITY-MISMATCH")]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panics_at_runtime_on_arity_above_cardinality(
) {
// NEGATIVE PIN — ARITY-MISMATCH above-cardinality corner:
// symmetric sibling to the below-cardinality pin. `1 + 2 + 3
// = 6` slots for a `{0..=2}` range of cardinality 3 — the
// arity check fires FIRST before the sweep-and-count would
// catch the joint duplicates on `0`/`1`/`2`. Pins that the
// ARITY-provenance surfaces even when downstream axes would
// ALSO reject.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 3, 0, 2>(
0u8,
&[1u8, 2u8],
&[0u8, 1u8, 2u8],
);
}
#[test]
#[should_panic(expected = "OUT-OF-RANGE")]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panics_at_runtime_on_scalar_out_of_range(
) {
// NEGATIVE PIN — SCALAR OUT-OF-RANGE arm: a joint carving
// whose arity matches the range cardinality but whose SCALAR
// lies outside `[LO, HI]` MUST panic at runtime. Pins the
// helper's scalar-carving arm distinct from the array
// carvings' out-of-range arms — a regression that skipped
// the scalar check but kept the array checks would leave
// this drift uncaught.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
7u8,
&[0u8, 2u8],
&[3u8, 4u8, 5u8, 6u8],
);
}
#[test]
#[should_panic(expected = "OUT-OF-RANGE")]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panics_at_runtime_on_first_array_out_of_range(
) {
// NEGATIVE PIN — FIRST-ARRAY OUT-OF-RANGE arm: a joint
// carving whose arity + scalar are valid but whose FIRST
// ARRAY carries an out-of-range entry MUST panic at runtime.
// The `1u8` slot the scalar occupies is left absent from
// the first array; the entry `7u8` lies outside `[0, 6]`.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
1u8,
&[0u8, 7u8],
&[3u8, 4u8, 5u8, 6u8],
);
}
#[test]
#[should_panic(expected = "OUT-OF-RANGE")]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panics_at_runtime_on_second_array_out_of_range(
) {
// NEGATIVE PIN — SECOND-ARRAY OUT-OF-RANGE arm: symmetric
// sibling to the first-array pin. The entry `9u8` in the
// second array lies outside `[0, 6]`; all other arms are
// green.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
1u8,
&[0u8, 2u8],
&[3u8, 4u8, 5u8, 9u8],
);
}
#[test]
#[should_panic(expected = "duplicate")]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panics_at_runtime_on_cross_carving_duplicate(
) {
// NEGATIVE PIN — JOINT-duplicate arm (cross-carving): the
// byte `1u8` appears in BOTH the scalar carving AND the
// first array. Arity matches, all bytes are in-range, but
// JOINT INJECTIVITY fails — the duplicate byte occurs at
// `count == 2` in the sweep-and-count loop, masking the
// pigeonhole-forced JOINT-MISSING at byte `2u8` behind the
// duplicate arm's message. Pins the cross-carving collision
// detection between the scalar arm and a downstream array
// arm.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
1u8,
&[0u8, 1u8],
&[3u8, 4u8, 5u8, 6u8],
);
}
#[test]
#[should_panic(expected = "duplicate")]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panics_at_runtime_on_intra_carving_duplicate(
) {
// NEGATIVE PIN — JOINT-duplicate arm (intra-carving): the
// byte `0u8` appears TWICE inside the first array. Arity
// matches, all bytes are in-range, but JOINT INJECTIVITY
// fails — the sweep-and-count discipline treats intra- and
// cross-carving collisions with the SAME mechanism, so this
// failure mode surfaces on the same `"duplicate"` axis-
// provenance message as the cross-carving pin.
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 4, 0, 6>(
1u8,
&[0u8, 0u8],
&[3u8, 4u8, 5u8, 6u8],
);
}
#[test]
fn assert_scalar_plus_two_u8_arrays_permute_inclusive_range_panic_message_names_the_helper_and_arity_mismatch_axis(
) {
// PANIC-MESSAGE PROVENANCE PIN — ARITY-MISMATCH arm: the
// panic message MUST begin with the compound helper's own
// name AND identify the failed AXIS as "ARITY-MISMATCH".
// Sibling posture to `assert_u8_array_permutes_inclusive_
// range_panic_message_names_the_helper_and_arity_mismatch_
// axis` on the (single-array) corner — both bind the
// (helper, failed-axis) provenance pair.
let outcome = std::panic::catch_unwind(|| {
assert_scalar_plus_two_u8_arrays_permute_inclusive_range::<2, 3, 0, 6>(
1u8,
&[0u8, 2u8],
&[3u8, 4u8, 5u8],
);
});
let payload = outcome.expect_err(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range \
must panic on an arity-cardinality mismatch",
);
let msg = payload
.downcast_ref::<&'static str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.expect(
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range \
panic payload must be a static &str or String",
);
assert!(
msg.contains("assert_scalar_plus_two_u8_arrays_permute_inclusive_range"),
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range \
ARITY-MISMATCH panic message {msg:?} must name the helper \
for provenance-preserving failure diagnostics",
);
assert!(
msg.contains("ARITY-MISMATCH"),
"assert_scalar_plus_two_u8_arrays_permute_inclusive_range \
ARITY-MISMATCH panic message {msg:?} must name the failed \
AXIS (\"ARITY-MISMATCH\") for axis-provenance-preserving \
failure diagnostics",
);
}
// ── node_count: structural size on the outer Sexp algebra ──────────
#[test]
fn node_count_nil_is_one() {
// The residual-axis unit-payload arm contributes exactly one
// node — the outer arm itself. Base case of the recursion.
assert_eq!(Sexp::Nil.node_count(), 1);
}
#[test]
fn node_count_atom_is_one_for_every_atom_kind() {
// Every atomic arm — Symbol, Keyword, Str, Int, Float, Bool —
// is a leaf on the AST algebra. The payload's own length
// (a string with 100 chars, an integer with a large value)
// does not contribute; the projection counts NODES on the
// typed algebra, not bytes on the payload.
assert_eq!(Sexp::symbol("foo").node_count(), 1);
assert_eq!(Sexp::keyword("k").node_count(), 1);
assert_eq!(Sexp::string("hello world").node_count(), 1);
assert_eq!(Sexp::int(42).node_count(), 1);
assert_eq!(Sexp::float(1.5).node_count(), 1);
assert_eq!(Sexp::boolean(true).node_count(), 1);
assert_eq!(
Sexp::symbol("a-symbol-with-a-very-long-name").node_count(),
1
);
}
#[test]
fn node_count_empty_list_is_one() {
// The residual-axis payload-bearing arm with an empty payload
// contributes exactly one node — the outer arm itself, no
// children to sum over. Sits at the boundary between the
// `Sexp::Nil` unit arm (also one node) and every non-empty
// list.
assert_eq!(Sexp::List(vec![]).node_count(), 1);
}
#[test]
fn node_count_flat_list_is_one_plus_child_count() {
// `(a b c)` — one outer List arm plus three Atom children,
// each contributing one node. Load-bearing arithmetic
// identity: `list(items).node_count() == 1 +
// sum(item.node_count())` with atom children.
let form = Sexp::list([Sexp::symbol("a"), Sexp::symbol("b"), Sexp::symbol("c")]);
assert_eq!(form.node_count(), 4);
}
#[test]
fn node_count_nested_list_sums_recursively() {
// `(a (b c) d)` — one outer, plus a=1, plus inner (b c)=3,
// plus d=1. Total 6. Pins the recursive sum over the tree.
let form = Sexp::list([
Sexp::symbol("a"),
Sexp::list([Sexp::symbol("b"), Sexp::symbol("c")]),
Sexp::symbol("d"),
]);
assert_eq!(form.node_count(), 6);
}
#[test]
fn node_count_each_quote_family_wrapper_adds_one_plus_inner() {
// The four homoiconic wrappers each contribute one node for
// the wrapper arm plus the node count of the wrapped inner.
// `'x` = 2 (Quote wrapper + Atom x).
// `` `x `` = 2. `,x` = 2. `,@x` = 2.
let x = Sexp::symbol("x");
assert_eq!(Sexp::Quote(Box::new(x.clone())).node_count(), 2);
assert_eq!(Sexp::Quasiquote(Box::new(x.clone())).node_count(), 2);
assert_eq!(Sexp::Unquote(Box::new(x.clone())).node_count(), 2);
assert_eq!(Sexp::UnquoteSplice(Box::new(x.clone())).node_count(), 2);
// Nested inner: `'(a b)` = Quote wrapper (1) + inner (a b)
// list (3) = 4. Pins the recursion through wrappers.
let inner = Sexp::list([Sexp::symbol("a"), Sexp::symbol("b")]);
assert_eq!(Sexp::Quote(Box::new(inner)).node_count(), 4);
}
#[test]
fn node_count_is_monotone_under_list_growth() {
// Adding a strictly-larger subtree to a list strictly grows
// the node count. LOAD-BEARING monotonicity pin — a resource
// ceiling keyed on `node_count` relies on this identity so
// that a strictly-larger expansion is bounded by a strictly-
// larger count. A regression that ever ignored a child's
// contribution (a bug that hardcoded arm-only counting)
// fails this pin because the added subtree's own children
// would silently drop out.
let small = Sexp::list([Sexp::symbol("a")]);
let large = Sexp::list([
Sexp::symbol("a"),
Sexp::list([Sexp::symbol("b"), Sexp::symbol("c")]),
]);
assert!(large.node_count() > small.node_count());
assert_eq!(small.node_count(), 2);
assert_eq!(large.node_count(), 5);
}
}