canon_codec library

Classes

Codec<T>
A strict, bidirectional codec for a single string token. decode returns null when the token is not valid for this codec — that null is what lets the caller fall through (URL match fallthrough, or best-effort restore). encode is the exact inverse for any value the codec can produce, so a value round-trips to the same canonical token.
CompositeCodec
A composite codec (see Codec.composite); const-constructible. Components are individual fields — a const constructor can't build a list — so the signature itself caps the arity at 16. The value is a positional RECORD of the components' decoded values: a record's runtime type comes from its fields' runtime types, so a 2-part composite of string codecs decodes to a value that IS a (String, String) — typed casts and structural equality (repeat-collapse, prefix reuse) work as if it were declared that shape.
CompositeId
See IdNode.compose. Component nodes are individual fields — a const constructor can't build a list — so the signature itself caps the arity at 16 (à la Object.hash); generators read the n* fields directly.
ConcatCodec
An ordered sequence of codecs occupying ONE path segment: exactly one VARIABLE member (carries the value) framed by LiteralCodec members (fixed text). Invertible because the literals anchor the boundaries — decode strips the leading/trailing literals, delegates the remainder to the variable. A second variable has no recoverable boundary, so it is rejected.
CsvCodec<T>
Comma-joined list in a single token (see Codec.csv); const-constructible. A normal scalar codec — no repeated-key protocol.
IdNode
The contract an @ids enum wears: every row carries a codec. The node IS a Codec (it delegates to its inner one), so a screen can bind it straight into a Codec? id field (id: .user) and a store can key by it — the SAME node across both grammar trees. Generators read node.codec to recover the value type (the node itself erases to Codec<Object?>).
IDs
Marks the HAND-WRITTEN enum that is an app's id-space: each row is an identity carrying its Codec — how its key serialises in a URL. Nothing is generated; the enum IS the holder. Other grammar trees (canon's @screens, ledger's @stores) reference these rows by dot-shorthand and read row.codec to encode/decode and to validate a screen id or a store key against them.
ListCodec<T>
The repeated-key list carrier. Its element codec is read by URL machinery (a list key decodes element-wise from repeated keys, never as one token).
LiteralCodec
A fixed-token codec (Codec.literal). Exposed so link-tree assembly can detect literal branches (e.g. to order an injected id codec after them).
Record2Codec<A, B>
A 2-field record codec (see Codec.record2); const so it works as an enum-constant id, e.g. Record2Codec(Codec.string, Codec.integer).
Record3Codec<A, B, C>
A 3-field record codec (see Codec.record3); const-constructible.
UnionCodec<T>
The flattened branches of an a | b | c union. Decode tries them left-to- right (first non-null wins); encode uses the left/canonical branch. The nav/link layer reads branches to recover the ordered union the spec wrote.

Mixins

NameableCodec<T>
Adds (#name) to a codec, overriding a generated field name at the use site (slot(.uuid(#productId))). The returned codec drops the mixin, so a name can be applied at most once. Battery codecs mix this in; custom codecs may.

Extensions

CodecConcat on Codec<Object?>
+ is ORDERED concatenation within one segment — the string forms of the members joined in order (Ids.image + Codec.literal('_thumb'){imageId}_thumb). Non-commutative on purpose (prefix ≠ suffix), unlike the commutative |. Exactly one member carries a value; literals frame it.
CodecUnion on Codec<T>
a | b — a union: either token addresses the same T. Decode tries the branches left-to-right (strict codecs return null on a non-match, so the first that accepts the token wins); encode delegates to the left branch (the canonical form). The nav/link generator reads the branches structurally; this runtime form lets a spec written with | compile and round-trip. An extension, not an interface member, so existing implements Codec classes are unaffected.