prebindgen_registry/registry/declare.rs
1//! Build a registry: say what the binding contains, then close it.
2//!
3//! Every declaring method here records; none derives. The builder is a passive
4//! recorder precisely so it never has to call back into a generator to find out
5//! what it is meant to produce — and it is a *separate type* from [`Registry`]
6//! so that "still being described" and "finished, and answerable" cannot be
7//! confused for one another.
8
9use std::collections::{HashMap, HashSet};
10
11use super::*;
12
13/// A registry under construction.
14///
15/// Chain the declarations, hand over the conversions, then [`build`](Self::build):
16///
17/// ```ignore
18/// let registry = Registry::builder(flat)?
19/// .export(&name)
20/// .decompose(decompositions)
21/// .convert_with(|crossing, built, emit| my_gen.convert(crossing, built, emit))?
22/// .build()?;
23/// ```
24///
25/// The result is read-only. Nothing can add a crossing to a `Registry`, which
26/// is what makes "every crossing has a conversion" a fact about the type rather
27/// than a phase you have to be careful about.
28pub struct RegistryBuilder<M> {
29 registry: Registry<M>,
30 /// Conversions handed over so far, applied at [`Self::build`].
31 built: HashMap<Crossing, TypeEntry<M>>,
32 /// The scan runs once, on demand: it needs every declaration, and
33 /// [`Self::crossings`] / [`Self::convert_with`] / [`Self::build`] each need
34 /// it to have run. `Some` holds the derived demand, in order.
35 order: Option<Vec<Crossing>>,
36}
37
38impl<M> Registry<M> {
39 /// Start describing a binding over this model.
40 ///
41 /// A `Flat` is what a registry projects, and reading captured prebindgen
42 /// output into one is [`FlatBuilder`](prebindgen_flat::flat::FlatBuilder)'s job
43 /// — so a build script says where items come from at the layer that owns
44 /// the question, and there is one such layer rather than two:
45 ///
46 /// ```
47 /// # prebindgen::Source::init_doctest_simulate();
48 /// use prebindgen_registry::{Flat, Registry};
49 ///
50 /// let flat = Flat::builder().source("source_ffi").build()?;
51 /// // Annotated only because nothing here resolves: in a build script `M` is
52 /// // fixed by the adapter passed to `resolve`, so no call site names it.
53 /// let registry: Registry<()> = Registry::builder(flat)?.build()?;
54 /// assert!(registry.flat().function("test_function").is_some());
55 /// # Ok::<_, Box<dyn std::error::Error>>(())
56 /// ```
57 ///
58 /// Several sources compose there too, including one this crate renames:
59 ///
60 /// ```ignore
61 /// let flat = Flat::builder()
62 /// .source(flat_crate::PREBINDGEN_OUT_DIR)
63 /// .source_named(helpers::PREBINDGEN_OUT_DIR, "helpers")
64 /// .build()?;
65 /// ```
66 ///
67 /// **Fails on anything the language cannot express** — a `self` receiver, an
68 /// `async fn`, a generic binder, a type form outside the grammar, or a
69 /// reference to a type the flat API does not declare. All of them at once, so
70 /// a source crate that needs migrating sees one list instead of one rebuild
71 /// per item. This is independent of what any binding declares: an
72 /// inexpressible item is a hard error whether or not it is ever named.
73 pub fn builder(flat: prebindgen_flat::flat::Flat) -> Result<RegistryBuilder<M>, ScanError> {
74 let entries: Vec<NotExpressibleEntry> = flat
75 .unsupported()
76 .map(|u| NotExpressibleEntry {
77 name: u.name.clone(),
78 reason: u.error.to_string(),
79 location: (*u.origin.location).clone(),
80 })
81 .collect();
82 if !entries.is_empty() {
83 return Err(ScanError::NotExpressible { entries });
84 }
85
86 let mut registry = Registry::empty();
87 registry.flat = flat;
88 Ok(RegistryBuilder {
89 registry,
90 built: HashMap::new(),
91 order: None,
92 })
93 }
94}
95
96impl<M> RegistryBuilder<M> {
97 // ── configure: what this binding builds ───────────────────────────
98 //
99 // Pushed in by the generator before `resolve`. The registry never asks —
100 // it records, then derives the crossing set from what it was given.
101
102 /// An element this binding **exports**.
103 ///
104 /// The model says how to derive its crossings, so the caller does not: a
105 /// function's signature gives its parameters (in) and its return (out); a
106 /// const gives its value type (out). A name matching no element is an
107 /// error, reported with every other missing name at once by `resolve`
108 /// rather than here — a build script with three typos should learn all
109 /// three in one build.
110 pub fn export(mut self, name: &syn::Ident) -> Self {
111 self.registry.declared.functions.insert(name.clone());
112 self
113 }
114
115 /// A const this binding exports.
116 ///
117 /// Separate from [`Self::export`] only because *having a const mechanism at
118 /// all* is itself a fact: a binding that never calls this re-emits every
119 /// captured const verbatim, while one that calls it emits exactly what it
120 /// names. See [`Self::declares_consts`].
121 pub fn export_const(mut self, name: &syn::Ident) -> Self {
122 self.registry
123 .declared
124 .consts
125 .get_or_insert_with(HashSet::new)
126 .insert(name.clone());
127 self
128 }
129
130 /// Declare that this binding has a const mechanism, even if it exports no
131 /// consts. Without it every captured const is re-emitted verbatim.
132 pub fn declares_consts(mut self) -> Self {
133 self.registry
134 .declared
135 .consts
136 .get_or_insert_with(HashSet::new);
137 self
138 }
139
140 /// A type this binding **exports**: it crosses in both directions, and its
141 /// body — a struct's fields, an enum's payloads — is scanned too.
142 ///
143 /// Takes the **type the declaration was written with**, like its sibling
144 /// [`Self::cross`], and derives the key here. It used to take the key alone,
145 /// which meant the scan had to recover tokens *from* the key to intern the
146 /// type and to diagnose its spelling — reasoning backwards from an identity
147 /// to a thing that already existed. A build script wrote `ptr_class!(Foo)`;
148 /// this is that `Foo` (#291).
149 ///
150 /// Declaring the same type twice keeps the **first** spelling. That is what
151 /// the `HashSet` this replaced did with the identity, and what
152 /// `register_class` does with a reopened declarator: the two spellings agree
153 /// on identity by construction, so the tie-break only decides which
154 /// equivalent rendering the scan reads, and it should not depend on
155 /// declaration order.
156 pub fn export_type(mut self, ty: Origin<syn::Type>) -> Self {
157 self.registry.declared.types.entry(ty.key()).or_insert(ty);
158 self
159 }
160
161 /// A type that **crosses** in one direction without being exported.
162 ///
163 /// The escape hatch for a crossing no signature can yield: a re-exported
164 /// foreign type named by a class declaration, or the value type of a
165 /// constant the binding synthesizes. Direction is explicit because these
166 /// are genuinely one-sided — which is what stops an output-only crossing
167 /// from silently lacking its input twin, the asymmetry the old
168 /// `required_output_types` had.
169 pub fn cross(mut self, dir: Direction, ty: &syn::Type) -> Self {
170 self.registry.declared.crossings.push((dir, ty.clone()));
171 self
172 }
173
174 /// `from`'s conversion needs `on`'s to exist first.
175 ///
176 /// [`Self::crossings`] derives its order from the type structure, which
177 /// covers almost everything: an `Option<T>` visibly contains a `T`. It
178 /// cannot see a dependency the *declaration* creates — a `convert!` whose
179 /// body chains through a helper function's parameter type, say, where
180 /// nothing about the target type mentions the other side.
181 ///
182 /// State those here, and the order accounts for them. Getting it wrong is
183 /// not silent: the conversion that needed the missing one simply cannot be
184 /// built, and [`Self::build`] names it.
185 pub fn depends(mut self, from: Crossing, on: Crossing) -> Self {
186 self.registry.declared.edges.push((from, on));
187 self
188 }
189
190 /// A function this binding **references but never emits** — a helper whose
191 /// name appears in a declaration. Its absence is an error; its presence
192 /// emits nothing.
193 pub fn reference(mut self, name: &syn::Ident) -> Self {
194 self.registry.declared.helper_functions.insert(name.clone());
195 self
196 }
197
198 /// A function the **binding crate itself** defines, with the module path
199 /// generated calls should qualify it by.
200 ///
201 /// There is no `#[prebindgen]` item behind it, so this is the one input
202 /// that adds to the model rather than selecting from it: only the
203 /// signature is read, never the body. A name colliding with a captured
204 /// item is an error — the generated call would resolve the wrong function.
205 pub fn local_function(
206 mut self,
207 item_fn: syn::ItemFn,
208 origin: String,
209 ) -> Result<Self, ScanError> {
210 let ident = item_fn.sig.ident.clone();
211 // Written by hand in a build script, so the grammar is checked here or
212 // nowhere: a dropped `self` receiver would surface as an arity mismatch
213 // out of rustc on generated code, which is the wrong end of the pipeline
214 // to learn about a build.rs typo.
215 let lowered = self
216 .registry
217 .flat
218 .lower_signature(&item_fn)
219 .map_err(|error| ScanError::AdapterInvariant {
220 message: format!("binding-local fn `{ident}`: {error}"),
221 })?;
222 if self.registry.flat.element(&ident).is_some() {
223 return Err(ScanError::AdapterInvariant {
224 message: format!(
225 "binding-local fn `{ident}` collides with a `#[prebindgen]` item — \
226 the generated call would resolve the wrong fn; rename the \
227 binding-local fn"
228 ),
229 });
230 }
231 self.registry.flat.add_local_function(lowered, origin);
232 Ok(self)
233 }
234
235 /// A function a decomposition reaches through rather than emits — excluded
236 /// from constructor composition, and the only functions a decomposer record
237 /// may name.
238 ///
239 /// Rides here until decompositions carry their own shape (step 2 of #251);
240 /// it is a property of the decomposition, not of the binding.
241 pub fn accessor(mut self, name: &syn::Ident) -> Self {
242 self.registry.declared.accessors.insert(name.clone());
243 self
244 }
245
246 /// The receiver type of a function emitted as a method. Same temporary
247 /// home as [`Self::accessor`].
248 pub fn method_receiver(mut self, name: &syn::Ident, receiver: TypeKey) -> Self {
249 self.registry
250 .declared
251 .method_receivers
252 .insert(name.clone(), receiver);
253 self
254 }
255
256 /// How this binding's composites cross **in pieces** instead of whole.
257 ///
258 /// Stated once, before [`Self::build`]. Replaces five separate callbacks
259 /// the registry used to make into the generator; see [`Decompositions`].
260 pub fn decompose(mut self, d: Decompositions) -> Self {
261 self.registry.declared.decompositions = d;
262 self
263 }
264}
265
266impl<M> RegistryBuilder<M> {
267 /// The model being described. Complete from the first call: everything that
268 /// adds to it ([`Self::local_function`]) is a declaration, not a derivation.
269 pub fn flat(&self) -> &prebindgen_flat::flat::Flat {
270 &self.registry.flat
271 }
272
273 /// Module paths of every ingested source, ingestion order.
274 ///
275 /// A model question, and the model is complete from the first call — so the
276 /// builder answers it exactly as the finished registry does.
277 pub fn all_source_modules(&self) -> Vec<syn::Path> {
278 self.registry.all_source_modules()
279 }
280
281 /// The origin crate's module path for an item — see
282 /// [`Registry::origin_module`].
283 pub fn origin_module(&self, ident: &syn::Ident) -> Option<syn::Path> {
284 self.registry.origin_module(ident)
285 }
286
287 /// The default module for references with no recorded origin — see
288 /// [`Registry::default_module`].
289 pub fn default_module(&self) -> Option<syn::Path> {
290 self.registry.default_module()
291 }
292
293 /// Every **named** item the model holds — see
294 /// [`Registry::named_item_idents`].
295 pub fn named_item_idents(&self) -> impl Iterator<Item = &syn::Ident> {
296 self.registry.named_item_idents()
297 }
298
299 /// Whether the source declares a type under this name — see
300 /// `Registry::declares_type`.
301 #[cfg(test)]
302 pub(crate) fn declares_type(&self, ident: &syn::Ident) -> bool {
303 self.registry.declares_type(ident)
304 }
305
306 /// Run the scan and apply the decompositions, once.
307 ///
308 /// Private and idempotent: three entry points need it to have happened, and
309 /// none of them should care whether it already did.
310 fn derive(&mut self) -> Result<&[Crossing], WriteRustError> {
311 if self.order.is_none() {
312 let mut declared = std::mem::take(&mut self.registry.declared);
313 let out = (|| {
314 self.registry.scan_declared_items(&declared)?;
315 self.registry.apply_adapter_plans(&mut declared)
316 })();
317 self.registry.declared = declared;
318 out?;
319 self.order = Some(self.registry.crossings());
320 }
321 Ok(self.order.as_deref().unwrap_or_default())
322 }
323
324 /// What a conversion — or a validation — is written against right now: the
325 /// model, the full crossing population, and whatever has been built so far.
326 fn view(&self) -> Building<'_, M> {
327 Building::new(
328 &self.registry,
329 &self.built,
330 self.order.as_deref().unwrap_or_default(),
331 )
332 }
333
334 /// Check this binding against a generator's own invariants, now that the
335 /// scan has read every declared signature.
336 ///
337 /// Earliest it can run: a missing declaration has already hard-errored, so
338 /// a check here sees only items that exist.
339 pub fn validate_with<E>(mut self, adapter: &E) -> Result<Self, WriteRustError>
340 where
341 E: Prebindgen<Metadata = M>,
342 {
343 self.derive()?;
344 adapter
345 .validate(&self.view())
346 .map_err(|message| ScanError::AdapterInvariant { message })?;
347 Ok(self)
348 }
349
350 /// Every crossing this binding needs a conversion for, **inner types
351 /// first** — see [`Self::crossings`] for what the order guarantees.
352 ///
353 /// Take this when you want to drive the loop yourself and hand the result
354 /// back through [`Self::conversions`]. [`Self::convert_with`] is the same
355 /// walk with the loop written for you.
356 pub fn crossings(&mut self) -> Result<Vec<Crossing>, WriteRustError> {
357 Ok(self.derive()?.to_vec())
358 }
359
360 /// Build a conversion for each crossing, in dependency order.
361 ///
362 /// `f` is called once per crossing with the conversions already built, so
363 /// by the time it sees `Option<Handle>` it can look up `Handle`. Returning
364 /// `None` records a gap — whether that gap matters is decided by
365 /// [`Self::build`], not here.
366 ///
367 /// This is a convenience over [`Self::crossings`] + [`Self::conversions`],
368 /// not a second mechanism: it is the same list, walked in the same order.
369 /// Nothing about it lets the registry choose when to call back — the
370 /// closure is yours, and the walk is finished before this returns.
371 pub fn convert_with<F>(mut self, mut f: F) -> Result<Self, WriteRustError>
372 where
373 F: FnMut(
374 &Crossing,
375 &Building<'_, M>,
376 &prebindgen_flat::Emit,
377 ) -> Option<crate::prebindgen::ConverterImpl<M>>,
378 {
379 // A converter IS generated Rust — `ConverterImpl::function` is a
380 // complete `syn::ItemFn` the adapter writes — so this closure is an
381 // emission callback and is handed the capability, exactly as the
382 // `on_*` ones are. See `prebindgen_flat::flat::emit`.
383 let emit = prebindgen_flat::Emit::new();
384 let order = self.derive()?.to_vec();
385 for crossing in &order {
386 let conv = f(crossing, &self.view(), &emit);
387 if let Some(c) = conv {
388 self.built
389 .insert(crossing.clone(), TypeEntry::from_converter(c));
390 }
391 }
392 Ok(self)
393 }
394
395 /// Hand over conversions built elsewhere — the bulk peer of
396 /// [`Self::convert_with`], for a generator that walked
397 /// [`Self::crossings`] itself.
398 ///
399 /// Accumulates, so it composes with `convert_with` and with itself.
400 pub fn conversions(mut self, conversions: HashMap<Crossing, TypeEntry<M>>) -> Self {
401 self.built.extend(conversions);
402 self
403 }
404
405 /// The scanned registry, with no conversions applied and no completeness
406 /// check.
407 ///
408 /// Test-only, and deliberately so: it is the state between "described" and
409 /// "answerable", which is exactly what the split exists to keep out of
410 /// everyone else's hands.
411 #[cfg(test)]
412 pub(crate) fn scanned(mut self) -> Result<Registry<M>, ScanError> {
413 // Narrower than `build`'s error on purpose: the scan is the only phase
414 // this runs, so a test matching on `ScanError` says what it means.
415 match self.derive() {
416 Ok(_) => Ok(self.registry),
417 Err(WriteRustError::Scan(e)) => Err(e),
418 Err(other) => panic!("scanned(): unexpected non-scan failure: {other}"),
419 }
420 }
421
422 /// Close the binding: apply every conversion, check the set is complete,
423 /// and hand back a registry that can only be read.
424 ///
425 /// A crossing with no conversion is not itself a failure — the scan
426 /// over-approximates on purpose. What fails is a crossing *reachable from
427 /// an export* with none, and the error names every one at once.
428 pub fn build(mut self) -> Result<Registry<M>, WriteRustError> {
429 self.derive()?;
430 for ((dir, key), entry) in self.built {
431 if let Some(cell) = self.registry.type_table_mut(dir).get_mut(&key) {
432 cell.entry = Some(entry);
433 }
434 }
435 crate::resolve::check_complete(&self.registry)?;
436 Ok(self.registry)
437 }
438}
439
440/// A builder answers the same questions a finished registry does — with one
441/// difference that is the whole point of the split: [`conversion`] sees only
442/// what has been handed over *so far*.
443///
444/// That is what a generator writing a conversion needs (its inners, already
445/// built) and it is all it should be able to see. Everything else — the model,
446/// the decompositions — is complete from the moment it is declared.
447///
448/// [`conversion`]: Conversions::conversion
449impl<M> Conversions<M> for RegistryBuilder<M> {
450 fn reading(&self, key: &TypeKey) -> Option<prebindgen_flat::flat::TypeRef> {
451 self.registry.reading(key)
452 }
453 fn flat(&self) -> &prebindgen_flat::flat::Flat {
454 &self.registry.flat
455 }
456 fn conversion(
457 &self,
458 dir: Direction,
459 reading: &prebindgen_flat::flat::TypeRef,
460 ) -> Option<&TypeEntry<M>> {
461 self.built.get(&(dir, reading.key()))
462 }
463 fn crossing_keys(&self, dir: Direction) -> Vec<TypeKey> {
464 self.order
465 .as_deref()
466 .unwrap_or_default()
467 .iter()
468 .filter(|(d, _)| *d == dir)
469 .map(|(_, k)| k.clone())
470 .collect()
471 }
472 fn callback_arg_plan(&self, key: &TypeKey) -> Option<&crate::unfold::UnfoldPlan> {
473 self.registry.callback_arg_plans.get(key)
474 }
475 fn callback_arg_plans(&self) -> &HashMap<TypeKey, crate::unfold::UnfoldPlan> {
476 &self.registry.callback_arg_plans
477 }
478 fn unfold_plans(&self) -> &HashMap<syn::Ident, crate::unfold::UnfoldPlan> {
479 &self.registry.unfold_plans
480 }
481 fn error_plans(&self) -> &HashMap<syn::Ident, crate::unfold::UnfoldPlan> {
482 &self.registry.error_plans
483 }
484 fn decon_plans(&self) -> &HashMap<crate::unfold::DeconId, crate::unfold::DeconSpec> {
485 &self.registry.decon_plans
486 }
487}