macroonz_compiler/request/type_guard.rs
1//! The request home's invariant nucleus: the roads that build one request, state its optional seats, and walk it.
2//!
3//! Declared inside `types.rs` as its own child, so a request's seats are reachable here and nowhere else.
4//!
5//! What lands here is what is about an ACT rather than about a value.
6//! The walk is one function because the road is one road: a caller cannot arrive at a proof holding a rendering nobody planned, and cannot arrive at a binding holding an explanation answered over something else, because there is no seat between the steps to put a foreign value in.
7
8use super::super::{decide, explain};
9use super::{
10 CrateBinding, Door, Producer, RUST_DECLARATION_PROFILE, Request, Selection, Statements,
11};
12use crate::closure::Closure;
13use crate::diagnostic::{Diagnostic, Placement, Refused};
14use crate::expansion::Expansion;
15use crate::explanation::View;
16use crate::identity::{
17 self, Contract, Identity, OwnerFact, OwnerIdentity, Profile, Role, ServiceEntry, Transcript,
18};
19use crate::kind::{Kind, Question};
20use crate::plan::Plan;
21use crate::render::{Output, RenderError};
22use crate::token::CapturedInput;
23
24impl CrateBinding {
25 /// The crate a consumer reaches this compiler's expansions through, by the word that consumer writes on its own dependency list.
26 #[must_use]
27 pub const fn declared(spelling: &'static str) -> Self {
28 Self { spelling }
29 }
30
31 /// The word a path rendered through this binding opens with.
32 #[must_use]
33 pub const fn spelling(self) -> &'static str {
34 self.spelling
35 }
36}
37
38impl Door {
39 /// One door, by the five facts a consumer declares once.
40 ///
41 /// A `const`, so a consumer writes it down beside its derive and passes it by reference from then on.
42 #[must_use]
43 pub const fn declared(
44 prefix: &'static str,
45 grammar: &'static str,
46 entry: &'static str,
47 binding: CrateBinding,
48 producer: Producer,
49 ) -> Self {
50 Self {
51 prefix,
52 grammar,
53 entry,
54 binding,
55 producer,
56 }
57 }
58
59 /// The word every line composed through this door opens with.
60 #[must_use]
61 pub const fn prefix(&self) -> &'static str {
62 self.prefix
63 }
64
65 /// The declaration grammar every diagnostic through this door expected to hold.
66 ///
67 /// Derived over the declared name's own bytes, rooted at [`Role::DeclaredName`], at position zero — the seat this compiler assigns a door's grammar.
68 #[must_use]
69 pub fn grammar(&self) -> Identity<Contract> {
70 Identity::derived(Transcript::rooted(
71 Role::DeclaredName,
72 self.grammar.as_bytes(),
73 0,
74 ))
75 }
76
77 /// The callable entry point every diagnostic through this door reproduces at.
78 ///
79 /// Derived on [`Door::grammar`]'s terms, separated from it by its own subject and by its own content, at position one.
80 #[must_use]
81 pub fn entry(&self) -> Identity<ServiceEntry> {
82 Identity::derived(Transcript::rooted(
83 Role::DeclaredName,
84 self.entry.as_bytes(),
85 1,
86 ))
87 }
88
89 /// The crate a path rendered through this door is rooted at.
90 #[must_use]
91 pub const fn binding(&self) -> CrateBinding {
92 self.binding
93 }
94
95 /// Who is producing, for whatever this door's expansions are stamped into.
96 #[must_use]
97 pub const fn producer(&self) -> Producer {
98 self.producer
99 }
100}
101
102impl<'door, K: Kind> Request<'door, K> {
103 /// The request one captured declaration and one kind's content amount to.
104 ///
105 /// Everything else has a stated default: nothing is depended on, the profile is [`RUST_DECLARATION_PROFILE`], nothing is assumed, no seat publishes to an address, and the kind's own questions are unanswered.
106 /// A kind that declares questions or publishes to an address states those seats before rendering, or the road refuses at the step that needs them.
107 pub fn over(capture: CapturedInput, content: K::Content, door: &'door Door) -> Self {
108 Self {
109 capture,
110 content,
111 door,
112 dependencies: Vec::new(),
113 profile: RUST_DECLARATION_PROFILE,
114 assumptions: Vec::new(),
115 addresses: Vec::new(),
116 answers: Vec::new(),
117 selection: Selection::All,
118 }
119 }
120
121 /// Selects the structurally nonempty subset this request plans from the kind's complete role roster.
122 ///
123 /// The first role is separate so an empty selection cannot be stated.
124 /// Selection order does not carry meaning and is canonicalized by the kind's role roster before planning.
125 /// Foreign, doubled, and overlarge selections remain typed planning refusals under the existing membership owner.
126 /// Stating a selection again replaces the earlier statement.
127 pub fn selecting(mut self, first: K::Role, rest: Vec<K::Role>) -> Self {
128 self.selection = Selection::Declared { first, rest };
129 self
130 }
131
132 /// States the captures this content declares it stands on.
133 ///
134 /// The set is canonicalized where the account is built, so two callers declaring one set in two orders reach one plan.
135 pub fn depending_on(
136 mut self,
137 dependencies: Vec<Identity<identity::CapturedDeclaration>>,
138 ) -> Self {
139 self.dependencies = dependencies;
140 self
141 }
142
143 /// States the profile this request is decided under.
144 pub fn profile(mut self, profile: Profile) -> Self {
145 self.profile = profile;
146 self
147 }
148
149 /// States the owner facts this projection rests on.
150 ///
151 /// They are the assumptions the explanation answers with and the decisions the trace records, which is one statement read twice rather than two a caller could disagree with itself about.
152 pub fn assuming(mut self, assumptions: Vec<OwnerFact>) -> Self {
153 self.assumptions = assumptions;
154 self
155 }
156
157 /// States the address the unit under one seat is written to.
158 ///
159 /// Stating a seat's address twice keeps the last statement: an address is one fact about one seat, and two of them would leave the plan electing.
160 /// The seat must be one a publication act consumes — planning refuses an address on a seat that never publishes, so a stated address is never an inert claim riding the identities.
161 pub fn publishing_at(mut self, role: K::Role, address: OwnerIdentity) -> Self {
162 self.addresses.retain(|(seat, _)| *seat != role);
163 self.addresses.push((role, address));
164 self
165 }
166
167 /// States the answers to the questions the kind itself declares.
168 ///
169 /// The universal questions every kind owes are answered by this road; these are the kind's own.
170 pub fn answering(mut self, answers: Vec<<K::Question as Question>::Answer>) -> Self {
171 self.answers = answers;
172 self
173 }
174
175 /// Walk the road: plan, render, close, explain, bind.
176 ///
177 /// The renderer is called once, against the plan, and writes one unit per seat the plan declares.
178 /// Each step hands the next a value the next one cannot forge, so the order is not a convention a caller could take in another sequence.
179 ///
180 /// # Errors
181 ///
182 /// Returns one [`Diagnostic`], composed under this request's door, wherever any step refuses: the plan the kind's roster and the caller's seats amount to, the renderer's own refusal, the units it wrote, the proof that they close over the plan, the coverage of the questions the kind owes, or the binding of the three.
183 /// Every one of them happens before a token is reachable, because tokens are reachable only from the expansion this road returns.
184 pub fn render(
185 self,
186 renderer: impl FnOnce(&Plan<K>, &mut Output<'_, K>) -> Result<(), RenderError>,
187 ) -> Result<Expansion<K>, Diagnostic> {
188 let Self {
189 capture,
190 content,
191 door,
192 dependencies,
193 profile,
194 assumptions,
195 addresses,
196 answers,
197 selection,
198 } = self;
199 let statements = Statements::from_request(&assumptions, &addresses, &selection);
200 let plan =
201 decide::planned::<K>(&capture, content, door, dependencies, profile, &statements)
202 .map_err(|refusal| refused(&refusal, door))?;
203
204 let mut out = Output::over(&plan);
205 renderer(&plan, &mut out).map_err(|refusal| refused(&refusal, door))?;
206 let units = out.rendered().map_err(|refusal| refused(&refusal, door))?;
207
208 let closure = Closure::proved(&plan, units).map_err(|refusal| refused(&refusal, door))?;
209 let universal = explain::universal(door, &plan, &closure, &assumptions)
210 .map_err(|refusal| refused(&refusal, door))?;
211 let view = View::complete(&plan, &closure, universal, answers)
212 .map_err(|refusal| refused(&refusal, door))?;
213 Expansion::bound(plan, closure, view).map_err(|refusal| refused(&refusal, door))
214 }
215}
216
217/// The one projection this road makes: any step's own refusal, under this request's door, about the declaration as a whole.
218///
219/// The placement is never a token, and that is a claim rather than a shortcut: every refusal reachable here is established at or after planning, which is downstream of a capture that already succeeded, so there is no clause of the caller's grammar left to point at.
220fn refused<E: Refused>(refusal: &E, door: &Door) -> Diagnostic {
221 Diagnostic::refused(refusal, door, &Placement::WholeDeclaration)
222}