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::{
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}