Skip to main content

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}