Skip to main content

macroonz_compiler/recipe/
type_guard.rs

1//! Projection capabilities and baked-recipe readback.
2
3use super::{
4    EffectiveProjection, LoweringSource, ProjectionError, ProjectionOffered, ProjectionRequest,
5    ProjectionSink, ProjectorReplacement, RELATION_TABLE_LIMIT, Recipe, RecipeBake,
6    RecipeProjection, RecipeRole, RecipeShell, RecipeShellContent, RecipeView,
7    RelationTableProjection,
8};
9use crate::bounded::Bounded;
10use crate::expansion::Expansion;
11use crate::kind::Role;
12use crate::render::Output;
13use crate::token::{GeneratedTree, SpanHandle};
14
15impl EffectiveProjection {
16    pub(in crate::recipe) fn effective(
17        role: RecipeRole,
18        name: Option<String>,
19        subject: Option<String>,
20        source: LoweringSource,
21        at: SpanHandle,
22    ) -> Self {
23        Self {
24            role,
25            name,
26            subject,
27            source,
28            exact_rust: None,
29            exact_dispatch_bindings: None,
30            exact_dispatch_binding_names: None,
31            exact_dispatch_imports: None,
32            relation_tables: None,
33            at,
34        }
35    }
36
37    pub(in crate::recipe) fn exact_dispatch(
38        name: String,
39        exact_rust: GeneratedTree,
40        bindings: [crate::token::GeneratedToken; 2],
41        binding_names: [String; 2],
42        imports: [bool; 2],
43        at: SpanHandle,
44    ) -> Self {
45        Self {
46            role: RecipeRole::Dispatch,
47            name: Some(name),
48            subject: None,
49            source: LoweringSource::ExactRust,
50            exact_rust: Some(exact_rust),
51            exact_dispatch_bindings: Some(bindings),
52            exact_dispatch_binding_names: Some(Box::new(binding_names)),
53            exact_dispatch_imports: Some(imports),
54            relation_tables: None,
55            at,
56        }
57    }
58
59    pub(in crate::recipe) fn with_relation_tables(
60        tables: Bounded<RelationTableProjection, RELATION_TABLE_LIMIT>,
61        at: SpanHandle,
62    ) -> Self {
63        Self {
64            role: RecipeRole::RelationTables,
65            name: None,
66            subject: None,
67            source: LoweringSource::Configuration,
68            exact_rust: None,
69            exact_dispatch_bindings: None,
70            exact_dispatch_binding_names: None,
71            exact_dispatch_imports: None,
72            relation_tables: Some(Box::new(tables)),
73            at,
74        }
75    }
76
77    /// Reads the selected role.
78    #[must_use]
79    pub const fn role(&self) -> RecipeRole {
80        self.role
81    }
82
83    /// Reads the effective public spelling where this role declares one.
84    #[must_use]
85    pub fn name(&self) -> Option<&str> {
86        self.name.as_deref()
87    }
88
89    /// Reads the informed structural subject selected for this projection.
90    #[must_use]
91    pub fn subject(&self) -> Option<&str> {
92        self.subject.as_deref()
93    }
94
95    pub(in crate::recipe) fn select_subject(&mut self, subject: String) {
96        self.subject = Some(subject);
97    }
98
99    /// Reads where the effective value came from.
100    #[must_use]
101    pub const fn source(&self) -> LoweringSource {
102        self.source
103    }
104
105    /// Reads the exact caller-authored Rust that replaced this mechanical seat.
106    #[must_use]
107    pub const fn exact_rust(&self) -> Option<&GeneratedTree> {
108        self.exact_rust.as_ref()
109    }
110
111    /// Reads the exact state and event binding tokens selected for an exact dispatch body.
112    #[must_use]
113    pub const fn dispatch_binding_tokens(&self) -> Option<&[crate::token::GeneratedToken; 2]> {
114        self.exact_dispatch_bindings.as_ref()
115    }
116
117    /// Reads the state and event parameter bindings selected for an exact dispatch body.
118    #[must_use]
119    pub fn dispatch_bindings(&self) -> Option<[&str; 2]> {
120        self.exact_dispatch_binding_names
121            .as_deref()
122            .map(|[state, event]| [state.as_str(), event.as_str()])
123    }
124
125    /// Reads whether an exact dispatch signature requires each transition vocabulary in scope.
126    #[must_use]
127    pub const fn dispatch_subject_imports(&self) -> Option<[bool; 2]> {
128        self.exact_dispatch_imports
129    }
130
131    /// Reads every selected relation-table surface in declaration order.
132    pub fn relation_tables(&self) -> impl Iterator<Item = &RelationTableProjection> {
133        self.relation_tables.iter().flat_map(|tables| tables.iter())
134    }
135
136    pub(in crate::recipe) const fn at(&self) -> SpanHandle {
137        self.at
138    }
139}
140
141impl RelationTableProjection {
142    pub(in crate::recipe) fn informed(
143        relation: String,
144        function: String,
145        source: LoweringSource,
146        exact_rust: Option<GeneratedTree>,
147        bindings: Option<[crate::token::GeneratedToken; 2]>,
148        imports: Option<[bool; 2]>,
149        at: SpanHandle,
150    ) -> Self {
151        Self {
152            relation,
153            function,
154            source,
155            exact_rust,
156            bindings,
157            imports,
158            at,
159        }
160    }
161
162    /// Reads the caller-named relation selected by this table.
163    #[must_use]
164    pub fn relation(&self) -> &str {
165        self.relation.as_str()
166    }
167
168    /// Reads the effective function name inside the relation-named module.
169    #[must_use]
170    pub fn function(&self) -> &str {
171        self.function.as_str()
172    }
173
174    /// Reads where this function surface came from.
175    #[must_use]
176    pub const fn source(&self) -> LoweringSource {
177        self.source
178    }
179
180    pub(in crate::recipe) const fn at(&self) -> SpanHandle {
181        self.at
182    }
183
184    /// Reads the exact caller-authored function signature where one was supplied.
185    #[must_use]
186    pub const fn exact_rust(&self) -> Option<&GeneratedTree> {
187        self.exact_rust.as_ref()
188    }
189
190    pub(in crate::recipe) const fn bindings(&self) -> Option<&[crate::token::GeneratedToken; 2]> {
191        self.bindings.as_ref()
192    }
193
194    pub(in crate::recipe) const fn imports(&self) -> Option<&[bool; 2]> {
195        self.imports.as_ref()
196    }
197}
198
199impl<'recipe> RecipeView<'recipe> {
200    pub(in crate::recipe) const fn over(recipe: &'recipe Recipe) -> Self {
201        Self { recipe }
202    }
203
204    /// Reads the informed recipe without plan or mutation authority.
205    #[must_use]
206    pub const fn recipe(self) -> &'recipe Recipe {
207        self.recipe
208    }
209}
210
211impl<'projector> ProjectorReplacement<'projector> {
212    /// Bind one caller-owned projector to one selected role for one bake.
213    #[must_use]
214    pub const fn for_role(
215        role: RecipeRole,
216        projector: &'projector dyn super::RecipeProjector,
217    ) -> Self {
218        Self { role, projector }
219    }
220
221    /// Reads the selected role this caller-owned projector replaces.
222    #[must_use]
223    pub const fn role(self) -> RecipeRole {
224        self.role
225    }
226
227    pub(in crate::recipe) const fn projector(self) -> &'projector dyn super::RecipeProjector {
228        self.projector
229    }
230}
231
232impl<'recipe> ProjectionRequest<'recipe> {
233    pub(in crate::recipe) const fn selected(effective: &'recipe EffectiveProjection) -> Self {
234        Self { effective }
235    }
236
237    /// Reads the exact selected role this invocation answers.
238    #[must_use]
239    pub const fn role(self) -> RecipeRole {
240        self.effective.role()
241    }
242
243    /// Reads the complete effective mechanical configuration for this invocation.
244    #[must_use]
245    pub const fn effective(self) -> &'recipe EffectiveProjection {
246        self.effective
247    }
248
249    /// Reads the destination owned by the selected role.
250    #[must_use]
251    pub fn destination(self) -> crate::kind::Destination {
252        self.role().destination()
253    }
254}
255
256impl<'output, 'plan> ProjectionSink<'output, 'plan> {
257    pub(in crate::recipe) const fn bound(
258        output: &'output mut Output<'plan, RecipeProjection>,
259        role: RecipeRole,
260    ) -> Self {
261        Self { output, role }
262    }
263
264    /// Offers one tree under the exact role bound into this one-use capability.
265    ///
266    /// # Errors
267    ///
268    /// Returns the existing output refusal when the plan does not admit the role or the rendered bytes exceed their bound.
269    pub fn offer(self, tree: GeneratedTree) -> Result<ProjectionOffered, ProjectionError> {
270        self.output
271            .unit(self.role, tree)
272            .map_err(ProjectionError::Render)?;
273        Ok(ProjectionOffered { _private: () })
274    }
275}
276
277impl RecipeBake {
278    pub(in crate::recipe) const fn baked(
279        projection: Expansion<RecipeProjection>,
280        emitted: Expansion<RecipeShell>,
281    ) -> Self {
282        Self {
283            projection,
284            emitted,
285        }
286    }
287
288    /// Reads the selected projection expansion before final module assembly.
289    pub const fn projection(&self) -> &Expansion<RecipeProjection> {
290        &self.projection
291    }
292
293    /// Reads the proved declaration-site cargo emitted by the paved proc host.
294    pub fn emit(&self) -> &crate::closure::PartitionCargo {
295        self.emitted.emit()
296    }
297}
298
299impl RecipeShellContent {
300    pub(in crate::recipe) const fn composed(
301        recipe: crate::identity::ClosedExpansionId,
302        support: Option<crate::identity::ClosedExpansionId>,
303    ) -> Self {
304        Self { recipe, support }
305    }
306}