[ClosedSet] — the typed witness for the closed-set-enum idiom.
The substrate carries 36+ closed-set enums (AtomKind,
QuoteForm, SexpShape, MacroDefHead, UnquoteForm,
KwargPathKind, ExpectedKwargShape, CompilerSpecIoStage in
this crate; ProcessPhase, ConditionKind, IntentKind,
LifetimeKind, TeardownPolicy, ProcessSignal,
ArtifactKind, ReportFormat, ChannelKind, ExportTrigger,
ReceiptKind, RequestorKind, SelectStrategyKind,
EncapsulationMode, EncapsulationTarget, DataClassification,
AllocationPhase, CalmClassification, OptimizationDirection,
HorizonKind, SubstrateType, ConvergencePointType,
MemberState, PoolPhase,
ReplacementPolicy, ReturnPolicy, AutoTerminateKind,
TerminateReasonKind,
VerificationPhase, WorkloadKind, MustReachPhase,
SighupStrategy, BreatheDimensionKind, MatrixTarget,
ReportPayloadShape, … in tatara-process). Each one independently
re-derives the same four-piece shape:
pub const ALL: [Self; N] = [...]— the forced-arity array literal that fails compilation if a new variant lands without being added to the set.fn label(self) -> &'static str(or its domain-canonical sibling —prefix,marker,keyword,as_str) — the typed projection from variant to the canonical&'static strliteral the diagnostic / wire format uses.impl FromStrwhose body is a linear sweep overSelf::ALLkeyed on the projection — exactly the same 6-line for-loop /Err(Unknown<TypeName>(s.to_owned()))shape every implementor re-derives byte-for-byte.pub struct Unknown<TypeName>(pub String)with#[error("unknown <thing>: {0}")]— the typed parse-rejection carrier that hands the offending input back unchanged.
Pieces 1, 2, 4 carry per-variant content (the variants themselves, their canonical labels, the rejection-class wording) and stay per-implementor. Piece 3 — the for-loop sweep — is mechanically identical across every implementor and is the duplication this trait lifts.
Trait surface
pub trait ClosedSet: Sized + Copy {
const ALL: &'static [Self];
type Unknown;
fn label(self) -> &'static str;
fn make_unknown(s: &str) -> Self::Unknown;
// Default — the lifted for-loop body.
fn parse_label(s: &str) -> Result<Self, Self::Unknown> { ... }
}
A typical implementor wires in three lines beyond its existing
inherent surface, and its hand-rolled FromStr body collapses
from six lines to one:
impl ClosedSet for AtomKind {
const ALL: &'static [Self] = &Self::ALL;
type Unknown = UnknownAtomKind;
fn label(self) -> &'static str { AtomKind::label(self) }
fn make_unknown(s: &str) -> Self::Unknown { UnknownAtomKind(s.to_owned()) }
}
impl FromStr for AtomKind {
type Err = UnknownAtomKind;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
<Self as ClosedSet>::parse_label(s)
}
}
Implementors with a non-label inherent projection name
(QuoteForm::prefix, UnquoteForm::marker, MacroDefHead::keyword,
tatara_process's *::as_str) delegate ClosedSet::label to
their domain-canonical method — the trait method gives every
implementor a STABLE name (label), with the inherent name kept as
the load-bearing domain-vocabulary projection (prefix for
homoiconic reader-form, marker for template-substitution
punctuation, keyword for macro-head reserved word, as_str for
tatara-process's PascalCase wire format).
Theory grounding
THEORY.md §V.1 — knowable platform; the for-loop / Unknown-
emission pattern was a known idiom carried by convention across 36+
implementors. This trait makes the idiom a TYPED WITNESS — any new
closed-set enum that implements ClosedSet plugs into the trait's
default parse_label and a future generic consumer (a metrics
tagger, a Lisp keyword completer, an iac-forge canonical-form
renderer over closed-set kinds) can take a T: ClosedSet
parameter and walk the set without knowing which crate it lives in.
THEORY.md §VI.1 — generation over composition; the trait IS the generative shape. New closed-set enums add the trait impl + the one-line FromStr delegation instead of re-deriving the for-loop body, and the parse-rejection diagnostic surface narrows from "36+ independent sweeps that must each be kept symmetric" to "one default body, 36+ impls of a four-method contract."
Provenance
This crate is pleme-io/tatara's tatara-lisp/src/closed_set.rs moved
verbatim, per theory/TATARA-LISP-CONSOLIDATION.md phase 2 step 1.
tatara-lisp neither carries nor re-exports ClosedSet: that is the
property that keeps the published tatara-lisp small enough for the
phase-3 facade, and it is enforced structurally — this crate depends on
tatara-lisp (for the one shared domain::suggest metric), so the
reverse edge would be a cargo dependency cycle and cannot be written.
The trait body is byte-identical to its pre-split form apart from
crate::domain::suggest → tatara_lisp::domain::suggest and the
doc-links that pointed at sibling modules which stayed in tatara-lisp.
Nothing about the wire surface (label / parse_label / the
"unknown {SET_LABEL}: {input}" carrier rendering) was reshaped — the
implementors serialize Kubernetes CRD state through it.