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::{CrateBinding, Door, Producer, RUST_DECLARATION_PROFILE, Request};
10use crate::closure::Closure;
11use crate::diagnostic::{Diagnostic, Placement, Refused};
12use crate::expansion::Expansion;
13use crate::explanation::View;
14use crate::identity::{
15 self, Contract, Identity, OwnerFact, OwnerIdentity, Profile, Role, ServiceEntry, Transcript,
16};
17use crate::kind::{Kind, Question};
18use crate::plan::Plan;
19use crate::render::{Output, RenderError};
20use crate::token::CapturedInput;
21
22impl CrateBinding {
23 /// The crate a consumer reaches this compiler's expansions through, by the word that consumer writes on its own dependency list.
24 #[must_use]
25 pub const fn declared(spelling: &'static str) -> Self {
26 Self { spelling }
27 }
28
29 /// The word a path rendered through this binding opens with.
30 #[must_use]
31 pub const fn spelling(self) -> &'static str {
32 self.spelling
33 }
34}
35
36impl Door {
37 /// One door, by the five facts a consumer declares once.
38 ///
39 /// A `const`, so a consumer writes it down beside its derive and passes it by reference from then on.
40 #[must_use]
41 pub const fn declared(
42 prefix: &'static str,
43 grammar: &'static str,
44 entry: &'static str,
45 binding: CrateBinding,
46 producer: Producer,
47 ) -> Self {
48 Self {
49 prefix,
50 grammar,
51 entry,
52 binding,
53 producer,
54 }
55 }
56
57 /// The word every line composed through this door opens with.
58 #[must_use]
59 pub const fn prefix(&self) -> &'static str {
60 self.prefix
61 }
62
63 /// The declaration grammar every diagnostic through this door expected to hold.
64 ///
65 /// Derived over the declared name's own bytes, rooted at [`Role::DeclaredName`], at position zero — the seat this compiler assigns a door's grammar.
66 #[must_use]
67 pub fn grammar(&self) -> Identity<Contract> {
68 Identity::derived(Transcript::rooted(
69 Role::DeclaredName,
70 self.grammar.as_bytes(),
71 0,
72 ))
73 }
74
75 /// The callable entry point every diagnostic through this door reproduces at.
76 ///
77 /// Derived on [`Door::grammar`]'s terms, separated from it by its own subject and by its own content, at position one.
78 #[must_use]
79 pub fn entry(&self) -> Identity<ServiceEntry> {
80 Identity::derived(Transcript::rooted(
81 Role::DeclaredName,
82 self.entry.as_bytes(),
83 1,
84 ))
85 }
86
87 /// The crate a path rendered through this door is rooted at.
88 #[must_use]
89 pub const fn binding(&self) -> CrateBinding {
90 self.binding
91 }
92
93 /// Who is producing, for whatever this door's expansions are stamped into.
94 #[must_use]
95 pub const fn producer(&self) -> Producer {
96 self.producer
97 }
98}
99
100impl<'door, K: Kind> Request<'door, K> {
101 /// The request one captured declaration and one kind's content amount to.
102 ///
103 /// 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.
104 /// 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.
105 pub fn over(capture: CapturedInput, content: K::Content, door: &'door Door) -> Self {
106 Self {
107 capture,
108 content,
109 door,
110 dependencies: Vec::new(),
111 profile: RUST_DECLARATION_PROFILE,
112 assumptions: Vec::new(),
113 addresses: Vec::new(),
114 answers: Vec::new(),
115 }
116 }
117
118 /// States the captures this content declares it stands on.
119 ///
120 /// The set is canonicalized where the account is built, so two callers declaring one set in two orders reach one plan.
121 pub fn depending_on(
122 mut self,
123 dependencies: Vec<Identity<identity::CapturedDeclaration>>,
124 ) -> Self {
125 self.dependencies = dependencies;
126 self
127 }
128
129 /// States the profile this request is decided under.
130 pub fn profile(mut self, profile: Profile) -> Self {
131 self.profile = profile;
132 self
133 }
134
135 /// States the owner facts this projection rests on.
136 ///
137 /// 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.
138 pub fn assuming(mut self, assumptions: Vec<OwnerFact>) -> Self {
139 self.assumptions = assumptions;
140 self
141 }
142
143 /// States the address the unit under one seat is written to.
144 ///
145 /// 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.
146 /// 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.
147 pub fn publishing_at(mut self, role: K::Role, address: OwnerIdentity) -> Self {
148 self.addresses.retain(|(seat, _)| *seat != role);
149 self.addresses.push((role, address));
150 self
151 }
152
153 /// States the answers to the questions the kind itself declares.
154 ///
155 /// The universal questions every kind owes are answered by this road; these are the kind's own.
156 pub fn answering(mut self, answers: Vec<<K::Question as Question>::Answer>) -> Self {
157 self.answers = answers;
158 self
159 }
160
161 /// Walk the road: plan, render, close, explain, bind.
162 ///
163 /// The renderer is called once, against the plan, and writes one unit per seat the plan declares.
164 /// 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.
165 ///
166 /// # Errors
167 ///
168 /// 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.
169 /// Every one of them happens before a token is reachable, because tokens are reachable only from the expansion this road returns.
170 pub fn render(
171 self,
172 renderer: impl FnOnce(&Plan<K>, &mut Output<'_, K>) -> Result<(), RenderError>,
173 ) -> Result<Expansion<K>, Diagnostic> {
174 let Self {
175 capture,
176 content,
177 door,
178 dependencies,
179 profile,
180 assumptions,
181 addresses,
182 answers,
183 } = self;
184 let plan = decide::planned::<K>(
185 &capture,
186 content,
187 door,
188 dependencies,
189 profile,
190 &assumptions,
191 &addresses,
192 )
193 .map_err(|refusal| refused(&refusal, door))?;
194
195 let mut out = Output::over(&plan);
196 renderer(&plan, &mut out).map_err(|refusal| refused(&refusal, door))?;
197 let units = out.rendered().map_err(|refusal| refused(&refusal, door))?;
198
199 let closure = Closure::proved(&plan, units).map_err(|refusal| refused(&refusal, door))?;
200 let universal = explain::universal(door, &plan, &closure, &assumptions)
201 .map_err(|refusal| refused(&refusal, door))?;
202 let view = View::complete(&plan, &closure, universal, answers)
203 .map_err(|refusal| refused(&refusal, door))?;
204 Expansion::bound(plan, closure, view).map_err(|refusal| refused(&refusal, door))
205 }
206}
207
208/// The one projection this road makes: any step's own refusal, under this request's door, about the declaration as a whole.
209///
210/// 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.
211fn refused<E: Refused>(refusal: &E, door: &Door) -> Diagnostic {
212 Diagnostic::refused(refusal, door, &Placement::WholeDeclaration)
213}