prebindgen_c/builder.rs
1use super::*;
2
3impl CbindgenBuilder {
4 fn clear_current(&mut self) {
5 self.current = None;
6 }
7
8 /// Create an adapter with no declarations (emits an empty library).
9 pub fn new() -> Self {
10 Self::default()
11 }
12
13 /// Set the module path the original `#[prebindgen]` items live under
14 /// (e.g. `syn::parse_quote!(zenoh_flat)`). Root-level modifier: resets the
15 /// current declaration, so it can't be followed by `.base_name()`/`.error()`/etc.
16 pub fn source_module(mut self, p: syn::Path) -> Self {
17 self.source_module = Some(p);
18 self.clear_current();
19 self
20 }
21
22 /// Set the name of the universal memory-freeing function (a type-agnostic C
23 /// `free`) the generated layer exports for releasing `char*` data it hands to
24 /// C — string returns and `String` fields of data structs. Root-level
25 /// modifier: resets the current declaration. Required whenever the adapter
26 /// produces such string memory; otherwise that's a build error.
27 pub fn free_memory_function(mut self, name: impl Into<String>) -> Self {
28 self.free_fn = Some(name.into());
29 self.clear_current();
30 self
31 }
32
33 /// Set the **base** Rust-type mangler: maps a type's Rust short name (e.g.
34 /// `ZKeyExpr`) to a canonical token (e.g. `keyexpr`). Its output feeds
35 /// [`Self::mangle_type_name`], [`Self::mangle_destructor`] and
36 /// [`Self::mangle_callback`], so a one-off spelling fix (e.g. `KeyExpr` →
37 /// `keyexpr`) lives in a single place instead of a per-declaration
38 /// `.base_name()` exception. Root-level modifier (resets the current
39 /// declaration). The adapter ships no default — unset, the base defaults to the
40 /// `snake_case` of the Rust short name.
41 pub fn mangle_rust_type(mut self, f: impl Fn(&str) -> String + 'static) -> Self {
42 self.mangle_rust_type = Some(Box::new(f));
43 self.clear_current();
44 self
45 }
46
47 /// Set the type-name mangler: base (see [`Self::mangle_rust_type`]) → the C
48 /// type name emitted for a `opaque_ptr` / `data_struct` / `enum_type` (e.g.
49 /// `keyexpr` → `z_keyexpr_t`). The base can be overridden per declaration by
50 /// [`.base_name()`](Self::base_name). Root-level modifier.
51 pub fn mangle_type_name(mut self, f: impl Fn(&str) -> String + 'static) -> Self {
52 self.mangle_type_name = Some(Box::new(f));
53 self.clear_current();
54 self
55 }
56
57 /// Set the destructor mangler: base → an opaque handle's `_drop` symbol (e.g.
58 /// `keyexpr` → `z_keyexpr_drop`). Root-level modifier.
59 pub fn mangle_destructor(mut self, f: impl Fn(&str) -> String + 'static) -> Self {
60 self.mangle_destructor = Some(Box::new(f));
61 self.clear_current();
62 self
63 }
64
65 /// Set the "take" mangler: base → the public move symbol of a `value_opaque`
66 /// type used as a [`Self::takeable_param`] (e.g. `sample` → `z_sample_take`).
67 /// When unset, the take symbol defaults to `<destructor-base>_take`. Root-level
68 /// modifier.
69 pub fn mangle_take(mut self, f: impl Fn(&str) -> String + 'static) -> Self {
70 self.mangle_take = Some(Box::new(f));
71 self.clear_current();
72 self
73 }
74
75 /// Set the callback-struct mangler: the bases of a callback's argument types
76 /// → the closure struct's C name (e.g. `["sample"]` → `z_closure_sample_t`,
77 /// `[]` → `z_closure_drop_t`). A per-declaration [`.base_name()`](Self::base_name)
78 /// replaces the args' bases with a single explicit base. Root-level modifier.
79 pub fn mangle_callback(mut self, f: impl Fn(&[String]) -> String + 'static) -> Self {
80 self.mangle_callback = Some(Box::new(f));
81 self.clear_current();
82 self
83 }
84
85 /// Set the function mangler: a `#[prebindgen]` function's Rust ident → its
86 /// exported `#[no_mangle]` symbol (e.g. prefix `z_`). Functions are not types,
87 /// so this does not go through the base mangler; the ident can be overridden
88 /// per declaration by [`.base_name()`](Self::base_name). Root-level modifier.
89 pub fn mangle_function(mut self, f: impl Fn(&str) -> String + 'static) -> Self {
90 self.mangle_function = Some(Box::new(f));
91 self.clear_current();
92 self
93 }
94
95 /// Declare a `#[prebindgen]` function to convert into the C layer.
96 /// Every `#[prebindgen]` item captured in `dir` — see
97 /// `JniGenBuilder::source`.
98 pub fn source<P: AsRef<std::path::Path>>(mut self, dir: P) -> Self {
99 self.sources = std::mem::take(&mut self.sources).source(dir);
100 self
101 }
102
103 /// The same, for a dependency this crate **renames** in `Cargo.toml`.
104 pub fn source_named<P: AsRef<std::path::Path>>(
105 mut self,
106 dir: P,
107 crate_name: impl Into<String>,
108 ) -> Self {
109 self.sources = std::mem::take(&mut self.sources).source_named(dir, crate_name);
110 self
111 }
112
113 /// Add a captured item stream. Accumulates, so it mixes with
114 /// [`Self::source`].
115 pub fn items<I>(mut self, items: I) -> Self
116 where
117 I: IntoIterator<Item = (syn::Item, prebindgen::SourceLocation)>,
118 {
119 self.sources = std::mem::take(&mut self.sources).items(items);
120 self
121 }
122
123 pub fn function(mut self, ident: syn::Ident) -> Self {
124 assert!(
125 !self.ignored_functions.contains(&ident),
126 "Cbindgen::function cannot declare `{}` because it is already ignored",
127 ident
128 );
129 self.functions.insert(ident.clone(), FnCfg::default());
130 self.current = Some(CurrentDecl::Function(ident));
131 self
132 }
133
134 /// Declare a canonical scalar conversion shared with JniGenBuilder. A domain on
135 /// the [`ConvertDecl`] is validated in both directions; invalid scalar
136 /// values become by-value niches for `Option`/`Result`, with public C
137 /// constants derived from the conversion's naming base.
138 pub fn convert(mut self, decl: ConvertDecl) -> Self {
139 assert!(
140 decl.input_spec().is_some() || decl.output_spec().is_some(),
141 "Cbindgen::convert declares no input or output conversion"
142 );
143 let key = decl.key().clone();
144 assert!(
145 !self
146 .convert_decls
147 .iter()
148 .any(|existing| *existing.key() == key),
149 "Cbindgen::convert already declares {}",
150 key
151 );
152 self.convert_decls.push(decl);
153 self.current = Some(CurrentDecl::Convert(key));
154 self
155 }
156
157 /// Mark a `#[prebindgen]` function as intentionally ignored by this
158 /// adapter. Root-level modifier: suppresses the registry's
159 /// "skipping undeclared" warning for that function without scanning or
160 /// emitting it.
161 pub fn ignore_function(mut self, ident: syn::Ident) -> Self {
162 assert!(
163 !self.functions.contains_key(&ident),
164 "Cbindgen::ignore_function cannot ignore `{}` because it is already declared",
165 ident
166 );
167 self.ignored_functions.insert(ident);
168 self.clear_current();
169 self
170 }
171
172 /// Allow the most recently declared [`Self::function`] to `panic!` on an
173 /// internal error message. Required when a non-`Result` function has a
174 /// fallible input (otherwise that's a build error) — a null borrow, an
175 /// invalid `String`, or an out-of-range discriminant for a declared
176 /// [`Self::enum_type`].
177 pub fn panic(mut self) -> Self {
178 match &self.current {
179 Some(CurrentDecl::Function(ident)) => {
180 let ident = ident.clone();
181 self.functions
182 .get_mut(&ident)
183 .expect("function entry vanished")
184 .panic = true;
185 }
186 other => panic!(
187 "Cbindgen::panic must be chained after a `function(...)` call, \
188 not after {}",
189 describe_current(other)
190 ),
191 }
192 self
193 }
194
195 /// Declare a pointer-struct (opaque-handle) type — a `Box`-owned Rust value
196 /// the C side holds as `#[repr(C)] struct T { _0: *mut c_void }`. Its C
197 /// struct + `<name>_drop` destructor are generated. (Mirrors `JniExt`'s
198 /// `ptr_class`.)
199 pub fn opaque_ptr(mut self, ty: syn::Type) -> Self {
200 let key = TypeKey::from_type(&ty);
201 assert!(
202 !self.ignored_types.contains(&key),
203 "Cbindgen::opaque_ptr cannot declare `{}` because it is already ignored",
204 key
205 );
206 self.opaque.insert(key.clone(), TypeCfg::new(ty));
207 self.current = Some(CurrentDecl::Ptr(key));
208 self
209 }
210
211 /// Declare a by-value `#[repr(C)]` data struct (e.g. `Error`).
212 pub fn data_struct(mut self, ty: syn::Type) -> Self {
213 let key = TypeKey::from_type(&ty);
214 assert!(
215 !self.ignored_types.contains(&key),
216 "Cbindgen::data_struct cannot declare `{}` because it is already ignored",
217 key
218 );
219 self.data.insert(key.clone(), TypeCfg::new(ty));
220 self.current = Some(CurrentDecl::Data(key));
221 self
222 }
223
224 /// Declare an **inline-opaque by-value, plain-data** type: the Rust value
225 /// `rust_ty` is passed across the C ABI *by value* (no `Box`) by transmuting it
226 /// to/from `opaque_ty`, an opaque `#[repr(C, align(_))]` counterpart of
227 /// identical size+align (typically produced by a size/align probe generator and
228 /// defined elsewhere). Use this for types that hold **no external resource**
229 /// (typically `Copy` — e.g. a timestamp): consuming one simply moves it out,
230 /// leaving the source's bitwise duplicate harmlessly droppable, so **no
231 /// gravestone write-back and no `prebindgen_c_runtime::Gravestone` impl are needed** —
232 /// only the autogenerated `prebindgen_c_runtime::Transmute` glue (emitted here) plus a
233 /// fail-closed `const _` size+align equality assert. Contrast
234 /// [`Self::opaque_owned_struct`] for types owning external data.
235 pub fn opaque_data_struct(self, rust_ty: syn::Type, opaque_ty: syn::Type) -> Self {
236 self.declare_opaque(rust_ty, opaque_ty, OpaqueKind::Data)
237 }
238
239 /// Declare an **inline-opaque by-value, owns-external-data** type: like
240 /// [`Self::opaque_data_struct`], but for a Rust value that owns external resources
241 /// (refcounts / heap — e.g. a byte buffer, a sample). Passed *by value* (no
242 /// `Box`) via the `opaque_ty` transmute counterpart; the converters move values
243 /// via `prebindgen_c_runtime::Transmute` and write a **gravestone** back on consume
244 /// (safe drop-after-move), exposing an `Option<rust_ty>` null niche. The
245 /// consumer must implement `prebindgen_c_runtime::Gravestone` for `opaque_ty` — only
246 /// its *logic* (`rust_gravestone`).
247 pub fn opaque_owned_struct(self, rust_ty: syn::Type, opaque_ty: syn::Type) -> Self {
248 self.declare_opaque(rust_ty, opaque_ty, OpaqueKind::Owned)
249 }
250
251 /// Shared body of [`Self::opaque_data_struct`] / [`Self::opaque_owned_struct`].
252 pub(super) fn declare_opaque(
253 mut self,
254 rust_ty: syn::Type,
255 opaque_ty: syn::Type,
256 kind: OpaqueKind,
257 ) -> Self {
258 let method = match kind {
259 OpaqueKind::Data => "opaque_data_struct",
260 OpaqueKind::Owned => "opaque_owned_struct",
261 };
262 let key = TypeKey::from_type(&rust_ty);
263 assert!(
264 !self.ignored_types.contains(&key),
265 "Cbindgen::{method} cannot declare `{key}` because it is already ignored",
266 );
267 self.value_opaque.insert(
268 key.clone(),
269 ValueOpaqueCfg {
270 opaque: opaque_ty,
271 kind,
272 generate_mirror: false,
273 assume_c_field_validity: false,
274 cfg: TypeCfg::new(rust_ty),
275 },
276 );
277 self.current = Some(CurrentDecl::ValueOpaque(key));
278 self
279 }
280
281 /// Declare a **`#[repr(C)]`, FFI-safe value struct** crossed **by direct
282 /// reinterpret** (zero-copy) — the C struct's memory *is* the Rust struct's
283 /// memory. Unlike [`Self::data_struct`] (which copies each field, lowering a
284 /// `String` to `char*`), this passes the whole struct by value via
285 /// `prebindgen_c_runtime::Transmute` and a `&T` borrow / `impl Fn(&T)` callback as a
286 /// zero-copy `*const` pointer cast — the value-opaque machinery, but with an
287 /// **auto-generated visible-field** `#[repr(C)]` C mirror (so C reads the
288 /// fields directly) instead of an opaque blob.
289 ///
290 /// Every field must be FFI-safe: a primitive, a declared
291 /// [`Self::enum_type`], or an **opaque pointer** `Option<Box<T>>` / `Box<T>`
292 /// where `T` is a declared [`Self::opaque_ptr`] (rendered `*mut t_t`; this is
293 /// how a heap `String` rides along — `Option<Box<String>>` → `string_t *`). The
294 /// source type **must** be `#[repr(C)]`; a fail-closed `size_of`/`align_of`
295 /// assert against the generated mirror proves the reinterpret sound at compile
296 /// time. Call after the manglers are configured (the mirror name is resolved
297 /// through them). A `<base>_drop` is generated.
298 ///
299 /// **Owned-ness is inferred** from the fields: a struct with an opaque-pointer field
300 /// owns external resources, so a by-value consume cleans the moved-from slot (nulls
301 /// the owned pointers) to keep the caller's later `_drop` a no-op — no `.owned()`
302 /// modifier and no double-free footgun. A struct with only scalar/enum fields is
303 /// plain data (a by-value crossing is a bitwise copy with no write-back). The source
304 /// type needs `Default` **only** if it has a bare `Box<T>` field (whose gravestone
305 /// can't be a NULL pointer); `Option<Box<T>>` fields are nulled in place.
306 ///
307 /// # Why the spelling is load-bearing here
308 ///
309 /// This is the one position that is **exempt** from the rule stated on
310 /// [`prebindgen_registry::Prebindgen`] — *same `kind` ⇒ same
311 /// destination-language type* — and the exemption is structural rather than
312 /// a concession. A mirror is not converted; it is **reinterpreted from the
313 /// source struct's bytes**, so its field types are a *layout* fact. `Box<T>`
314 /// is a pointer and `T` is inline: to C they really are different types, and
315 /// the size/align assert above would reject a mirror that pretended
316 /// otherwise. So this path reads the wrapper the model erases —
317 /// [`kind`](prebindgen_registry::flat::TypeRef::kind) rather than
318 /// [`unwrapped`](prebindgen_registry::flat::TypeRef::unwrapped) — on
319 /// purpose. It is the one place the usual "classify off `kind`, spell off
320 /// the syntax" split inverts, and it inverts because the contract is layout
321 /// rather than surface.
322 ///
323 /// That is also why a wrapper the model erases must **not** be refused here
324 /// (prebindgen#230). `Option<Box<String>>` is how a source crate says "this
325 /// field is a nullable pointer" — a layout statement a zero-copy mirror is
326 /// entitled to read, not the source naming a C type. There is no competing
327 /// spelling to prefer: `Option<String>` is a 24-byte niche-optimised value
328 /// with no C representation at all, and declaring one is a hard error naming
329 /// the field. Rejecting the `Box` would leave a nullable-pointer field
330 /// inexpressible.
331 pub fn repr_c_struct(mut self, ty: syn::Type) -> Self {
332 let key = TypeKey::from_type(&ty);
333 assert!(
334 !self.ignored_types.contains(&key),
335 "Cbindgen::repr_c_struct cannot declare `{}` because it is already ignored",
336 key
337 );
338 let mirror = self.c_type_ident(&key);
339 self.value_opaque.insert(
340 key.clone(),
341 ValueOpaqueCfg {
342 opaque: syn::parse_quote!(#mirror),
343 kind: OpaqueKind::Data,
344 generate_mirror: true,
345 assume_c_field_validity: false,
346 cfg: TypeCfg::new(ty),
347 },
348 );
349 self.current = Some(CurrentDecl::ValueOpaque(key));
350 self
351 }
352
353 /// Accept a [`Self::repr_c_struct`] whose mirror has **restricted-validity**
354 /// fields, taking responsibility for their bytes.
355 ///
356 /// A `repr_c_struct` crosses IN by one whole-struct reinterpret, so there is
357 /// no per-field hook where a C-supplied byte could be normalised or checked
358 /// before the source struct exists. A field whose Rust type accepts only
359 /// *some* bit patterns — `bool` (`0`/`1`) or a declared [`Self::enum_type`]
360 /// (the declared discriminants) — is therefore undefined behaviour the
361 /// moment C writes anything else into the mirror and hands it back. The
362 /// generator rejects such a declaration by default (#170 instance 3, #158
363 /// instance 3); the real fix is a raw-wire lowering, which does not exist
364 /// yet.
365 ///
366 /// This modifier is the acknowledgement, not a fix: it says the C side of
367 /// this binding is trusted to write only in-domain bytes into those fields.
368 /// It exists so that the audit rejects **silently unsound new declarations**
369 /// without removing bindings that already ship. Chain it directly after the
370 /// [`Self::repr_c_struct`] it applies to; the panic message names every
371 /// field it would cover.
372 ///
373 /// Prefer, in order: move the field into a [`Self::data_struct`] (per-field
374 /// wires, so `bool` normalises), pass it as a separate scalar parameter, or
375 /// widen it to an integer the whole domain of which is valid.
376 pub fn assume_c_field_validity(mut self) -> Self {
377 match self.current.clone() {
378 Some(CurrentDecl::ValueOpaque(key)) => {
379 self.value_opaque
380 .get_mut(&key)
381 .expect("entry vanished")
382 .assume_c_field_validity = true;
383 }
384 other => panic!(
385 "Cbindgen::assume_c_field_validity must follow a `repr_c_struct` declaration, \
386 not {}",
387 describe_current(&other)
388 ),
389 }
390 self
391 }
392
393 /// Mark a `#[prebindgen]` type as intentionally ignored by this adapter.
394 /// Root-level modifier: suppresses the registry's "skipping undeclared"
395 /// warning for that type without scanning or emitting it.
396 pub fn ignore_type(mut self, ty: syn::Type) -> Self {
397 let key = TypeKey::from_type(&ty);
398 assert!(
399 !self.opaque.contains_key(&key)
400 && !self.data.contains_key(&key)
401 && !self.value_opaque.contains_key(&key)
402 && !self.enums.contains_key(&key)
403 && !self.tagged_unions.contains_key(&key),
404 "Cbindgen::ignore_type cannot ignore `{}` because it is already declared",
405 key
406 );
407 self.ignored_types.insert(key);
408 self.clear_current();
409 self
410 }
411
412 /// Set the **base name** token of the **current declaration** (universal
413 /// modifier): the per-declaration base fed to the name manglers, replacing the
414 /// auto-derived one. For a type it replaces the `mangle_rust_type` base (so
415 /// `mangle_type_name`/`mangle_destructor`/`mangle_take` all see it); for a
416 /// function it replaces the ident fed to `mangle_function`; for a callback it
417 /// is the sole base fed to `mangle_callback` (replacing the args' bases —
418 /// useful to disambiguate e.g. `&T` from `T` closures). E.g.
419 /// `.callback(...).base_name("sample_ref")` with a `|bases| "z_closure_{…}_t"`
420 /// mangler → `z_closure_sample_ref_t`. Panics if not chained directly after a
421 /// declaration.
422 pub fn base_name(mut self, base: impl Into<String>) -> Self {
423 let base = base.into();
424 match self.current.clone() {
425 Some(CurrentDecl::Ptr(key)) => {
426 self.opaque.get_mut(&key).expect("entry vanished").base = Some(base);
427 }
428 Some(CurrentDecl::Data(key)) => {
429 self.data.get_mut(&key).expect("entry vanished").base = Some(base);
430 }
431 Some(CurrentDecl::ValueOpaque(key)) => {
432 self.value_opaque
433 .get_mut(&key)
434 .expect("entry vanished")
435 .cfg
436 .base = Some(base);
437 }
438 Some(CurrentDecl::Enum(key)) => {
439 self.enums.get_mut(&key).expect("entry vanished").base = Some(base);
440 }
441 Some(CurrentDecl::TaggedUnion(key)) => {
442 self.tagged_unions
443 .get_mut(&key)
444 .expect("entry vanished")
445 .base = Some(base);
446 }
447 Some(CurrentDecl::Callback(key)) => {
448 self.callbacks.get_mut(&key).expect("entry vanished").base = Some(base);
449 }
450 Some(CurrentDecl::Function(ident)) => {
451 self.functions.get_mut(&ident).expect("entry vanished").base = Some(base);
452 }
453 Some(CurrentDecl::Convert(key)) => {
454 self.convert_bases.insert(key, base);
455 }
456 None => panic!(
457 "Cbindgen::base_name must be chained directly after a declaration \
458 (`opaque_ptr` / `data_struct` / `enum_type` / `tagged_union` / `callback` / \
459 `function` / `convert`)"
460 ),
461 }
462 self
463 }
464
465 /// Mark the current declaration (which must be a [`Self::data_struct`]) as an
466 /// error type: it may appear as the `E` of a `Result<_, E>` return. The type
467 /// must implement `From<String>`. Panics if the current declaration is not a
468 /// data struct.
469 pub fn error(mut self) -> Self {
470 match &self.current {
471 Some(CurrentDecl::Data(key)) => {
472 self.error.insert(key.clone());
473 }
474 other => panic!(
475 "Cbindgen::error must be chained after a `data_struct(...)` call \
476 (error types are marshalled by value), not after {}",
477 describe_current(other)
478 ),
479 }
480 self
481 }
482
483 /// Declare an **opaque error type** — one that appears as the `E` of a
484 /// `Result<_, E>` but is *not* a by-value [`Self::data_struct`] (e.g.
485 /// `ZError = Box<dyn Error + Send + Sync>`). Such an error is marshalled to C
486 /// as a `char*` message obtained by calling `message_fn(&err) -> String`
487 /// (e.g. `z_error_message`); the generated wrapper's error out-param becomes
488 /// `char **e`. The type must implement `From<String>` (so a fallible input's
489 /// internal message can be lifted into it). Root-level modifier (resets the
490 /// current declaration).
491 pub fn opaque_error(mut self, error_ty: syn::Type, message_fn: syn::Ident) -> Self {
492 let key = TypeKey::from_type(&error_ty);
493 self.error.insert(key.clone());
494 self.opaque_errors.insert(key, message_fn);
495 self.clear_current();
496 self
497 }
498
499 /// Declare a C-like (fieldless) enum type to convert. (Mirrors `JniExt`'s
500 /// `enum_class`.)
501 ///
502 /// Crossing **into** Rust, the caller's discriminant is validated before any
503 /// Rust enum is built — an out-of-range one is a fallible-input error, so a
504 /// non-`Result` function taking this enum by value needs [`Self::panic`].
505 /// See the module docs for why the wire is `MaybeUninit<mirror>`.
506 pub fn enum_type(mut self, ty: syn::Type) -> Self {
507 let key = TypeKey::from_type(&ty);
508 assert!(
509 !self.ignored_types.contains(&key),
510 "Cbindgen::enum_type cannot declare `{}` because it is already ignored",
511 key
512 );
513 self.enums.insert(key.clone(), TypeCfg::new(ty));
514 self.current = Some(CurrentDecl::Enum(key));
515 self
516 }
517
518 /// Declare a **data-carrying** enum: it crosses by value as a `#[repr(C)]`
519 /// enum with payload variants, which cbindgen renders as the idiomatic C
520 /// tagged union (a tag enum plus a `union` of the variant bodies). The
521 /// counterpart of [`Self::enum_type`], which is for the unit-variant-only
522 /// case a plain C `enum` can hold. (Mirrors `JniExt`'s `sealed_class`.)
523 ///
524 /// Each payload field crosses as its own wire, chosen by the same policy a
525 /// [`Self::repr_c_struct`] field uses, extended with `String` → `char *`:
526 /// a scalar passes through, a declared [`Self::enum_type`] becomes its C
527 /// enum, a `String` becomes a malloc'd `char *`, and an opaque pointer
528 /// `Option<Box<T>>` / `Box<T>` (with `T` a declared [`Self::opaque_ptr`])
529 /// becomes `*mut t_t`. Anything else is a generation error.
530 ///
531 /// **Ownership.** The union crosses by value, so when any variant's
532 /// payload wire owns memory (`char *`, an opaque pointer) a typed
533 /// `<base>_drop(t_t *)` is generated that frees the **active arm** —
534 /// consistent with the existing typed per-pointer drops. A union whose
535 /// payloads are all plain data needs no drop and gets none.
536 ///
537 /// **Validity.** Crossing **into** Rust, the tag a C caller supplied is
538 /// range-checked before any Rust enum is built — so, exactly like
539 /// [`Self::enum_type`], a union taken by value is a fallible input, and a
540 /// function taking one without a `Result` return needs [`Self::panic`].
541 /// A data struct carrying a union field inherits that fallibility. See the
542 /// module docs for the wire this uses and why.
543 pub fn tagged_union(mut self, ty: syn::Type) -> Self {
544 let key = TypeKey::from_type(&ty);
545 assert!(
546 !self.ignored_types.contains(&key),
547 "Cbindgen::tagged_union cannot declare `{}` because it is already ignored",
548 key
549 );
550 self.tagged_unions.insert(key.clone(), TypeCfg::new(ty));
551 self.current = Some(CurrentDecl::TaggedUnion(key));
552 self
553 }
554
555 /// Declare a callback signature so its `impl Fn(...)` parameters resolve and
556 /// a `#[repr(C)]` closure struct (`{ void *context; call; drop }`) is
557 /// emitted for it. `ty` must be `impl Fn(Args...) + Send + Sync + 'static`.
558 /// Identical signatures share one struct. Sets the declaration cursor, so a
559 /// following `.base_name("...")` sets the base fed to
560 /// [`mangle_callback`](Self::mangle_callback) (else the args' bases drive
561 /// the generated name).
562 pub fn callback(mut self, ty: syn::Type) -> Self {
563 let args = extract_fn_trait_args(&ty).unwrap_or_else(|| {
564 panic!(
565 "Cbindgen::callback expects `impl Fn(Args...) + Send + Sync + 'static`, got `{}`",
566 ty.to_token_stream()
567 )
568 });
569 let key: CallbackKey = args.iter().map(TypeKey::from_type).collect();
570 self.callbacks.insert(key.clone(), CbCfg::new(args));
571 self.current = Some(CurrentDecl::Callback(key));
572 self
573 }
574
575 /// Mark argument `idx` of the **current callback declaration** as a *takeable
576 /// owned pointer*: the C `call` receives `*mut z_x_t` (not by value); the
577 /// callee may take the value (`z_x_take` moves it out, leaving a gravestone) or
578 /// just read it; the trampoline drops it after the call (no-op if taken). The
579 /// arg type must be an inline-opaque type ([`Self::opaque_owned_struct`] /
580 /// [`Self::opaque_data_struct`]). Chain after `.callback(...)` (and any `.base_name(...)`).
581 pub fn takeable_param(mut self, idx: usize) -> Self {
582 match &self.current {
583 Some(CurrentDecl::Callback(key)) => {
584 let key = key.clone();
585 self.callbacks
586 .get_mut(&key)
587 .expect("entry vanished")
588 .takeable
589 .insert(idx);
590 }
591 other => panic!(
592 "Cbindgen::takeable_param must be chained after a `callback(...)` call, not after {}",
593 describe_current(other)
594 ),
595 }
596 self
597 }
598
599 // ── Internal helpers ───────────────────────────────────────────────
600
601 /// Fully-qualify a bare single-segment source type against
602 /// [`Self::source_module`] (e.g. `ZKeyExpr` → `zenoh_flat::ZKeyExpr`).
603 /// Anything already qualified, or with no `source_module` set, is returned
604 /// unchanged.
605 pub(super) fn src_ty(&self, ty: &syn::Type) -> syn::Type {
606 // Built-in scalar primitives (`f64`, `i32`, …) live in no source module;
607 // qualifying them would produce invalid paths like `zenoh_flat::f64` (hit by
608 // callback args, e.g. `impl Fn(f64)`). Leave them bare.
609 if is_scalar(ty) {
610 return ty.clone();
611 }
612 // Std `String` likewise lives in no source module — qualifying it would
613 // produce `zenoh_flat::String`. It can be declared `opaque_ptr` (a boxed
614 // pointer the C side holds as `string_t *`), so resolve it to the std path.
615 if is_string(ty) {
616 return syn::parse_quote!(::std::string::String);
617 }
618 if let (Some(m), syn::Type::Path(tp)) = (&self.source_module, ty) {
619 if tp.qself.is_none() && tp.path.leading_colon.is_none() && tp.path.segments.len() == 1
620 {
621 let mut path = m.clone();
622 path.segments.push(tp.path.segments[0].clone());
623 return syn::Type::Path(syn::TypePath { qself: None, path });
624 }
625 }
626 ty.clone()
627 }
628
629 /// [`Self::src_ty`] off the **identity** — the type peer of
630 /// [`Self::src_fn`], for the emitters that hold a declared type's key or a
631 /// declaration's own `Origin` rather than a node.
632 ///
633 /// A `TypeKey` is a normalized type, so re-parsing it is the reverse of
634 /// `from_type` and the qualification policy stays in one place: `String`
635 /// still resolves to `::std::string::String` (it can be declared
636 /// `opaque_ptr`), scalars are still left bare, and only a bare
637 /// single-segment path is prefixed.
638 pub(super) fn src_ty_of(&self, key: &TypeKey) -> syn::Type {
639 let spelled: syn::Type = syn::parse_str(key.as_str())
640 .expect("a `TypeKey` is a normalized `syn::Type`, so it re-parses");
641 self.src_ty(&spelled)
642 }
643
644 /// Path to a source function (e.g. `zenoh_flat::z_keyexpr_try_from`).
645 pub(super) fn src_fn(&self, ident: &syn::Ident) -> syn::Path {
646 match &self.source_module {
647 Some(m) => {
648 let mut p = m.clone();
649 p.segments.push(syn::PathSegment::from(ident.clone()));
650 p
651 }
652 None => syn::Path::from(ident.clone()),
653 }
654 }
655
656 /// If `ty` is `&[E]` (a shared slice borrow) whose element `E` is a declared
657 /// **inline-opaque by-value** type ([`Self::repr_c_struct`] /
658 /// [`Self::opaque_data_struct`] / [`Self::opaque_owned_struct`] — all in
659 /// `value_opaque`), return `E`. Such a type's C counterpart is layout-identical
660 /// to the Rust value (size+align asserted by a generated `const _`), so a
661 /// `*const counterpart` block reinterprets to `&[E]` zero-copy — exactly as the
662 /// single-`&E` input converter reinterprets one element. Scalar slices take the
663 /// separate [`scalar_slice_elem`](super::scalar_slice_elem) path; other element
664 /// kinds (e.g. `data_struct`, whose wire copies each field) are unsupported here.
665 pub(super) fn value_opaque_slice_elem(&self, ty: &syn::Type) -> Option<syn::Type> {
666 let syn::Type::Reference(r) = ty else {
667 return None;
668 };
669 if r.mutability.is_some() {
670 return None;
671 }
672 let syn::Type::Slice(s) = &*r.elem else {
673 return None;
674 };
675 let elem = (*s.elem).clone();
676 self.value_opaque
677 .contains_key(&TypeKey::from_type(&elem))
678 .then_some(elem)
679 }
680
681 /// For a `&[E]` callback-argument slice, return `(src_elem, c_elem_wire)`:
682 /// the fully-qualified Rust element type and the C element wire it crosses as
683 /// (a scalar crosses as itself; an inline-opaque `E` crosses as its layout-
684 /// identical counterpart, e.g. `payload_t`). Drives the two-component
685 /// `(*const c_elem_wire, size_t)` lowering of the closure `call` param in
686 /// `prereq_callback_structs` / `dispatch_fn_input`. `None` for non-slice args.
687 pub(super) fn callback_slice_elem_wire(
688 &self,
689 ty: &syn::Type,
690 ) -> Option<(syn::Type, syn::Type)> {
691 if let Some(elem) = self.value_opaque_slice_elem(ty) {
692 let wire = self
693 .value_opaque_ty(&elem)
694 .expect("value_opaque_slice_elem guaranteed a value_opaque element")
695 .clone();
696 return Some((self.src_ty(&elem), wire));
697 }
698 scalar_slice_elem(ty).map(|elem| (elem.clone(), elem))
699 }
700
701 /// [`Self::callback_slice_elem_wire`] off the classification, for the
702 /// resolver side — the declaration side keeps the node peer above, because
703 /// a `.callback(...)` argument is written by the build script and the model
704 /// may never have interned it.
705 pub(super) fn callback_slice_elem_wire_of(
706 &self,
707 ty: &TypeRef,
708 ) -> Option<(syn::Type, syn::Type)> {
709 let elem = super::r_shared_slice_elem(ty)?;
710 let key = elem.key();
711 if let Some(wire) = self.value_opaque_ty_of(&key) {
712 return Some((self.src_ty_of(&key), wire.clone()));
713 }
714 super::scalar_ty(elem).map(|s| (s.clone(), s))
715 }
716
717 /// Like [`Self::src_ty`], but recurses into reference and slice element types so
718 /// `&ZSample` becomes `&zenoh_flat::ZSample` and `&[Payload]` becomes
719 /// `&[perftest_flat::Payload]` (needed so a callback's `Fn(&[E])` closure type
720 /// names the qualified element).
721 /// [`Self::src_ty`], recursing into a borrow's and a slice's element — off
722 /// the classification. `&ZSample` becomes `&zenoh_flat::ZSample` and
723 /// `&[Payload]` becomes `&[perftest_flat::Payload]`, so a callback's
724 /// `Fn(&[E])` closure type names the qualified element.
725 ///
726 /// The two recursing forms are `TypeKind::Ref` and `TypeKind::Slice`, which
727 /// is what the `syn::Type::Reference` / `syn::Type::Slice` match this
728 /// replaces was reading — and the borrow's lifetime and mutability are on
729 /// the kind, so the rebuilt spelling says what the source said.
730 pub(super) fn src_ty_deep_of(&self, ty: &TypeRef) -> syn::Type {
731 match ty.kind() {
732 TypeKind::Ref {
733 lifetime,
734 mutable,
735 inner,
736 } => {
737 let inner = self.src_ty_deep_of(inner);
738 let lt = lifetime.as_ref().map(|l| quote!(#l)).unwrap_or_default();
739 let m = if *mutable { quote!(mut) } else { quote!() };
740 syn::parse_quote!(& #lt #m #inner)
741 }
742 TypeKind::Slice(elem) => {
743 let elem = self.src_ty_deep_of(elem);
744 syn::parse_quote!([#elem])
745 }
746 _ => self.src_ty_of(&ty.key()),
747 }
748 }
749
750 /// [`Self::in_name`] off the **identity**, for a caller holding a reading
751 /// rather than a node — which is every per-field site.
752 pub(super) fn in_name_of(key: &TypeKey) -> syn::Ident {
753 format_ident!("__cbg_in_{}", sanitize(key))
754 }
755
756 /// [`Self::out_name`] off the identity. See [`Self::in_name_of`].
757 pub(super) fn out_name_of(key: &TypeKey) -> syn::Ident {
758 format_ident!("__cbg_out_{}", sanitize(key))
759 }
760
761 /// Config of a declared type (across the opaque/data/enum maps), by key.
762 pub(super) fn type_cfg(&self, key: &TypeKey) -> Option<&TypeCfg> {
763 self.opaque
764 .get(key)
765 .or_else(|| self.data.get(key))
766 .or_else(|| self.value_opaque.get(key).map(|c| &c.cfg))
767 .or_else(|| self.enums.get(key))
768 .or_else(|| self.tagged_unions.get(key))
769 }
770
771 /// The opaque counterpart type of a declared inline-opaque type, if any.
772 pub(super) fn value_opaque_ty(&self, ty: &syn::Type) -> Option<&syn::Type> {
773 self.value_opaque_ty_of(&TypeKey::from_type(ty))
774 }
775
776 /// [`Self::value_opaque_ty`] off the **identity**, for a caller holding a
777 /// reading — which is the whole selector chain.
778 pub(super) fn value_opaque_ty_of(&self, key: &TypeKey) -> Option<&syn::Type> {
779 self.value_opaque.get(key).map(|c| &c.opaque)
780 }
781
782 /// [`Self::value_opaque_slice_elem`] off the classification.
783 pub(super) fn r_value_opaque_slice_elem<'t>(&self, t: &'t TypeRef) -> Option<&'t TypeRef> {
784 super::r_shared_slice_elem(t).filter(|e| self.value_opaque.contains_key(&e.key()))
785 }
786
787 /// Type keys used as a takeable callback parameter (any `.takeable_param(idx)`
788 /// across all declared callbacks). These value_opaque types get a public
789 /// `<base>_take(dst, src)` move function.
790 pub(super) fn takeable_type_keys(&self) -> HashSet<TypeKey> {
791 let mut s = HashSet::new();
792 for (key, cfg) in &self.callbacks {
793 for &idx in &cfg.takeable {
794 if let Some(tk) = key.get(idx) {
795 s.insert(tk.clone());
796 }
797 }
798 }
799 s
800 }
801
802 /// Public "take" (move) symbol for a takeable value_opaque type:
803 /// [`Self::mangle_take`] over the base, else `<base>_take` (e.g.
804 /// `z_sample_take`). Symmetric with [`Self::destructor_symbol`].
805 pub(super) fn take_symbol(&self, key: &TypeKey) -> syn::Ident {
806 if let Some(f) = &self.mangle_take {
807 return format_ident!("{}", f(&self.rust_base(key)));
808 }
809 format_ident!("{}_take", self.rust_base(key))
810 }
811
812 /// Base token for a Rust type: [`Self::mangle_rust_type`] applied to the Rust
813 /// short name, or the short name verbatim when unset. Feeds the type-name,
814 /// destructor and callback manglers.
815 pub(super) fn rust_base(&self, key: &TypeKey) -> String {
816 if let Some(b) = self.type_cfg(key).and_then(|c| c.base.clone()) {
817 return b;
818 }
819 let short = type_short(key);
820 match &self.mangle_rust_type {
821 Some(f) => f(&short),
822 // No mangler: a C-like `snake_case` default (so destructors/take/type
823 // names read e.g. `sample_drop`, not `Sample_drop`).
824 None => snake_case(&short),
825 }
826 }
827
828 /// Emitted C type name of a declared type: [`Self::mangle_type_name`] over the
829 /// base, else the base (which is the `mangle_rust_type`/`.base_name` token).
830 pub(super) fn c_type_name(&self, key: &TypeKey) -> String {
831 let base = self.rust_base(key);
832 match &self.mangle_type_name {
833 Some(f) => f(&base),
834 None => base,
835 }
836 }
837
838 /// C type identifier (the `#[repr(C)]` struct/enum name + the wire type used
839 /// across converters and wrappers).
840 pub(super) fn c_type_ident(&self, key: &TypeKey) -> syn::Ident {
841 format_ident!("{}", self.c_type_name(key))
842 }
843
844 /// Destructor symbol of an opaque handle: [`Self::mangle_destructor`] over the
845 /// base, else `<base>_drop`.
846 pub(super) fn destructor_symbol(&self, key: &TypeKey) -> syn::Ident {
847 if let Some(f) = &self.mangle_destructor {
848 return format_ident!("{}", f(&self.rust_base(key)));
849 }
850 format_ident!("{}_drop", self.rust_base(key))
851 }
852
853 /// Emitted C type name of a callback's closure struct: [`Self::mangle_callback`]
854 /// over the bases — a `.base_name(...)` override (as the sole base) when set,
855 /// else the args' derived bases — or, with no mangler, a generic default
856 /// (`closure` for zero bases, `closure_<base0>_<base1>…` otherwise). The
857 /// adapter's own default carries no target-language naming convention.
858 pub(super) fn callback_c_name(&self, key: &CallbackKey) -> String {
859 let base_override = self.callbacks.get(key).and_then(|c| c.base.clone());
860 if let Some(f) = &self.mangle_callback {
861 // The override (when set) is the sole base; otherwise the args' bases.
862 let bases: Vec<String> = match &base_override {
863 Some(b) => vec![b.clone()],
864 None => key.iter().map(|k| self.rust_base(k)).collect(),
865 };
866 return f(&bases);
867 }
868 // No mangler: an explicit base is the name as-is; otherwise compose from
869 // the args' bases.
870 if let Some(b) = base_override {
871 return b;
872 }
873 if key.is_empty() {
874 "closure".to_string()
875 } else {
876 let parts: Vec<String> = key.iter().map(|k| self.rust_base(k)).collect();
877 format!("closure_{}", parts.join("_"))
878 }
879 }
880
881 /// C struct identifier for a callback's closure type (see
882 /// [`Self::callback_c_name`]).
883 pub(super) fn callback_c_ident(&self, key: &CallbackKey) -> syn::Ident {
884 format_ident!("{}", self.callback_c_name(key))
885 }
886}
887
888/// Rebuild the canonical `impl Fn(args...) + Send + Sync + 'static` type from an
889/// argument list (matching the source spelling so its [`TypeKey`] round-trips —
890/// see `core::resolve`'s reconstruction).
891pub(super) fn callback_fn_type(args: &[syn::Type]) -> syn::Type {
892 syn::parse_quote!(impl Fn(#(#args),*) + Send + Sync + 'static)
893}
894
895/// Human-readable description of the current declaration, for panic messages.
896fn describe_current(current: &Option<CurrentDecl>) -> String {
897 match current {
898 None => "no declaration".to_string(),
899 Some(CurrentDecl::Ptr(k)) => format!("opaque_ptr `{}`", k.as_str()),
900 Some(CurrentDecl::Data(k)) => format!("data_struct `{}`", k.as_str()),
901 Some(CurrentDecl::ValueOpaque(k)) => format!("value_opaque `{}`", k.as_str()),
902 Some(CurrentDecl::Enum(k)) => format!("enum_type `{}`", k.as_str()),
903 Some(CurrentDecl::TaggedUnion(k)) => format!("tagged_union `{}`", k.as_str()),
904 Some(CurrentDecl::Callback(k)) => {
905 let args: Vec<&str> = k.iter().map(|t| t.as_str()).collect();
906 format!("callback `impl Fn({})`", args.join(", "))
907 }
908 Some(CurrentDecl::Function(i)) => format!("function `{i}`"),
909 Some(CurrentDecl::Convert(k)) => format!("convert `{k}`"),
910 }
911}