1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! The case-sensitivity axis every vocabulary parse table declares, and
//! the two matching strategies that axis chooses between.
//!
//! # The law
//!
//! Case-sensitivity is a **per-household constitutional attribute**, not
//! a crate-wide default. Every vocabulary's [`FromStr`](core::str::FromStr)
//! names its [`Case`] explicitly, as the first argument to the one call
//! that resolves its match key ([`lookup`]) — right beside the `match`
//! table that key feeds. There is no [`Default`] impl for [`Case`], so a
//! household cannot omit the choice; leaving it out is a compile error
//! (a missing function argument), not a silently-assumed mode. Both
//! strategies are **one implementation each** ([`fold`] for
//! [`Case::Insensitive`]; the verbatim pass-through in [`lookup`] for
//! [`Case::Sensitive`]) that every household shares through [`lookup`] —
//! a `FromStr` body never reimplements either, it only names which one
//! applies.
//!
//! - [`Case::Insensitive`]: the roster is matched through [`fold`] —
//! ASCII case-folded, so `"BT709"`, `"Bt709"` and `"bt709"` are one
//! value, the same **named** variant. Only a genuine stranger — a
//! spelling the folded lookup still misses — reaches the
//! `Other(SmolStr)` escape, and it carries the caller's spelling
//! **verbatim**: folding a name nobody claims would destroy
//! information (vendor fourccs and codec tags are routinely
//! case-sensitive) for no compensating benefit, now that the lookup
//! already catches every case-variant of a name this crate *does*
//! recognise. **Every household in this crate is `Insensitive` today**
//! — all 22 are lowercase-slug domains with no distinctly-cased roster
//! member, so this axis lands with zero behaviour change; it exists so
//! the choice is provable rather than assumed.
//! - [`Case::Sensitive`]: the roster is matched on **exact bytes**, no
//! folding, no [`FOLD_CAP`] length cap (there is nothing to fold, so
//! nothing to fit in a fold buffer — an exact comparison either equals
//! a slug or it does not, at any length). A case variant of a roster
//! name is not a healed hit here, it is an ordinary table miss — the
//! same verbatim-stranger escape as any other unrecognised spelling.
//! Right for a **fourcc-shaped** domain (vendor codec tags, container
//! FourCCs, and similar wire-vocabulary alphabets that are
//! case-sensitive **by convention**, where two different casings can
//! legitimately name two different real-world values): folding one
//! spelling onto another there would silently substitute a different,
//! *wrong* roster member for the caller's actual value —
//! error-beats-wrong-value. No household needs this yet; [`lookup`]'s
//! own tests pin the strategy end-to-end against a test-only table (see
//! `parse::tests`), so the first real `Sensitive` household inherits
//! machinery already proven, rather than being the first thing to
//! exercise it.
//!
//! `Self::other` (every open household's escape constructor) already
//! runs its own [`FromStr`] lookup rather than a second table — so it
//! inherits whichever [`Case`] the household declared with no extra
//! wiring, exactly as it inherits the rest of the match table. One axis,
//! named once per household, however the value is reached.
//!
//! Folding — where [`Case::Insensitive`] chooses it — is deliberately
//! **ASCII-only**. These are FFmpeg / H.273 / file extension identifiers;
//! Unicode case folding is locale-sensitive (Turkish dotless i maps `I`
//! to `ı`, not `i`) in ways a wire vocabulary must not be, and would make
//! the canonical form depend on who is reading.
//!
//! The lookup itself is on the **byte side**: [`lookup`] yields the
//! resolved bytes and every table arm is a `b"slug"` literal (spelled in
//! whatever case that household's own [`Case`] compares against — the
//! canonical lowercase slug for every `Insensitive` household today). A
//! `FromStr` added here writes its table that way.
//!
//! The errors these parses return live with the vocabularies themselves,
//! one per type — a `Rational` that is malformed and a `Matrix` that names
//! nothing are different failures, and the type is what says which.
/// Capacity of the stack buffer [`fold`] folds into.
///
/// The longest canonical slug in the crate is well under this; the buffer
/// exists because the coded vocabularies are available at the crate's
/// no-alloc tier, where there is no heap to fold into. An input that does
/// not fit cannot name a variant either, so the caller treats the
/// overflow as an ordinary miss.
///
/// Only [`Case::Insensitive`] folds, so only that strategy is subject to
/// this cap — [`Case::Sensitive`] compares the input's own bytes and has
/// no length limit. Every [`lookup`] call site still allocates a buffer
/// of this size regardless of which [`Case`] it declares, so the two
/// strategies stay one declaration word apart at the call site; the
/// buffer a `Sensitive` lookup allocates but never touches is a 64-byte
/// stack value, not a cost worth a divergent call shape.
pub const FOLD_CAP: usize = 64;
/// ASCII-fold `s` into `buf`, returning the lowercase bytes, or [`None`]
/// when `s` is longer than any slug can be.
///
/// The lookup tables compare on the byte side — every `FromStr` in the
/// crate matches `b"slug"` literals — so the fold hands back the buffer
/// itself and never re-derives a `str` from it. That conversion would be
/// a second O(n) pass over bytes this function just wrote, to prove a
/// property no caller consumes.
///
/// The [`Case::Insensitive`] half of [`lookup`] — a `FromStr` body never
/// calls this directly; it declares its [`Case`] and lets [`lookup`]
/// choose. Allocation-free, so the lookup gate is the same at every
/// capability tier.
pub
/// The two case-matching strategies a household's parse table can
/// declare — the sealed per-household axis; see the module doc for the
/// full law.
///
/// Deliberately has **no [`Default`] impl**. That absence is the
/// enforcement mechanism: [`lookup`] takes a `Case` as a required
/// argument, so a household that does not name one does not compile,
/// rather than silently inheriting a crate-wide assumption.
pub
/// Resolve `s` to the byte key a household's `b"slug"` match table
/// compares against, under `case`'s strategy — the one call every
/// `FromStr` in this crate makes to reach its table, and the household's
/// declaration site for [`Case`].
///
/// [`Case::Insensitive`] folds through [`fold`], falling back to the
/// unfolded original past [`FOLD_CAP`] (an input that long cannot name a
/// variant either, so the fallback is still an ordinary miss, not a
/// panic). [`Case::Sensitive`] takes `s`'s own bytes verbatim: there is
/// nothing to fold, so `buf` goes unused on that path — every call site
/// still supplies one, so naming the [`Case`] is the *only* thing that
/// differs between a `FromStr` that folds and one that does not.
pub