Skip to main content

macroonz_compiler/identity/
type_contract.rs

1//! The constant answers the identity home's two closed rosters settle.
2//!
3//! A role's declared name, its published slot, the sentence it reads as, and the grammar it stands in are four tables over one roster; an anchoring's discriminant and its commitment are two over the other.
4//! Each is total, so a row admitted later stops the compiler in every table until somebody says what that row's name, slot, sentence, and grammar are — a role with no grammar and a role with no slot are both unrepresentable rather than defaulted.
5//!
6//! Nothing here is computed, and nothing here reaches a private field.
7
8use super::{
9    Anchoring, BUNDLE_PROFILE, CAPTURED_DECLARATION_PROFILE, CAPTURED_HELPER_PROFILE,
10    CLOSED_EXPANSION_PROFILE, CLOSURE_PROFILE, DECLARATION_DOCUMENTATION_PROFILE,
11    DECLARED_NAME_PROFILE, DIAGNOSTIC_RELATION_PROFILE, EXPLANATION_PROFILE,
12    GENERATED_UNIT_PROFILE, GENERATOR_VERSION_PROFILE, ORIGIN_NODE_PROFILE, PLAN_PROFILE,
13    PROJECTION_CONTENT_PROFILE, PROJECTION_INTENT_PROFILE, PROJECTION_KIND_PROFILE, Profile,
14    RENDERED_UNIT_PROFILE, Role,
15};
16
17impl Role {
18    /// The complete roster, in slot order.
19    pub const ALL: &'static [Self] = &[
20        Self::CapturedDeclaration,
21        Self::Plan,
22        Self::OriginNode,
23        Self::GeneratedUnit,
24        Self::RenderedUnit,
25        Self::OutputBytes,
26        Self::Bundle,
27        Self::Closure,
28        Self::ClosedExpansion,
29        Self::ProjectionIntent,
30        Self::Explanation,
31        Self::DeclarationDocumentation,
32        Self::DeclaredName,
33        Self::GeneratorVersion,
34        Self::DiagnosticRelation,
35        Self::CapturedHelper,
36        Self::ProjectionContent,
37        Self::ProjectionKind,
38    ];
39
40    /// The role's declared segment of the derive-key context.
41    ///
42    /// Declared rather than taken from the Rust spelling, for the reason [a subject's name](super::Subject::NAME) is: changing one of these literals renames every identity ever derived at that seat.
43    #[must_use]
44    pub const fn name(self) -> &'static str {
45        match self {
46            Self::CapturedDeclaration => "captured-declaration",
47            Self::Plan => "plan",
48            Self::OriginNode => "origin-node",
49            Self::GeneratedUnit => "generated-unit",
50            Self::RenderedUnit => "rendered-unit",
51            Self::OutputBytes => "output-bytes",
52            Self::Bundle => "bundle",
53            Self::Closure => "closure",
54            Self::ClosedExpansion => "closed-expansion",
55            Self::ProjectionIntent => "projection-intent",
56            Self::Explanation => "explanation",
57            Self::DeclarationDocumentation => "declaration-documentation",
58            Self::DeclaredName => "declared-name",
59            Self::GeneratorVersion => "generator-version",
60            Self::DiagnosticRelation => "diagnostic-relation",
61            Self::CapturedHelper => "captured-helper",
62            Self::ProjectionContent => "projection-content",
63            Self::ProjectionKind => "projection-kind",
64        }
65    }
66
67    /// The published byte member six of every transcript carries for this role.
68    #[must_use]
69    pub const fn slot(self) -> u8 {
70        match self {
71            Self::CapturedDeclaration => 0,
72            Self::Plan => 1,
73            Self::OriginNode => 2,
74            Self::GeneratedUnit => 3,
75            Self::RenderedUnit => 4,
76            Self::OutputBytes => 5,
77            Self::Bundle => 6,
78            Self::Closure => 7,
79            Self::ClosedExpansion => 8,
80            Self::ProjectionIntent => 9,
81            Self::Explanation => 10,
82            Self::DeclarationDocumentation => 11,
83            Self::DeclaredName => 12,
84            Self::GeneratorVersion => 13,
85            Self::DiagnosticRelation => 14,
86            Self::CapturedHelper => 15,
87            Self::ProjectionContent => 16,
88            Self::ProjectionKind => 17,
89        }
90    }
91
92    /// The seat rendered for a person. A projection: nothing reads it back.
93    #[must_use]
94    pub const fn described(self) -> &'static str {
95        match self {
96            Self::CapturedDeclaration => "the token material one expansion was handed",
97            Self::Plan => "one projection plan",
98            Self::OriginNode => "one node of the origin graph",
99            Self::GeneratedUnit => "one generated unit a plan declares it will materialize",
100            Self::RenderedUnit => "one rendered unit a renderer actually materialized",
101            Self::OutputBytes => "the canonical bytes of one rendered unit",
102            Self::Bundle => "one bundle materialized across a single publication boundary",
103            Self::Closure => "one proved closure between a plan and its rendering",
104            Self::ClosedExpansion => "one closed expansion",
105            Self::ProjectionIntent => "one projection intent, ahead of anything decided about it",
106            Self::Explanation => "one explanation answered over a plan and its closure",
107            Self::DeclarationDocumentation => {
108                "the documentation rows one captured declaration carries"
109            }
110            Self::DeclaredName => "one stable name this compiler wrote down",
111            Self::GeneratorVersion => "the generator's declared name and its shape position",
112            Self::DiagnosticRelation => {
113                "one refusal body or one established issue a diagnostic points at"
114            }
115            Self::CapturedHelper => "one helper attribute's material, read beside a declaration",
116            Self::ProjectionContent => "one kind-specific content commitment",
117            Self::ProjectionKind => "one owner-qualified projection kind",
118        }
119    }
120
121    /// The preimage grammar a transcript at this role stands in.
122    ///
123    /// Total, and the ONE road from a mint site to a version ladder: a call site names the seat it is deriving for, and the grammar follows rather than being passed alongside it.
124    /// A road that took both would admit a rendered unit derived under the plan grammar's position, which is a disagreement no reader of the resulting bytes could see.
125    ///
126    /// # Bounds
127    ///
128    /// Total and never injective.
129    /// Two seats standing over ONE grammar answer with one profile and are separated inside it by the role, which is a member of the transcript and a segment of the context: [`Role::RenderedUnit`] names a rendered unit and [`Role::OutputBytes`] names the digest of exactly that unit's bytes, so both read here to [`RENDERED_UNIT_PROFILE`].
130    ///
131    /// Nothing reads back: a grammar names no role, because a grammar is a preimage several seats may stand over and a role is one seat inside it.
132    #[must_use]
133    pub const fn profile(self) -> Profile {
134        match self {
135            Self::CapturedDeclaration => CAPTURED_DECLARATION_PROFILE,
136            Self::Plan => PLAN_PROFILE,
137            Self::OriginNode => ORIGIN_NODE_PROFILE,
138            Self::GeneratedUnit => GENERATED_UNIT_PROFILE,
139            Self::RenderedUnit | Self::OutputBytes => RENDERED_UNIT_PROFILE,
140            Self::Bundle => BUNDLE_PROFILE,
141            Self::Closure => CLOSURE_PROFILE,
142            Self::ClosedExpansion => CLOSED_EXPANSION_PROFILE,
143            Self::ProjectionIntent => PROJECTION_INTENT_PROFILE,
144            Self::Explanation => EXPLANATION_PROFILE,
145            Self::DeclarationDocumentation => DECLARATION_DOCUMENTATION_PROFILE,
146            Self::DeclaredName => DECLARED_NAME_PROFILE,
147            Self::GeneratorVersion => GENERATOR_VERSION_PROFILE,
148            Self::DiagnosticRelation => DIAGNOSTIC_RELATION_PROFILE,
149            Self::CapturedHelper => CAPTURED_HELPER_PROFILE,
150            Self::ProjectionContent => PROJECTION_CONTENT_PROFILE,
151            Self::ProjectionKind => PROJECTION_KIND_PROFILE,
152        }
153    }
154}
155
156const _: () = assert!(
157    slots_are_ordered(Role::ALL, 0),
158    "a role whose published slot disagrees with its position in the roster",
159);
160
161/// Whether every row's published slot is its own position in the roster.
162///
163/// The slot is what a transcript carries, and the roster order is what a reader walks; two rows at one slot would derive one identity for two seats.
164const fn slots_are_ordered(roles: &[Role], at: u8) -> bool {
165    match roles.split_first() {
166        None => true,
167        Some((first, rest)) => first.slot() == at && slots_are_ordered(rest, at.saturating_add(1)),
168    }
169}
170
171impl Anchoring {
172    /// The discriminant byte member seven of every transcript carries for this posture.
173    #[must_use]
174    pub const fn slot(self) -> u8 {
175        match self {
176            Self::Rooted => 0,
177            Self::UnderOwner(_) => 1,
178            Self::UnderProjection(_) => 2,
179        }
180    }
181
182    /// The anchor commitment at full width, where there is one.
183    #[must_use]
184    pub const fn commitment(&self) -> Option<&[u8; 32]> {
185        match self {
186            Self::Rooted => None,
187            Self::UnderOwner(anchor) | Self::UnderProjection(anchor) => Some(anchor),
188        }
189    }
190}