Skip to main content

macroonz_compiler/codec/
types.rs

1//! The codec home's declarations: the kind, the shape a codec is written for, the wire vocabulary its members stand under, where the surface lands, and how a declaration of any of it refuses.
2//!
3//! Declarations only.
4//! Every road that reaches a private field lives in `type_guard.rs`, this file's own child, which is what makes this home's walls structural: a shape is seated by one road that refuses an empty roster, a doubled spelling, and a spelling the decode road has already taken, and there is no second road that seats one.
5
6use crate::bounded::{Bounded, Capped, NonEmpty};
7use crate::explanation::ASSUMPTION_LIMIT;
8use crate::identity::{OwnerFact, OwnerIdentity};
9
10#[path = "type_guard.rs"]
11mod guard;
12
13/// Members one declared shape may carry.
14///
15/// Every member is one framed run in the encode road and one bound local in the decode road, so a shape past this has stopped being one value's spelling; the repair is a nested member carrying its own codec rather than a longer roster here.
16pub const CODEC_MEMBER_LIMIT: usize = 64;
17
18/// Segments one rendered type path may carry.
19///
20/// A path reaching deeper has stopped naming an item and started describing a tree, and the repair is a re-export at the address rather than a longer spelling at this end.
21pub const CODEC_PATH_SEGMENT_LIMIT: usize = crate::token::RENDERED_PATH_SEGMENT_LIMIT;
22
23/// Issues one codec refusal carries before it begins counting the rest.
24///
25/// One per member seat, because the widest pass asks one question of every declared member and every member can answer it at once — and a caller repairing a shape one member per attempt is a caller this home failed.
26pub const CODEC_ISSUE_LIMIT: usize = 64;
27
28/// The road a rendered surface writes one value's canonical bytes by, and the road a nested member's own type is billed for.
29pub const ENCODE_ROAD: &str = "encode_canonical";
30
31/// The road a rendered surface reads those bytes back by.
32pub const DECODE_ROAD: &str = "decode_canonical";
33
34/// The roster constant a closed choice's admitted arms are walked through.
35pub const ROSTER_CONSTANT: &str = "ALL";
36
37/// The road one arm of a closed roster answers its declared position through, one byte wide because a choice is written as one byte.
38pub const SLOT_ROAD: &str = "slot";
39
40crate::roster! {
41    /// How many of one member there are.
42    ///
43    /// Three rows and no fourth: the wire roads below stand over ONE occurrence whatever supplied it, so a cardinality decides how many times a road runs and never what the road writes.
44    pub enum Cardinality {
45        /// Exactly one, written where the shape declares it.
46        Required = "required",
47        /// One or none, written behind a presence byte.
48        Optional = "optional",
49        /// As many as the value holds, written behind a framed count.
50        Repeated = "repeated",
51    }
52}
53
54crate::roster! {
55    /// The wire shape one member is written under.
56    ///
57    /// Five rows, every one a shape the rendering can write end to end: there is no opaque arm, because a member the rendering could not write would be a member whose bytes nobody could re-read.
58    pub enum CodecMemberShape {
59        /// A count, carried at the framing width and narrowed back at the member's own type on the way in.
60        Count = "count",
61        /// Variable-length bytes, written length-prefixed.
62        Bytes = "bytes",
63        /// Variable-length text, written length-prefixed as its UTF-8 bytes and read back through a check that refuses.
64        Text = "text",
65        /// One arm of a closed roster, written as that arm's own declared position and read back by walking the roster the owner declared.
66        ClosedChoice = "closed-choice",
67        /// A nested value carrying its own codec, framed at its own length so the member after it stays readable.
68        Nested = "nested",
69    }
70}
71
72crate::roster! {
73    /// Which of the two roads a request covers.
74    pub enum CodecDirection {
75        /// Typed value to canonical bytes.
76        Encode = "encode",
77        /// Canonical bytes to typed value.
78        Decode = "decode",
79        /// Both, so neither can drift from the other.
80        RoundTrip = "round-trip",
81    }
82}
83
84crate::roster! {
85    /// Where one rendered type path is rooted.
86    ///
87    /// Four rows and none is a default: where a path is rooted is a claim about whose scope resolves it, and a rendering that guessed would put the wrong one in somebody else's crate.
88    /// The qualifier is typed here rather than smuggled as a first segment, so every segment stays an item step and the keyword roster holds on all of them.
89    pub enum PathRooting {
90        /// Rooted at the caller's own crate — rendered under the language's `crate` qualifier, so the path resolves the same wherever the surface lands.
91        CrateAbsolute = "crate-absolute",
92        /// Resolved in the scope the surface lands in, exactly as the caller spelled it.
93        InScope = "in-scope",
94        /// Rooted at the module the surface lands in, under the language's `self` qualifier.
95        SelfScoped = "self-scoped",
96        /// Rooted one module above the surface, under the language's `super` qualifier; a deeper reach is a re-export at the address rather than a longer qualifier run.
97        ParentScoped = "parent-scoped",
98    }
99}
100
101crate::roster! {
102    /// One arm of the decode refusal this home renders, by the spelling it is rendered under.
103    ///
104    /// The declared name is the arm's own Rust spelling, because this roster IS the rendered type's variant list.
105    /// Which arms name the member a read was standing at is said once, at `carries_member`.
106    pub enum DecodeRefusal {
107        /// The material ended inside a member.
108        Truncated = "Truncated",
109        /// A declared length runs past the material that remains.
110        LengthPastRemaining = "LengthPastRemaining",
111        /// A declared length does not fit an addressable width.
112        LengthPastAddressableWidth = "LengthPastAddressableWidth",
113        /// A declared count does not fit the width its member is held at.
114        CountPastDeclaredWidth = "CountPastDeclaredWidth",
115        /// Framed bytes that were to be text are not UTF-8.
116        TextNotUtf8 = "TextNotUtf8",
117        /// The member's own type refused what was read for it.
118        MemberNotAdmitted = "MemberNotAdmitted",
119        /// A slot names no arm of the roster it was declared over.
120        SlotNotAdmitted = "SlotNotAdmitted",
121        /// A nested codec refused the framed material.
122        NestedMemberRefused = "NestedMemberRefused",
123        /// A presence byte is neither of the two the encode road writes.
124        PresenceNotAdmitted = "PresenceNotAdmitted",
125        /// Material remains after the last declared member.
126        TrailingBytes = "TrailingBytes",
127        /// Every member was read and the road that assembles them refused.
128        NotAssembled = "NotAssembled",
129    }
130}
131
132/// One wire shape's bill: the roads the rendered surface calls on a member's own type.
133///
134/// A road named through a trait is written qualified, with `T` standing for the member's own type; a road named on that type itself is written bare.
135///
136/// # Authority
137///
138/// **The bill is stated and never worked around.**
139/// A member the rendering could not write end to end would be a member whose bytes nobody could re-read, so the rendering does not degrade: it calls the roads named here, and where one is absent the failure lands at the caller's site as an ordinary unresolved method.
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
141pub struct MemberContract {
142    /// The wire shape this row is about.
143    pub shape: CodecMemberShape,
144    /// The road the encode surface calls to read the member out.
145    pub encode_road: &'static str,
146    /// The road the decode surface calls to build the member back.
147    pub decode_road: &'static str,
148}
149
150/// The generated write operation one contract row selects.
151#[derive(Clone, Copy)]
152pub(super) enum WriteRoad {
153    /// Widen one count and write its big-endian bytes.
154    Count,
155    /// Borrow bytes through the declared trait road and frame them.
156    Bytes,
157    /// Borrow text through the declared trait road and frame its UTF-8 bytes.
158    Text,
159    /// Write the declared slot of one closed-choice arm.
160    ClosedChoice,
161    /// Call and frame one nested codec.
162    Nested,
163}
164
165/// The generated read operation one contract row selects.
166#[derive(Clone, Copy)]
167pub(super) enum ReadRoad {
168    /// Read and narrow one count.
169    Count,
170    /// Read framed bytes and ask the member type to admit them.
171    Bytes,
172    /// Read framed UTF-8 text and ask the member type to admit it.
173    Text,
174    /// Elect one arm from the owner's complete roster.
175    ClosedChoice,
176    /// Ask one nested codec to read its framed material.
177    Nested,
178}
179
180/// One authoritative contract row, with its public bill and the two internal operations that consume it.
181#[derive(Clone, Copy)]
182pub(super) struct RenderingContract {
183    /// The public statement of the member roads.
184    pub(super) bill: MemberContract,
185    /// The generated write operation.
186    pub(super) write: WriteRoad,
187    /// The generated read operation.
188    pub(super) read: ReadRoad,
189}
190
191/// One type path a rendered expression names.
192///
193/// # Bounds
194///
195/// The segments are structurally non-empty: a path naming no segment names nothing, and a rendering that wrote one would emit a bare separator.
196#[derive(Debug, Clone, PartialEq, Eq, Hash)]
197pub struct CodecTypePath {
198    rooting: PathRooting,
199    segments: NonEmpty<String, CODEC_PATH_SEGMENT_LIMIT>,
200}
201
202/// One member of a declared shape: what the owner calls it, the type it is held at, how it is written, and how many of it there are.
203///
204/// # Bounds
205///
206/// The spelling is one Rust identifier by construction, because the decode road binds a local under it and the encode road reads a field under it — and a spelling that is not one renders tokens the caller's compiler reads as something else.
207#[derive(Debug, Clone, PartialEq, Eq, Hash)]
208pub struct CodecMember {
209    spelling: String,
210    held_as: CodecTypePath,
211    shape: CodecMemberShape,
212    cardinality: Cardinality,
213}
214
215/// What the decode road does with the members once it has read them all.
216///
217/// Not an option and not a default: a total constructor and a checked one are called differently, and a rendering that guessed would either drop a refusal the owner declared or write a `?` on a value that is not a `Result`.
218#[derive(Debug, Clone, PartialEq, Eq, Hash)]
219pub enum AssemblyPosture {
220    /// The road is total: every member the decode road read is an argument, and there is nothing left to refuse.
221    Total,
222    /// The road is checked, and this is the refusal it answers with.
223    Checked {
224        /// The refusal the assembly road answers with, carried into the rendered one by a conversion this home writes.
225        refusal: CodecTypePath,
226    },
227}
228
229/// The road one decoded value is assembled by, and the posture it stands under.
230///
231/// # Bounds
232///
233/// The road is an associated road on the owner's own type, so a free function is unwritable here rather than refused: that is the shape a decode road can call without learning where the owner's module sits.
234#[derive(Debug, Clone, PartialEq, Eq, Hash)]
235pub struct CodecAssembly {
236    road: String,
237    posture: AssemblyPosture,
238}
239
240/// The complete declared shape one codec is rendered for.
241///
242/// # Bounds
243///
244/// The member set is structurally non-empty: a codec over no member writes no byte and reads none, so it could refuse for one reason and would admit every other input — and a codec that cannot refuse is not the validator this home says a codec is.
245///
246/// The rendered refusal's spelling is carried rather than derived, because it is a type declared in the caller's own scope and this home may not choose a name there.
247#[derive(Debug, Clone, PartialEq, Eq, Hash)]
248pub struct CodecShape {
249    owner: CodecTypePath,
250    refusal: String,
251    assembly: CodecAssembly,
252    members: NonEmpty<CodecMember, CODEC_MEMBER_LIMIT>,
253}
254
255/// The spelling one visibly published module is declared under.
256///
257/// # Bounds
258///
259/// One Rust identifier by construction: the module lands in the caller's own scope and shares a namespace with every other item there.
260#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
261pub struct ModuleSpelling {
262    spelling: String,
263}
264
265/// What shape the rendered surface lands in.
266///
267/// # Bounds
268///
269/// Both rows are declaration-site deliveries, so the delivery is the seat's constant answer under either and what this decides is the surface's shape alone.
270#[derive(Debug, Clone, PartialEq, Eq, Hash)]
271pub enum CodecPlacement {
272    /// Spliced beside the owner's own item, in the scope the declaration sits in.
273    AtDeclarationSite,
274    /// Wrapped in a visibly published module, whose head imports the scope the module sits in.
275    PublishedModule {
276        /// The module's declared spelling.
277        spelling: ModuleSpelling,
278    },
279}
280
281/// What one codec request carries beyond its captured tokens.
282///
283/// # Nonclaims
284///
285/// The schema and the byte role reach no token of the rendered surface: the schema is what the codec is projected FROM and the shape is what it is written FOR, and the framing is this home's whatever the bytes are called.
286/// They travel so an explanation can name them and a caller can join the surface back to the declaration it answers to.
287#[derive(Debug, Clone, PartialEq, Eq, Hash)]
288pub struct CodecContent {
289    /// The declared shape the two roads are written over.
290    pub shape: CodecShape,
291    /// Which of the two roads the surface carries.
292    pub direction: CodecDirection,
293    /// The shape the rendered surface lands in.
294    pub placement: CodecPlacement,
295    /// The schema the codec is projected from, where the caller minted one.
296    pub schema: Option<OwnerIdentity>,
297    /// The byte role naming which bytes these are, where the caller minted one.
298    pub byte_role: Option<OwnerIdentity>,
299    /// The owner facts this projection assumes.
300    pub assumptions: Bounded<OwnerFact, ASSUMPTION_LIMIT>,
301}
302
303/// Projects a declared shape into the codec that reads and writes its canonical bytes.
304///
305/// One rendered unit, at the declaration site: the surface is Rust the caller's normal build compiles, whether it is spliced beside the owner's item or wrapped in a published module.
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
307pub struct CodecProjection;
308
309/// How one declaration of this home's vocabulary refuses.
310///
311/// No row is payload-free where a payload would tell a caller what to repair: a row names the spelling it refused at, or the two counts a magnitude was passed by.
312#[derive(Debug, Clone, PartialEq, Eq, Hash)]
313pub enum CodecIssue {
314    /// A rendered type path names no segment, so it names nothing.
315    PathSegmentsAbsent,
316    /// A path segment cannot name a rendered item — not one Rust identifier, or a keyword the language already took — so the rendering would write tokens the caller's compiler reads as something else.
317    SegmentNotAnIdentifier {
318        /// The segment as it was spelled.
319        segment: String,
320    },
321    /// A path carries more segments than the declared magnitude.
322    PathSegmentsUnbounded {
323        /// The declared bound.
324        bound: u64,
325        /// The observed count.
326        observed: u64,
327    },
328    /// A member states no spelling, so nothing names it in either road.
329    MemberSpellingAbsent,
330    /// A member's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
331    MemberSpellingNotAnIdentifier {
332        /// The spelling as it was stated.
333        spelling: String,
334    },
335    /// Two members of one shape carry one spelling, so the decode road would bind one local twice and the assembly would be handed the second.
336    MemberSpellingDoubled {
337        /// The spelling two members share.
338        spelling: String,
339    },
340    /// A member's spelling is one of the locals the decode road declares for itself, so the member's binding would shadow the rendering's and the road would go on reading a value nobody meant.
341    MemberShadowsBinding {
342        /// The member that collided.
343        spelling: String,
344        /// The binding it collided with.
345        binding: &'static str,
346    },
347    /// An assembly road states no spelling.
348    AssemblyRoadAbsent,
349    /// An assembly road's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
350    AssemblyRoadNotAnIdentifier {
351        /// The spelling as it was stated.
352        spelling: String,
353    },
354    /// A rendered decode refusal's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
355    RefusalSpellingNotAnIdentifier {
356        /// The spelling as it was stated.
357        spelling: String,
358    },
359    /// A published module's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
360    ModuleSpellingNotAnIdentifier {
361        /// The spelling as it was stated.
362        spelling: String,
363    },
364    /// A shape declares no member at all.
365    MembersAbsent,
366    /// A shape declares more members than the declared magnitude.
367    MembersUnbounded {
368        /// The declared bound.
369        bound: u64,
370        /// The observed count.
371        observed: u64,
372    },
373}
374
375/// How declaring a codec says no.
376///
377/// The passes that reach it are dependent in a stated order, so exactly one cause is true of a refused path, spelling, or road — while the pass over a shape's members co-establishes freely, because a caller told about one colliding member and not the next is a caller who repairs a shape one attempt at a time.
378#[must_use = "a codec refusal names the exact seat the declaration did not fill"]
379#[derive(Debug, Clone, PartialEq, Eq, Hash)]
380pub struct CodecError {
381    body: Capped<CodecIssue, CODEC_ISSUE_LIMIT>,
382}
383
384/// The one alphabet every spelling this home renders as a Rust identifier is admitted by, published from the nucleus every road here already reads it through.
385pub use guard::{rendered_identifier, rendered_name};