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 = 8;
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/// One type path a rendered expression names.
151///
152/// # Bounds
153///
154/// The segments are structurally non-empty: a path naming no segment names nothing, and a rendering that wrote one would emit a bare separator.
155#[derive(Debug, Clone, PartialEq, Eq, Hash)]
156pub struct CodecTypePath {
157 rooting: PathRooting,
158 segments: NonEmpty<String, CODEC_PATH_SEGMENT_LIMIT>,
159}
160
161/// 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.
162///
163/// # Bounds
164///
165/// 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.
166#[derive(Debug, Clone, PartialEq, Eq, Hash)]
167pub struct CodecMember {
168 spelling: String,
169 held_as: CodecTypePath,
170 shape: CodecMemberShape,
171 cardinality: Cardinality,
172}
173
174/// What the decode road does with the members once it has read them all.
175///
176/// 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`.
177#[derive(Debug, Clone, PartialEq, Eq, Hash)]
178pub enum AssemblyPosture {
179 /// The road is total: every member the decode road read is an argument, and there is nothing left to refuse.
180 Total,
181 /// The road is checked, and this is the refusal it answers with.
182 Checked {
183 /// The refusal the assembly road answers with, carried into the rendered one by a conversion this home writes.
184 refusal: CodecTypePath,
185 },
186}
187
188/// The road one decoded value is assembled by, and the posture it stands under.
189///
190/// # Bounds
191///
192/// 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.
193#[derive(Debug, Clone, PartialEq, Eq, Hash)]
194pub struct CodecAssembly {
195 road: String,
196 posture: AssemblyPosture,
197}
198
199/// The complete declared shape one codec is rendered for.
200///
201/// # Bounds
202///
203/// 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.
204///
205/// 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.
206#[derive(Debug, Clone, PartialEq, Eq, Hash)]
207pub struct CodecShape {
208 owner: CodecTypePath,
209 refusal: String,
210 assembly: CodecAssembly,
211 members: NonEmpty<CodecMember, CODEC_MEMBER_LIMIT>,
212}
213
214/// The spelling one visibly published module is declared under.
215///
216/// # Bounds
217///
218/// One Rust identifier by construction: the module lands in the caller's own scope and shares a namespace with every other item there.
219#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
220pub struct ModuleSpelling {
221 spelling: String,
222}
223
224/// What shape the rendered surface lands in.
225///
226/// # Bounds
227///
228/// 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.
229#[derive(Debug, Clone, PartialEq, Eq, Hash)]
230pub enum CodecPlacement {
231 /// Spliced beside the owner's own item, in the scope the declaration sits in.
232 AtDeclarationSite,
233 /// Wrapped in a visibly published module, whose head imports the scope the module sits in.
234 PublishedModule {
235 /// The module's declared spelling.
236 spelling: ModuleSpelling,
237 },
238}
239
240/// What one codec request carries beyond its captured tokens.
241///
242/// # Nonclaims
243///
244/// 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.
245/// They travel so an explanation can name them and a caller can join the surface back to the declaration it answers to.
246#[derive(Debug, Clone, PartialEq, Eq, Hash)]
247pub struct CodecContent {
248 /// The declared shape the two roads are written over.
249 pub shape: CodecShape,
250 /// Which of the two roads the surface carries.
251 pub direction: CodecDirection,
252 /// The shape the rendered surface lands in.
253 pub placement: CodecPlacement,
254 /// The schema the codec is projected from, where the caller minted one.
255 pub schema: Option<OwnerIdentity>,
256 /// The byte role naming which bytes these are, where the caller minted one.
257 pub byte_role: Option<OwnerIdentity>,
258 /// The owner facts this projection assumes.
259 pub assumptions: Bounded<OwnerFact, ASSUMPTION_LIMIT>,
260}
261
262/// Projects a declared shape into the codec that reads and writes its canonical bytes.
263///
264/// 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.
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
266pub struct CodecProjection;
267
268/// How one declaration of this home's vocabulary refuses.
269///
270/// 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.
271#[derive(Debug, Clone, PartialEq, Eq, Hash)]
272pub enum CodecIssue {
273 /// A rendered type path names no segment, so it names nothing.
274 PathSegmentsAbsent,
275 /// 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.
276 SegmentNotAnIdentifier {
277 /// The segment as it was spelled.
278 segment: String,
279 },
280 /// A path carries more segments than the declared magnitude.
281 PathSegmentsUnbounded {
282 /// The declared bound.
283 bound: u64,
284 /// The observed count.
285 observed: u64,
286 },
287 /// A member states no spelling, so nothing names it in either road.
288 MemberSpellingAbsent,
289 /// A member's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
290 MemberSpellingNotAnIdentifier {
291 /// The spelling as it was stated.
292 spelling: String,
293 },
294 /// 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.
295 MemberSpellingDoubled {
296 /// The spelling two members share.
297 spelling: String,
298 },
299 /// 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.
300 MemberShadowsBinding {
301 /// The member that collided.
302 spelling: String,
303 /// The binding it collided with.
304 binding: &'static str,
305 },
306 /// An assembly road states no spelling.
307 AssemblyRoadAbsent,
308 /// An assembly road's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
309 AssemblyRoadNotAnIdentifier {
310 /// The spelling as it was stated.
311 spelling: String,
312 },
313 /// A rendered decode refusal's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
314 RefusalSpellingNotAnIdentifier {
315 /// The spelling as it was stated.
316 spelling: String,
317 },
318 /// A published module's spelling cannot name a rendered item: not one Rust identifier, or a keyword the language already took.
319 ModuleSpellingNotAnIdentifier {
320 /// The spelling as it was stated.
321 spelling: String,
322 },
323 /// A shape declares no member at all.
324 MembersAbsent,
325 /// A shape declares more members than the declared magnitude.
326 MembersUnbounded {
327 /// The declared bound.
328 bound: u64,
329 /// The observed count.
330 observed: u64,
331 },
332}
333
334/// How declaring a codec says no.
335///
336/// 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.
337#[must_use = "a codec refusal names the exact seat the declaration did not fill"]
338#[derive(Debug, Clone, PartialEq, Eq, Hash)]
339pub struct CodecError {
340 body: Capped<CodecIssue, CODEC_ISSUE_LIMIT>,
341}
342
343/// 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.
344pub use guard::{rendered_identifier, rendered_name};