1use prebindgen_registry::{Building, Conversions, Crossing, RegistryBuilder};
2
3use super::{builder::callback_fn_type, *};
4
5impl CbindgenBuilder {
11 pub(crate) fn in_opaque_handle(&self, ty: &TypeRef) -> Option<ConverterImpl<()>> {
14 let key = ty.key();
15 if !self.opaque.contains_key(&key) {
16 return None;
17 }
18 let name = Self::in_name_of(&ty.key());
19 let c_struct = self.c_type_ident(&ty.key());
20 let src = self.src_ty_of(&ty.key());
21 let short = type_short(&ty.key());
22 let null_msg = format!("null {short} handle passed by value");
23 let function: syn::ItemFn = syn::parse_quote!(
24 #[allow(non_snake_case, unused_variables, dead_code)]
25 pub(crate) unsafe fn #name(
26 v: *mut #c_struct,
27 ) -> ::core::result::Result<#src, ::std::string::String> {
28 if v.is_null() {
29 return ::core::result::Result::Err(
30 ::std::string::String::from(#null_msg),
31 );
32 }
33 ::core::result::Result::Ok(*::std::boxed::Box::from_raw(v as *mut #src))
34 }
35 );
36 Some(ConverterImpl {
37 subs: vec![],
38 destination: syn::parse_quote!(*mut #c_struct),
39 function,
40 pre_stages: vec![],
41 niches: Niches::empty(),
42 metadata: (),
43 })
44 }
45
46 pub(crate) fn in_data_struct(
48 &self,
49 ty: &TypeRef,
50 r: &impl Conversions<()>,
51 ) -> Option<ConverterImpl<()>> {
52 let key = ty.key();
53 if !self.data.contains_key(&key) {
54 return None;
55 }
56 let fields = self.struct_fields(r, &ty.key())?;
57 let name = Self::in_name_of(&ty.key());
58 let c_struct = self.c_type_ident(&ty.key());
59 let src = self.src_ty_of(&ty.key());
60 let mut inits: Vec<TokenStream> = Vec::new();
61 let mut subs: Vec<TypeKey> = Vec::new();
62 let mut fallible = false;
63 for (fname, fty) in &fields {
64 if r_is_string(fty) {
65 inits.push(quote!(#fname: if v.#fname.is_null() {
66 ::std::string::String::new()
67 } else {
68 ::std::ffi::CStr::from_ptr(v.#fname).to_string_lossy().into_owned()
69 }));
70 } else if self.tagged_unions.contains_key(&fty.key()) {
71 let conv = Self::in_name_of(&fty.key());
75 subs.push(fty.key());
76 fallible = true;
77 inits.push(quote!(#fname: #conv(v.#fname)?));
78 } else if r_is_bool(fty) {
79 let read = bool_in_expr(quote!(v.#fname));
83 inits.push(quote!(#fname: #read));
84 } else {
85 inits.push(quote!(#fname: v.#fname));
86 }
87 }
88 let function: syn::ItemFn = if fallible {
91 syn::parse_quote!(
92 #[allow(non_snake_case, unused_variables, dead_code)]
93 pub(crate) unsafe fn #name(
94 v: #c_struct,
95 ) -> ::core::result::Result<#src, ::std::string::String> {
96 ::core::result::Result::Ok(#src { #(#inits),* })
97 }
98 )
99 } else {
100 syn::parse_quote!(
101 #[allow(non_snake_case, unused_variables, dead_code)]
102 pub(crate) unsafe fn #name(v: #c_struct) -> #src {
103 #src { #(#inits),* }
104 }
105 )
106 };
107 Some(ConverterImpl {
108 subs,
109 destination: syn::parse_quote!(#c_struct),
110 function,
111 pre_stages: vec![],
112 niches: Niches::empty(),
113 metadata: (),
114 })
115 }
116
117 fn nullable_owned_ptr_fields(
124 &self,
125 registry: &impl Conversions<()>,
126 key: &TypeKey,
127 ) -> Option<Vec<syn::Ident>> {
128 let cfg = self.value_opaque.get(key)?;
129 if !cfg.generate_mirror {
130 return None;
131 }
132 let mut idents = Vec::new();
133 for (fname, fty) in self.struct_fields(registry, key)? {
134 if matches!(self.mirror_field_wire(fty), Some(syn::Type::Ptr(_))) {
137 fty.optional_inner()?;
139 idents.push(fname);
140 }
141 }
142 Some(idents)
143 }
144
145 fn value_opaque_writeback(
154 &self,
155 registry: &impl Conversions<()>,
156 key: &TypeKey,
157 slot: &syn::Ident,
158 ) -> Option<TokenStream> {
159 let cfg = self.value_opaque.get(key)?;
160 let opaque = &cfg.opaque;
161 if cfg.generate_mirror {
162 match self.nullable_owned_ptr_fields(registry, key) {
163 Some(fields) if fields.is_empty() => None,
165 Some(fields) => Some(quote!(#( (*#slot).#fields = ::core::ptr::null_mut(); )*)),
167 None => Some(
169 quote!(::core::ptr::write(#slot, <#opaque as ::prebindgen_c_runtime::Gravestone>::gravestone());),
170 ),
171 }
172 } else {
173 match cfg.kind {
175 OpaqueKind::Owned => Some(
176 quote!(::core::ptr::write(#slot, <#opaque as ::prebindgen_c_runtime::Gravestone>::gravestone());),
177 ),
178 OpaqueKind::Data => None,
179 }
180 }
181 }
182
183 fn mirror_needs_gravestone_impl(&self, registry: &Registry<()>, key: &TypeKey) -> bool {
189 match self.value_opaque.get(key) {
190 Some(cfg) if cfg.generate_mirror => {
191 self.nullable_owned_ptr_fields(registry, key).is_none()
192 }
193 _ => false,
194 }
195 }
196
197 pub(crate) fn in_value_opaque(
215 &self,
216 ty: &TypeRef,
217 registry: &impl Conversions<()>,
218 ) -> Option<ConverterImpl<()>> {
219 let opaque = self.value_opaque_ty_of(&ty.key())?.clone();
220 let name = Self::in_name_of(&ty.key());
221 let src = self.src_ty_of(&ty.key());
222 let short = type_short(&ty.key());
223 let null_msg = format!("null {short} value passed by value");
224 let writeback = self.value_opaque_writeback(registry, &ty.key(), &format_ident!("v"));
227 let function: syn::ItemFn = syn::parse_quote!(
228 #[allow(non_snake_case, unused_variables, dead_code)]
229 pub(crate) unsafe fn #name(
230 v: *mut #opaque,
231 ) -> ::core::result::Result<#src, ::std::string::String> {
232 if v.is_null() {
233 return ::core::result::Result::Err(
234 ::std::string::String::from(#null_msg),
235 );
236 }
237 let __live = <#opaque as ::prebindgen_c_runtime::Transmute>::into_rust(
238 ::core::ptr::read(v),
239 );
240 #writeback
241 ::core::result::Result::Ok(__live)
242 }
243 );
244 Some(ConverterImpl {
245 subs: vec![],
246 destination: syn::parse_quote!(*mut #opaque),
247 function,
248 pre_stages: vec![],
249 niches: Niches::empty(),
250 metadata: (),
251 })
252 }
253
254 pub(crate) fn in_enum(
274 &self,
275 ty: &TypeRef,
276 r: &impl Conversions<()>,
277 ) -> Option<ConverterImpl<()>> {
278 let key = ty.key();
279 if !self.enums.contains_key(&key) {
280 return None;
281 }
282 let e = unit_enum(r, &ty.key())?;
283 let name = Self::in_name_of(&ty.key());
284 let cname = self.c_type_ident(&ty.key());
285 let src = self.src_ty_of(&ty.key());
286 let cname_str = cname.to_string();
287 let arms = e.values.iter().map(|v| {
288 let id = &v.name;
289 quote!(
290 if __raw == #cname::#id as ::core::ffi::c_int {
291 return ::core::result::Result::Ok(#src::#id);
292 }
293 )
294 });
295 let bad_msg = format!("invalid discriminant {{}} for `{cname_str}`");
296 let size_msg = format!("`{cname_str}`: a #[repr(C)] enum must have the size of a C `int`");
297 let align_msg =
298 format!("`{cname_str}`: a #[repr(C)] enum must have the alignment of a C `int`");
299 let function: syn::ItemFn = syn::parse_quote!(
300 #[allow(non_snake_case, unused_variables, dead_code)]
301 pub(crate) unsafe fn #name(
302 v: ::core::mem::MaybeUninit<#cname>,
303 ) -> ::core::result::Result<#src, ::std::string::String> {
304 const _: () = {
305 assert!(
306 ::core::mem::size_of::<#cname>()
307 == ::core::mem::size_of::<::core::ffi::c_int>(),
308 #size_msg
309 );
310 assert!(
311 ::core::mem::align_of::<#cname>()
312 == ::core::mem::align_of::<::core::ffi::c_int>(),
313 #align_msg
314 );
315 };
316 let __raw: ::core::ffi::c_int =
317 ::core::ptr::read(v.as_ptr() as *const ::core::ffi::c_int);
318 #(#arms)*
319 ::core::result::Result::Err(::std::format!(#bad_msg, __raw))
320 }
321 );
322 Some(ConverterImpl {
323 subs: vec![],
324 destination: syn::parse_quote!(::core::mem::MaybeUninit<#cname>),
325 function,
326 pre_stages: vec![],
327 niches: Niches::empty(),
328 metadata: (),
329 })
330 }
331
332 pub(crate) fn in_string(&self, ty: &TypeRef) -> Option<ConverterImpl<()>> {
334 if !r_is_string(ty) {
335 return None;
336 }
337 let name = Self::in_name_of(&ty.key());
338 let function: syn::ItemFn = syn::parse_quote!(
339 #[allow(non_snake_case, unused_variables, dead_code)]
340 pub(crate) unsafe fn #name(
341 v: *const ::core::ffi::c_char,
342 ) -> ::core::result::Result<::std::string::String, ::std::string::String> {
343 if v.is_null() {
344 return ::core::result::Result::Err(
345 ::std::string::String::from("null pointer passed for String argument"),
346 );
347 }
348 match ::std::ffi::CStr::from_ptr(v).to_str() {
349 ::core::result::Result::Ok(s) => {
350 ::core::result::Result::Ok(s.to_owned())
351 }
352 ::core::result::Result::Err(_) => {
353 ::core::result::Result::Err(
354 ::std::string::String::from("invalid UTF-8 in String argument"),
355 )
356 }
357 }
358 }
359 );
360 Some(ConverterImpl {
361 subs: vec![],
362 destination: syn::parse_quote!(*const ::core::ffi::c_char),
363 function,
364 pre_stages: vec![],
365 niches: Niches::empty(),
366 metadata: (),
367 })
368 }
369
370 pub(crate) fn in_str(&self, ty: &TypeRef) -> Option<ConverterImpl<()>> {
373 if !r_is_str(ty) {
374 return None;
375 }
376 let name = Self::in_name_of(&ty.key());
377 let function: syn::ItemFn = syn::parse_quote!(
378 #[allow(non_snake_case, dead_code, unused_variables)]
379 pub(crate) fn #name() {}
380 );
381 Some(ConverterImpl {
382 subs: vec![],
383 destination: syn::parse_quote!(*const ::core::ffi::c_char),
384 function,
385 pre_stages: vec![],
386 niches: Niches::empty(),
387 metadata: (),
388 })
389 }
390
391 pub(crate) fn in_bool(&self, ty: &TypeRef) -> Option<ConverterImpl<()>> {
398 if !r_is_bool(ty) {
399 return None;
400 }
401 let name = Self::in_name_of(&ty.key());
402 let wire = bool_wire();
403 let read = bool_in_expr(quote!(v));
404 let function: syn::ItemFn = syn::parse_quote!(
405 #[allow(non_snake_case, unused_variables, dead_code)]
406 pub(crate) unsafe fn #name(v: #wire) -> bool {
407 #read
408 }
409 );
410 Some(ConverterImpl {
411 subs: vec![],
412 destination: wire,
413 function,
414 pre_stages: vec![],
415 niches: Niches::empty(),
416 metadata: (),
417 })
418 }
419
420 pub(crate) fn in_scalar(&self, ty: &TypeRef) -> Option<ConverterImpl<()>> {
423 if !r_is_scalar(ty) || r_is_bool(ty) {
424 return None;
425 }
426 let name = Self::in_name_of(&ty.key());
427 let spelled = scalar_ty(ty)?;
429 let function: syn::ItemFn = syn::parse_quote!(
430 #[allow(non_snake_case, unused_variables, dead_code)]
431 pub(crate) fn #name(v: #spelled) -> #spelled {
432 v
433 }
434 );
435 Some(ConverterImpl {
436 subs: vec![],
437 destination: spelled.clone(),
438 function,
439 pre_stages: vec![],
440 niches: Niches::empty(),
441 metadata: (),
442 })
443 }
444}
445
446impl CbindgenBuilder {
450 fn prereq_alloc_free(&self, registry: &Registry<()>, produces_array: bool) -> Vec<syn::Item> {
454 let mut items: Vec<syn::Item> = Vec::new();
455 if !(self.needs_free(registry) || produces_array) {
456 return items;
457 }
458 let free_ident = match &self.free_fn {
459 Some(name) => format_ident!("{}", name),
460 None => panic!(
461 "Cbindgen: the generated layer hands `char*` string memory to C \
462 (a `String` return or a `String` data-struct field) but no \
463 memory-freeing function is declared — add \
464 `.free_memory_function(\"z_free\")`"
465 ),
466 };
467 items.push(syn::parse_quote!(
469 extern "C" {
470 fn malloc(size: usize) -> *mut ::core::ffi::c_void;
471 fn free(ptr: *mut ::core::ffi::c_void);
472 }
473 ));
474 items.push(syn::parse_quote!(
477 #[allow(non_snake_case, dead_code)]
478 pub(crate) fn __cbg_alloc_cstr(s: ::std::string::String) -> *mut ::core::ffi::c_char {
479 let c = ::std::ffi::CString::new(s).unwrap_or_default();
480 let bytes = c.as_bytes_with_nul();
481 unsafe {
482 let p = malloc(bytes.len()) as *mut u8;
483 if p.is_null() {
484 return ::core::ptr::null_mut();
485 }
486 ::core::ptr::copy_nonoverlapping(bytes.as_ptr(), p, bytes.len());
487 p as *mut ::core::ffi::c_char
488 }
489 }
490 ));
491 items.push(syn::parse_quote!(
494 #[no_mangle]
495 #[allow(non_snake_case, unused_variables)]
496 pub unsafe extern "C" fn #free_ident(p: *mut ::core::ffi::c_void) {
497 free(p);
498 }
499 ));
500 items
501 }
502
503 fn prereq_array_builder(&self, produces_array: bool) -> Vec<syn::Item> {
507 let mut items: Vec<syn::Item> = Vec::new();
508 if !produces_array {
509 return items;
510 }
511 items.push(syn::parse_quote!(
512 #[allow(non_snake_case, dead_code)]
513 pub(crate) unsafe fn __cbg_alloc_array<W>(v: ::std::vec::Vec<W>) -> (*mut W, usize) {
514 let n = v.len();
515 if n == 0 {
516 return (::core::ptr::null_mut(), 0);
517 }
518 let p = malloc(n.wrapping_mul(::core::mem::size_of::<W>())) as *mut W;
519 if p.is_null() {
520 return (::core::ptr::null_mut(), 0);
521 }
522 for (i, e) in v.into_iter().enumerate() {
523 ::core::ptr::write(p.add(i), e);
524 }
525 (p, n)
526 }
527 ));
528 items
529 }
530
531 fn prereq_opaque_handles(&self, registry: &Registry<()>) -> Vec<syn::Item> {
534 let mut items: Vec<syn::Item> = Vec::new();
535 for (key, _cfg) in sorted_by_key(&self.opaque) {
536 let Some(reading) = registry.reading(key) else {
539 continue;
540 };
541 if registry.input_entry(&reading).is_none() && registry.output_entry(&reading).is_none()
542 {
543 continue;
544 }
545 let c_struct = self.c_type_ident(&reading.key());
546 items.push(syn::parse_quote!(
549 #[repr(C)]
550 #[allow(non_camel_case_types)]
551 pub struct #c_struct {
552 _private: [u8; 0],
553 }
554 ));
555 let src = self.src_ty_of(&reading.key());
556 let drop_ident = self.destructor_symbol(&reading.key());
557 items.push(syn::parse_quote!(
558 #[no_mangle]
559 #[allow(non_snake_case, unused_variables)]
560 pub unsafe extern "C" fn #drop_ident(this_: *mut #c_struct) {
561 if !this_.is_null() {
562 drop(::std::boxed::Box::from_raw(this_ as *mut #src));
563 }
564 }
565 ));
566 }
567 items
568 }
569
570 fn prereq_data_structs(&self, registry: &Registry<()>) -> Vec<syn::Item> {
574 let mut items: Vec<syn::Item> = Vec::new();
575 for (key, _cfg) in sorted_by_key(&self.data) {
576 let Some(reading) = registry.reading(key) else {
577 continue;
578 };
579 if registry.input_entry(&reading).is_none() && registry.output_entry(&reading).is_none()
580 {
581 continue;
582 }
583 let Some(fields) = self.struct_fields(registry, &reading.key()) else {
584 continue;
585 };
586 let c_struct = self.c_type_ident(&reading.key());
587 let mut field_defs: Vec<TokenStream> = Vec::new();
588 for (fname, fty) in &fields {
589 let wire = self.data_field_wire(fty).unwrap_or_else(|| {
590 panic!(
591 "Cbindgen: field `{}` of data struct `{}` has unsupported type `{}`",
592 fname,
593 type_short(&reading.key()),
594 fty
595 )
596 });
597 field_defs.push(quote!(pub #fname: #wire));
598 }
599 items.push(syn::parse_quote!(
600 #[repr(C)]
601 #[allow(non_camel_case_types)]
602 pub struct #c_struct {
603 #(#field_defs,)*
604 }
605 ));
606 }
607 items
608 }
609
610 fn prereq_value_opaque(&self, registry: &Registry<()>) -> Vec<syn::Item> {
616 let mut items: Vec<syn::Item> = Vec::new();
617 let takeable_keys = self.takeable_type_keys();
618 let mut vo: Vec<(&TypeKey, &ValueOpaqueCfg)> = self.value_opaque.iter().collect();
619 vo.sort_by(|a, b| a.0.as_str().cmp(b.0.as_str()));
620 for (key, cfg) in vo {
621 let Some(reading) = registry.reading(key) else {
622 continue;
623 };
624 if registry.input_entry(&reading).is_none() && registry.output_entry(&reading).is_none()
625 {
626 continue;
627 }
628 let src = self.src_ty_of(&reading.key());
629 let opaque = &cfg.opaque;
630 if cfg.generate_mirror {
636 let mirror_ident = self.c_type_ident(&reading.key());
637 let fields = self
638 .struct_fields(registry, &reading.key())
639 .unwrap_or_else(|| {
640 panic!(
641 "Cbindgen::repr_c_struct: `{}` is not a named struct",
642 type_short(&reading.key())
643 )
644 });
645 let restricted = self.restricted_validity_fields(registry, &reading.key());
658 if !restricted.is_empty() && !cfg.assume_c_field_validity {
659 let listed: Vec<String> = restricted
660 .iter()
661 .map(|(fname, reason)| format!(" `{fname}`: {reason}"))
662 .collect();
663 panic!(
664 "Cbindgen::repr_c_struct: `{}` crosses C's memory by whole-struct \
665 reinterpret, but these fields have restricted-validity Rust types:\n\
666 {}\n\
667 A C caller can write a byte outside those domains, and the reinterpret \
668 materialises it with no hook to normalise or validate it first (#170, \
669 #158). Move the field to a `data_struct` (per-field wires), pass it as \
670 a separate parameter, or widen it to an integer. If this binding's C \
671 side is trusted to write only in-domain bytes — or never hands the \
672 mirror back at all — acknowledge it with `.assume_c_field_validity()`.",
673 type_short(&reading.key()),
674 listed.join("\n"),
675 );
676 }
677 let field_defs: Vec<TokenStream> = fields
678 .iter()
679 .map(|(fname, fty)| {
680 let wire = self.mirror_field_wire(fty).unwrap_or_else(|| {
681 panic!(
682 "Cbindgen::repr_c_struct: field `{}` of `{}` has unsupported \
683 type `{}` (expected a scalar, a declared `enum_type`, or an \
684 opaque pointer `Option<Box<T>>`/`Box<T>` with `T` an `opaque_ptr`)",
685 fname,
686 type_short(&reading.key()),
687 fty
688 )
689 });
690 quote!(pub #fname: #wire)
691 })
692 .collect();
693 items.push(syn::parse_quote!(
694 #[repr(C)]
695 #[allow(non_camel_case_types)]
696 pub struct #mirror_ident {
697 #(#field_defs,)*
698 }
699 ));
700 if self.mirror_needs_gravestone_impl(registry, &reading.key()) {
705 items.push(syn::parse_quote!(
706 impl ::prebindgen_c_runtime::Gravestone for #mirror_ident {
707 #[inline]
708 fn rust_gravestone() -> #src {
709 <#src as ::core::default::Default>::default()
710 }
711 }
712 ));
713 }
714 }
715 items.push(syn::parse_quote!(
717 const _: () = {
718 assert!(
719 ::core::mem::size_of::<#src>() == ::core::mem::size_of::<#opaque>(),
720 "value_opaque: Rust type and opaque counterpart differ in size"
721 );
722 assert!(
723 ::core::mem::align_of::<#src>() == ::core::mem::align_of::<#opaque>(),
724 "value_opaque: Rust type and opaque counterpart differ in alignment"
725 );
726 };
727 ));
728 items.push(syn::parse_quote!(
732 impl ::prebindgen_c_runtime::Transmute for #opaque {
733 type Rust = #src;
734 #[inline]
735 fn from_rust(value: Self::Rust) -> Self {
736 let __v = ::core::mem::ManuallyDrop::new(value);
737 unsafe {
738 ::core::ptr::read(&*__v as *const Self::Rust as *const Self)
739 }
740 }
741 #[inline]
742 fn into_rust(self) -> Self::Rust {
743 let __v = ::core::mem::ManuallyDrop::new(self);
744 unsafe {
745 ::core::ptr::read(&*__v as *const Self as *const Self::Rust)
746 }
747 }
748 #[inline]
749 fn as_rust(&self) -> &Self::Rust {
750 unsafe { &*(self as *const Self as *const Self::Rust) }
751 }
752 #[inline]
753 fn as_rust_mut(&mut self) -> &mut Self::Rust {
754 unsafe { &mut *(self as *mut Self as *mut Self::Rust) }
755 }
756 }
757 ));
758 let drop_ident = self.destructor_symbol(&reading.key());
759 items.push(syn::parse_quote!(
763 #[no_mangle]
764 #[allow(non_snake_case, unused_variables)]
765 pub unsafe extern "C" fn #drop_ident(this_: *mut #opaque) {
766 if !this_.is_null() {
767 ::core::ptr::drop_in_place(
768 <#opaque as ::prebindgen_c_runtime::Transmute>::as_rust_mut(&mut *this_),
769 );
770 }
771 }
772 ));
773 if takeable_keys.contains(key) {
780 let take_ident = self.take_symbol(&reading.key());
781 let writeback =
784 self.value_opaque_writeback(registry, &reading.key(), &format_ident!("src"));
785 items.push(syn::parse_quote!(
786 #[no_mangle]
787 #[allow(non_snake_case, unused_variables)]
788 pub unsafe extern "C" fn #take_ident(
789 dst: *mut #opaque,
790 src: *mut #opaque,
791 ) {
792 if dst.is_null() || src.is_null() {
793 return;
794 }
795 ::core::ptr::write(dst, ::core::ptr::read(src));
796 #writeback
797 }
798 ));
799 }
800 }
801 items
802 }
803
804 fn prereq_enums(
822 &self,
823 registry: &Registry<()>,
824 emit: &prebindgen_registry::Emit,
825 ) -> Vec<syn::Item> {
826 let mut items: Vec<syn::Item> = Vec::new();
827 for (key, _cfg) in sorted_by_key(&self.enums) {
828 let Some(reading) = registry.reading(key) else {
829 continue;
830 };
831 if registry.input_entry(&reading).is_none() && registry.output_entry(&reading).is_none()
832 {
833 continue;
834 }
835 let Some(e) = unit_enum(registry, &reading.key()) else {
836 continue;
837 };
838 let cname = self.c_type_ident(&reading.key());
839 let variants = e.values.iter().map(|v| {
843 let id = &v.name;
844 match emit.discriminant(v) {
845 Some(expr) => quote!(#id = #expr),
846 None => quote!(#id),
847 }
848 });
849 items.push(syn::parse_quote!(
850 #[repr(C)]
851 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
852 #[allow(non_camel_case_types)]
853 pub enum #cname {
854 #(#variants),*
855 }
856 ));
857 }
858 items
859 }
860
861 fn prereq_tagged_unions(
873 &self,
874 registry: &Registry<()>,
875 emit: &prebindgen_registry::Emit,
876 ) -> Vec<syn::Item> {
877 let mut items: Vec<syn::Item> = Vec::new();
878 for (key, _cfg) in sorted_by_key(&self.tagged_unions) {
879 let Some(reading) = registry.reading(key) else {
880 continue;
881 };
882 if registry.input_entry(&reading).is_none() && registry.output_entry(&reading).is_none()
883 {
884 continue;
885 }
886 let Some(e) = payload_enum(registry, &reading.key()) else {
887 continue;
888 };
889 let cname = self.c_type_ident(&reading.key());
890
891 let mut variant_defs: Vec<TokenStream> = Vec::new();
892 let mut drop_arms: Vec<TokenStream> = Vec::new();
895 for a in &e.alternatives {
896 let vident = &a.name;
897 let wires: Vec<syn::Type> = a
898 .fields
899 .iter()
900 .map(|f| self.payload_wire_of(&reading.key(), vident, f, registry))
901 .collect();
902 let defs: Vec<TokenStream> = a
906 .fields
907 .iter()
908 .zip(&wires)
909 .map(|(f, w)| f.bind(w))
910 .collect();
911 variant_defs.push(emit.shape(a, quote!(#vident), &defs));
912
913 let owning: Vec<(usize, &Field, &syn::Type)> = a
915 .fields
916 .iter()
917 .zip(&wires)
918 .enumerate()
919 .filter(|(_, (f, w))| self.payload_wire_owns(&f.ty, w, registry))
920 .map(|(i, (f, w))| (i, f, w))
921 .collect();
922 if owning.is_empty() {
923 continue;
924 }
925 let binds: Vec<syn::Ident> = (0..a.fields.len())
926 .map(|i| format_ident!("__f{}", i))
927 .collect();
928 let parts: Vec<TokenStream> = a
929 .fields
930 .iter()
931 .zip(&binds)
932 .map(|(f, b)| f.bind(b))
933 .collect();
934 let pattern = emit.shape(a, quote!(#cname::#vident), &parts);
935 let frees = owning.iter().map(|(i, f, _)| {
936 let b = &binds[*i];
937 self.payload_free_stmt(&f.ty, b, registry)
938 });
939 drop_arms.push(quote!(#pattern => { #(#frees)* }));
940 }
941
942 items.push(syn::parse_quote!(
943 #[repr(C)]
944 #[allow(non_camel_case_types)]
945 pub enum #cname {
946 #(#variant_defs),*
947 }
948 ));
949
950 if self.tagged_union_has_drop(&reading, registry) {
954 debug_assert!(!drop_arms.is_empty(), "has_drop implies an owning arm");
955 let drop_ident = self.destructor_symbol(&reading.key());
956 let tag_guard = self.tag_guard(
964 &cname,
965 e.alternatives.len(),
966 quote!((*this_)),
967 quote!(return;),
968 );
969 items.push(syn::parse_quote!(
970 #[no_mangle]
971 #[allow(non_snake_case, unused_variables)]
972 pub unsafe extern "C" fn #drop_ident(
973 this_: *mut ::core::mem::MaybeUninit<#cname>,
974 ) {
975 if this_.is_null() {
976 return;
977 }
978 #tag_guard
979 match (*this_).assume_init_mut() {
980 #(#drop_arms)*
981 _ => {}
982 }
983 }
984 ));
985 }
986 }
987 items
988 }
989
990 fn payload_wire_of(
993 &self,
994 key: &TypeKey,
995 variant: &syn::Ident,
996 field: &Field,
997 registry: &Registry<()>,
998 ) -> syn::Type {
999 self.payload_field_wire(&field.ty, registry)
1000 .unwrap_or_else(|reason| {
1001 panic!(
1002 "Cbindgen::tagged_union: payload `{}::{}{}` of type `{}` cannot cross: {}",
1003 type_short(key),
1004 variant,
1005 match &field.name {
1006 Some(n) => format!(".{n}"),
1007 None => String::new(),
1008 },
1009 field.ty,
1010 reason,
1011 )
1012 })
1013 }
1014
1015 fn payload_free_stmt(
1021 &self,
1022 fty: &TypeRef,
1023 binding: &syn::Ident,
1024 registry: &Registry<()>,
1025 ) -> TokenStream {
1026 if r_is_string(fty) {
1027 return quote!(
1028 free(*#binding as *mut ::core::ffi::c_void);
1029 *#binding = ::core::ptr::null_mut();
1030 );
1031 }
1032 let owning = self.owning_data_struct_fields(fty, registry);
1039 if !owning.is_empty() {
1040 let frees = owning.iter().map(|(fname, fty)| {
1041 if r_is_string(fty) {
1042 quote!(
1043 free((*#binding).#fname as *mut ::core::ffi::c_void);
1044 (*#binding).#fname = ::core::ptr::null_mut();
1045 )
1046 } else if self.tagged_union_has_drop(fty, registry) {
1047 let drop_ident = self.destructor_symbol(&fty.key());
1054 quote!(#drop_ident(&mut (*#binding).#fname);)
1055 } else {
1056 panic!(
1061 "Cbindgen: data-struct field `{}` of type `{}` is owning but has no \
1062 release form (expected a `String` or a declared `tagged_union`)",
1063 fname, fty,
1064 )
1065 }
1066 });
1067 return quote!(#(#frees)*);
1068 }
1069 let src_inner = self.src_ty_of(&r_boxed_inner(fty).unwrap_or(fty).key());
1070 quote!(
1071 if !(*#binding).is_null() {
1072 drop(::std::boxed::Box::from_raw(*#binding as *mut #src_inner));
1073 *#binding = ::core::ptr::null_mut();
1074 }
1075 )
1076 }
1077
1078 pub(crate) fn in_tagged_union(
1096 &self,
1097 ty: &TypeRef,
1098 r: &impl Conversions<()>,
1099 emit: &prebindgen_registry::Emit,
1100 ) -> Option<ConverterImpl<()>> {
1101 let key = ty.key();
1102 if !self.tagged_unions.contains_key(&key) {
1103 return None;
1104 }
1105 let e = payload_enum(r, &key)?;
1106 let name = Self::in_name_of(&ty.key());
1107 let cname = self.c_type_ident(&ty.key());
1108 let src = self.src_ty_of(&ty.key());
1109 for a in &e.alternatives {
1116 for f in &a.fields {
1117 if self.payload_needs_converter(&f.ty) && r.input_entry(&f.ty).is_none() {
1118 return None;
1119 }
1120 }
1121 }
1122 let mut subs: Vec<TypeKey> = Vec::new();
1123 let arms: Vec<TokenStream> = e
1124 .alternatives
1125 .iter()
1126 .map(|a| {
1127 let vident = &a.name;
1128 let binds: Vec<syn::Ident> = (0..a.fields.len())
1129 .map(|i| format_ident!("__f{}", i))
1130 .collect();
1131 let parts: Vec<TokenStream> = a
1132 .fields
1133 .iter()
1134 .zip(&binds)
1135 .map(|(f, b)| f.bind(b))
1136 .collect();
1137 let from = emit.shape(a, quote!(#cname::#vident), &parts);
1138 let exprs: Vec<TokenStream> = a
1139 .fields
1140 .iter()
1141 .zip(&binds)
1142 .map(|(f, b)| {
1143 if self.payload_needs_converter(&f.ty) {
1150 subs.push(f.ty.key());
1151 }
1152 self.payload_in_expr(&f.ty, b, r)
1153 })
1154 .collect();
1155 let inits: Vec<TokenStream> = a
1156 .fields
1157 .iter()
1158 .zip(&exprs)
1159 .map(|(f, e)| f.bind(e))
1160 .collect();
1161 let to = emit.shape(a, quote!(#src::#vident), &inits);
1162 quote!(#from => #to,)
1163 })
1164 .collect();
1165 let bad_msg = format!(
1166 "invalid tag {{}} for `{cname}` (expected 0..{})",
1167 e.alternatives.len()
1168 );
1169 let tag_guard = self.tag_guard(
1170 &cname,
1171 e.alternatives.len(),
1172 quote!(v),
1173 quote!(return ::core::result::Result::Err(::std::format!(#bad_msg, __tag));),
1174 );
1175 let function: syn::ItemFn = syn::parse_quote!(
1176 #[allow(non_snake_case, unused_variables, dead_code)]
1177 pub(crate) unsafe fn #name(
1178 v: ::core::mem::MaybeUninit<#cname>,
1179 ) -> ::core::result::Result<#src, ::std::string::String> {
1180 #tag_guard
1181 let v = v.assume_init();
1182 ::core::result::Result::Ok(match v { #(#arms)* })
1183 }
1184 );
1185 Some(ConverterImpl {
1186 subs,
1187 destination: syn::parse_quote!(::core::mem::MaybeUninit<#cname>),
1188 function,
1189 pre_stages: vec![],
1190 niches: Niches::empty(),
1191 metadata: (),
1192 })
1193 }
1194
1195 fn tag_guard(
1206 &self,
1207 cname: &syn::Ident,
1208 variants: usize,
1209 slot: TokenStream,
1210 on_bad: TokenStream,
1211 ) -> TokenStream {
1212 let n = variants as i64;
1213 let bounds_msg = format!(
1214 "`{cname}`: a #[repr(C)] enum with payload variants must be at least as large as \
1215 its C `int` discriminant"
1216 );
1217 quote!(
1218 const _: () = {
1219 assert!(
1220 ::core::mem::size_of::<#cname>()
1221 >= ::core::mem::size_of::<::core::ffi::c_int>(),
1222 #bounds_msg
1223 );
1224 };
1225 let __tag: ::core::ffi::c_int =
1226 ::core::ptr::read(#slot.as_ptr() as *const ::core::ffi::c_int);
1227 if !((__tag as i64) >= 0 && (__tag as i64) < #n) {
1228 #on_bad
1229 }
1230 )
1231 }
1232
1233 pub(crate) fn out_tagged_union(
1238 &self,
1239 ty: &TypeRef,
1240 r: &impl Conversions<()>,
1241 emit: &prebindgen_registry::Emit,
1242 ) -> Option<ConverterImpl<()>> {
1243 let key = ty.key();
1244 if !self.tagged_unions.contains_key(&key) {
1245 return None;
1246 }
1247 let e = payload_enum(r, &key)?;
1248 let name = Self::out_name_of(&ty.key());
1249 let cname = self.c_type_ident(&ty.key());
1250 let src = self.src_ty_of(&ty.key());
1251 for a in &e.alternatives {
1253 for f in &a.fields {
1254 if self.payload_needs_converter(&f.ty) && r.output_entry(&f.ty).is_none() {
1255 return None;
1256 }
1257 }
1258 }
1259 let mut subs: Vec<TypeKey> = Vec::new();
1260 let arms: Vec<TokenStream> = e
1261 .alternatives
1262 .iter()
1263 .map(|a| {
1264 let vident = &a.name;
1265 let binds: Vec<syn::Ident> = (0..a.fields.len())
1266 .map(|i| format_ident!("__f{}", i))
1267 .collect();
1268 let parts: Vec<TokenStream> = a
1269 .fields
1270 .iter()
1271 .zip(&binds)
1272 .map(|(f, b)| f.bind(b))
1273 .collect();
1274 let from = emit.shape(a, quote!(#src::#vident), &parts);
1275 let exprs: Vec<TokenStream> = a
1276 .fields
1277 .iter()
1278 .zip(&binds)
1279 .map(|(f, b)| {
1280 if self.payload_needs_converter(&f.ty) {
1281 subs.push(f.ty.key());
1282 }
1283 self.payload_out_expr(&f.ty, b, r)
1284 })
1285 .collect();
1286 let inits: Vec<TokenStream> = a
1287 .fields
1288 .iter()
1289 .zip(&exprs)
1290 .map(|(f, e)| f.bind(e))
1291 .collect();
1292 let to = emit.shape(a, quote!(#cname::#vident), &inits);
1293 quote!(#from => #to,)
1294 })
1295 .collect();
1296 let function: syn::ItemFn = syn::parse_quote!(
1300 #[allow(non_snake_case, unused_variables, dead_code)]
1301 pub(crate) fn #name(v: #src) -> ::core::mem::MaybeUninit<#cname> {
1302 ::core::mem::MaybeUninit::new(match v { #(#arms)* })
1303 }
1304 );
1305 Some(ConverterImpl {
1306 subs,
1307 destination: syn::parse_quote!(::core::mem::MaybeUninit<#cname>),
1308 function,
1309 pre_stages: vec![],
1310 niches: Niches::empty(),
1311 metadata: (),
1312 })
1313 }
1314
1315 fn payload_in_expr(
1319 &self,
1320 fty: &TypeRef,
1321 b: &syn::Ident,
1322 registry: &impl Conversions<()>,
1323 ) -> TokenStream {
1324 if r_is_string(fty) {
1325 return quote!(if #b.is_null() {
1326 ::std::string::String::new()
1327 } else {
1328 ::std::ffi::CStr::from_ptr(#b).to_string_lossy().into_owned()
1329 });
1330 }
1331 if self.enums.contains_key(&fty.key()) {
1332 let conv = Self::in_name_of(&fty.key());
1336 return quote!(#conv(#b)?);
1337 }
1338 if let Some(inner) = self.declared_opaque_payload_inner(fty) {
1344 let src_inner = self.src_ty_of(&inner);
1345 let owned = quote!(*::std::boxed::Box::from_raw(#b as *mut #src_inner));
1346 let null_msg = format!(
1347 "null payload for `{}` (a non-optional handle payload cannot be NULL — the \
1348 union may already have been dropped)",
1349 type_short(&inner)
1350 );
1351 return if fty.optional_inner().is_some() {
1352 quote!(if #b.is_null() {
1353 ::core::option::Option::None
1354 } else {
1355 ::core::option::Option::Some(#owned)
1356 })
1357 } else {
1358 quote!({
1359 if #b.is_null() {
1360 return ::core::result::Result::Err(
1361 ::std::string::String::from(#null_msg),
1362 );
1363 }
1364 #owned
1365 })
1366 };
1367 }
1368 if let Some(inner) = r_boxed_inner(fty) {
1369 let src_inner = self.src_ty_of(&inner.key());
1370 let boxed = quote!(::std::boxed::Box::from_raw(#b as *mut #src_inner));
1371 return if fty.optional_inner().is_some() {
1372 quote!(if #b.is_null() {
1373 ::core::option::Option::None
1374 } else {
1375 ::core::option::Option::Some(#boxed)
1376 })
1377 } else {
1378 let null_msg = format!(
1384 "null payload for `{}` (a non-optional `Box` payload cannot be NULL — the \
1385 union may already have been dropped)",
1386 type_short(&inner.key())
1387 );
1388 quote!({
1389 if #b.is_null() {
1390 return ::core::result::Result::Err(
1391 ::std::string::String::from(#null_msg),
1392 );
1393 }
1394 #boxed
1395 })
1396 };
1397 }
1398 if r_is_bool(fty) {
1401 return bool_in_expr(quote!(#b));
1402 }
1403 if r_is_scalar(fty) {
1405 return quote!(#b);
1406 }
1407 match registry.input_entry(fty) {
1412 Some(entry) => {
1413 let conv = &entry.function.sig.ident;
1414 if returns_result(&entry.function.sig.output) {
1415 quote!(#conv(#b)?)
1416 } else {
1417 quote!(#conv(#b))
1418 }
1419 }
1420 None => quote!(#b),
1421 }
1422 }
1423
1424 fn payload_out_expr(
1427 &self,
1428 fty: &TypeRef,
1429 b: &syn::Ident,
1430 registry: &impl Conversions<()>,
1431 ) -> TokenStream {
1432 if r_is_string(fty) {
1433 return quote!(__cbg_alloc_cstr(#b));
1434 }
1435 if self.enums.contains_key(&fty.key()) {
1436 let conv = Self::out_name_of(&fty.key());
1437 return quote!(::core::mem::MaybeUninit::new(#conv(#b)));
1438 }
1439 if let Some(inner) = self.declared_opaque_payload_inner(fty) {
1442 let c = self.c_type_ident(&inner);
1443 return if fty.optional_inner().is_some() {
1444 quote!(match #b {
1445 ::core::option::Option::Some(__v) => {
1446 ::std::boxed::Box::into_raw(::std::boxed::Box::new(__v)) as *mut #c
1447 }
1448 ::core::option::Option::None => ::core::ptr::null_mut(),
1449 })
1450 } else {
1451 quote!(::std::boxed::Box::into_raw(::std::boxed::Box::new(#b)) as *mut #c)
1452 };
1453 }
1454 if let Some(inner) = r_boxed_inner(fty) {
1455 let c = self.c_type_ident(&inner.key());
1456 return if fty.optional_inner().is_some() {
1457 quote!(match #b {
1458 ::core::option::Option::Some(__b) => {
1459 ::std::boxed::Box::into_raw(__b) as *mut #c
1460 }
1461 ::core::option::Option::None => ::core::ptr::null_mut(),
1462 })
1463 } else {
1464 quote!(::std::boxed::Box::into_raw(#b) as *mut #c)
1465 };
1466 }
1467 if r_is_bool(fty) {
1470 return bool_out_expr(quote!(#b));
1471 }
1472 if r_is_scalar(fty) {
1473 return quote!(#b);
1474 }
1475 match registry.output_entry(fty) {
1480 Some(entry) => {
1481 let conv = entry.function.sig.ident.clone();
1482 quote!(#conv(#b))
1483 }
1484 None => quote!(#b),
1485 }
1486 }
1487
1488 fn prereq_callback_structs(&self, registry: &Registry<()>) -> Vec<syn::Item> {
1494 let mut items: Vec<syn::Item> = Vec::new();
1495 let mut cb_keys: Vec<(&CallbackKey, &CbCfg)> = self.callbacks.iter().collect();
1500 cb_keys.sort_by_key(|(k, _)| self.callback_c_name(k));
1501 for (key, cfg) in cb_keys {
1502 let args: Vec<syn::Type> = cfg.args.clone();
1503 if registry
1506 .reading_of(&callback_fn_type(&args))
1507 .and_then(|tr| registry.input_entry(&tr))
1508 .is_none()
1509 {
1510 continue;
1511 }
1512 let takeable = &self.callbacks.get(key).expect("callback cfg").takeable;
1513 let mut arg_wires: Vec<syn::Type> = Vec::new();
1514 for (i, a) in args.iter().enumerate() {
1515 if let Some((_src, elem_wire)) = self.callback_slice_elem_wire(a) {
1518 arg_wires.push(syn::parse_quote!(*const #elem_wire));
1519 arg_wires.push(syn::parse_quote!(usize));
1520 continue;
1521 }
1522 let wire = registry
1523 .reading_of(a)
1524 .and_then(|tr| registry.output_entry(&tr))
1525 .unwrap_or_else(|| {
1526 panic!(
1527 "Cbindgen: callback arg `{}` has no output converter (declare it \
1528 as a opaque_ptr/data_struct/enum_type)",
1529 a.to_token_stream()
1530 )
1531 })
1532 .destination
1533 .clone();
1534 if takeable.contains(&i) {
1536 arg_wires.push(syn::parse_quote!(*mut #wire));
1537 } else {
1538 arg_wires.push(wire);
1539 }
1540 }
1541 let c_struct = self.callback_c_ident(key);
1542 items.push(syn::parse_quote!(
1543 #[repr(C)]
1544 #[allow(non_camel_case_types)]
1545 pub struct #c_struct {
1546 pub context: *mut ::core::ffi::c_void,
1547 pub call: ::core::option::Option<
1548 unsafe extern "C" fn(#(#arg_wires,)* *mut ::core::ffi::c_void),
1549 >,
1550 pub drop: ::core::option::Option<
1551 unsafe extern "C" fn(*mut ::core::ffi::c_void),
1552 >,
1553 }
1554 ));
1555 }
1556 items
1557 }
1558}
1559
1560impl CbindgenBuilder {
1561 fn collect_local_functions(&self) -> Vec<(syn::ItemFn, String)> {
1568 let mut result = Vec::new();
1569 let mut seen = HashMap::<syn::Ident, String>::new();
1570 for (ident, path, sig) in self.convert_decls.iter().flat_map(|decl| decl.locals()) {
1571 let origin = prebindgen_registry::decl::local_path_prefix(path);
1572 let mut sig = sig.clone();
1573 sig.ident = ident.clone();
1574 let signature = quote!(#origin #sig).to_string();
1575 match seen.get(ident) {
1576 Some(previous) if previous == &signature => continue,
1577 Some(_) => panic!(
1578 "binding-local conversion fn `{ident}` is declared with two different signatures"
1579 ),
1580 None => {
1581 seen.insert(ident.clone(), signature);
1582 }
1583 }
1584 let item: syn::ItemFn = syn::parse_quote!(#sig { unimplemented!() });
1585 result.push((item, origin));
1586 }
1587 result
1588 }
1589
1590 pub fn build(self) -> Result<Cbindgen, prebindgen_registry::WriteRustError> {
1595 let flat = self
1596 .sources
1597 .clone()
1598 .build()
1599 .map_err(prebindgen_registry::ScanError::from)?;
1600 let registry = prebindgen_registry::Registry::builder(flat)?;
1601 self.build_with(registry)
1602 }
1603
1604 pub(crate) fn build_with(
1606 self,
1607 registry: prebindgen_registry::RegistryBuilder<()>,
1608 ) -> Result<Cbindgen, prebindgen_registry::WriteRustError> {
1609 let registry = self
1610 .declare_into(registry)?
1611 .validate_with(&self)?
1612 .convert_with(|crossing, built, emit| self.convert_crossing(crossing, built, emit))?
1613 .build()?;
1614 self.validate_resolved(®istry)
1615 .map_err(|message| prebindgen_registry::ScanError::AdapterInvariant { message })?;
1616 Ok(Cbindgen {
1617 gen: self,
1618 registry,
1619 })
1620 }
1621
1622 fn convert_crossing(
1624 &self,
1625 crossing: &Crossing,
1626 built: &Building<'_, ()>,
1627 emit: &prebindgen_registry::Emit,
1628 ) -> Option<ConverterImpl<()>> {
1629 let (dir, key) = crossing;
1630 let ty = built.reading(key)?;
1636 match dir {
1637 Direction::Input => self.select_input_type(&ty, built, emit).or_else(|| {
1638 let args = ty.callback_args()?;
1641 self.dispatch_fn_input(args, built)
1642 }),
1643 Direction::Output => self.select_output_type(&ty, built, emit),
1644 }
1645 }
1646
1647 pub fn declare_into(
1648 &self,
1649 mut registry: RegistryBuilder<()>,
1650 ) -> Result<RegistryBuilder<()>, prebindgen_registry::ScanError> {
1651 for (item_fn, origin) in self.collect_local_functions() {
1652 registry = registry.local_function(item_fn, origin)?;
1653 }
1654 for ident in self.declared_functions() {
1655 registry = registry.export(&ident);
1656 }
1657 for ident in self.helper_functions() {
1658 registry = registry.reference(&ident);
1659 }
1660 for ty in self.declared_types().into_values() {
1661 registry = registry.export_type(ty);
1662 }
1663 Ok(registry)
1664 }
1665}
1666
1667impl CbindgenBuilder {
1668 fn dispatch_fn_input(
1669 &self,
1670 args: &[TypeRef],
1671 registry: &impl Conversions<()>,
1672 ) -> Option<ConverterImpl<()>> {
1673 let key: CallbackKey = args.iter().map(|a| a.key()).collect();
1674 if !self.callbacks.contains_key(&key) {
1675 return None;
1678 }
1679 let c_struct = self.callback_c_ident(&key);
1680
1681 let takeable = &self.callbacks.get(&key).expect("callback cfg").takeable;
1688 let mut closure_params: Vec<TokenStream> = Vec::new();
1689 let mut encode_stmts: Vec<TokenStream> = Vec::new();
1690 let mut call_args: Vec<TokenStream> = Vec::new();
1691 let mut post_drops: Vec<TokenStream> = Vec::new();
1692 for (i, arg) in args.iter().enumerate() {
1693 if let Some((src_elem, elem_wire)) = self.callback_slice_elem_wire_of(arg) {
1698 let ai = format_ident!("__a{}", i);
1699 closure_params.push(quote!(#ai: &[#src_elem]));
1700 call_args.push(quote!(#ai.as_ptr() as *const #elem_wire));
1701 call_args.push(quote!(#ai.len()));
1702 continue;
1703 }
1704 let entry = registry.output_entry(arg)?;
1705 let conv = entry.function.sig.ident.clone();
1706 let opaque = entry.destination.clone();
1707 let fallible = matches!(
1708 &entry.function.sig.output,
1709 syn::ReturnType::Type(_, ty) if is_result(ty)
1710 );
1711 let src = self.src_ty_deep_of(arg);
1712 let ai = format_ident!("__a{}", i);
1713 let wi = format_ident!("__w{}", i);
1714 closure_params.push(quote!(#ai: #src));
1715 let is_takeable = takeable.contains(&i);
1716 let mut_kw = if is_takeable { quote!(mut) } else { quote!() };
1717 if fallible {
1718 encode_stmts.push(quote!(
1719 let #mut_kw #wi = match #conv(#ai) {
1720 ::core::result::Result::Ok(__v) => __v,
1721 ::core::result::Result::Err(__e) => {
1722 ::core::panic!("cbindgen: callback argument conversion failed: {}", __e)
1723 }
1724 };
1725 ));
1726 } else {
1727 encode_stmts.push(quote!(let #mut_kw #wi = #conv(#ai);));
1728 }
1729 if is_takeable {
1730 call_args.push(quote!(&mut #wi as *mut #opaque));
1731 post_drops.push(
1734 quote!(let _ = <#opaque as ::prebindgen_c_runtime::Transmute>::into_rust(#wi);),
1735 );
1736 } else {
1737 call_args.push(quote!(#wi));
1738 }
1739 }
1740
1741 let fn_ty = callback_fn_type(
1742 &args
1743 .iter()
1744 .map(|a| self.src_ty_deep_of(a))
1745 .collect::<Vec<_>>(),
1746 );
1747 let name = format_ident!("__cbg_in_{}", self.callback_c_name(&key));
1748 let function: syn::ItemFn = syn::parse_quote!(
1749 #[allow(non_snake_case, unused_variables, dead_code)]
1750 pub(crate) unsafe fn #name(c: #c_struct) -> #fn_ty {
1751 struct __Ctx {
1752 context: *mut ::core::ffi::c_void,
1753 drop: ::core::option::Option<unsafe extern "C" fn(*mut ::core::ffi::c_void)>,
1754 }
1755 unsafe impl ::core::marker::Send for __Ctx {}
1756 unsafe impl ::core::marker::Sync for __Ctx {}
1757 impl ::core::ops::Drop for __Ctx {
1758 fn drop(&mut self) {
1759 if let ::core::option::Option::Some(__d) = self.drop {
1760 unsafe { __d(self.context) }
1761 }
1762 }
1763 }
1764 let __call = c.call;
1765 let __ctx = ::std::sync::Arc::new(__Ctx { context: c.context, drop: c.drop });
1766 move |#(#closure_params),*| {
1767 #(#encode_stmts)*
1768 if let ::core::option::Option::Some(__f) = __call {
1769 unsafe { __f(#(#call_args,)* __ctx.context) }
1770 }
1771 #(#post_drops)*
1772 }
1773 }
1774 );
1775 Some(ConverterImpl {
1776 subs: vec![],
1777 destination: syn::parse_quote!(#c_struct),
1778 function,
1779 pre_stages: vec![],
1780 niches: Niches::empty(),
1781 metadata: (),
1782 })
1783 }
1784}
1785
1786impl Prebindgen for CbindgenBuilder {
1787 fn validate(&self, binding: &Building<'_, Self::Metadata>) -> Result<(), String> {
1795 let mut functions = self.declared_functions();
1796 functions.extend(self.helper_functions());
1797 prebindgen_registry::warn_unclaimed(
1798 binding.flat(),
1799 &prebindgen_registry::Claimed {
1800 functions,
1801 types: self.declared_types().into_keys().collect(),
1805 consts: None,
1806 ignored_functions: self.ignored_functions(),
1807 ignored_types: self.ignored_types(),
1808 ..Default::default()
1809 },
1810 );
1811 Ok(())
1812 }
1813
1814 type Metadata = ();
1815
1816 fn source_module(&self) -> Option<&syn::Path> {
1823 self.source_module.as_ref()
1824 }
1825
1826 fn prerequisites(
1832 &self,
1833 registry: &Registry<()>,
1834 emit: &prebindgen_registry::Emit,
1835 ) -> Vec<syn::Item> {
1836 let produces_array = self.produces_array(registry);
1843 let mut items: Vec<syn::Item> = Vec::new();
1844 items.extend(self.prereq_alloc_free(registry, produces_array));
1845 items.extend(self.prereq_array_builder(produces_array));
1846 items.extend(self.prereq_opaque_handles(registry));
1847 items.extend(self.prereq_data_structs(registry));
1848 items.extend(self.prereq_value_opaque(registry));
1849 items.extend(self.prereq_enums(registry, emit));
1850 items.extend(self.prereq_tagged_unions(registry, emit));
1851 items.extend(self.prereq_callback_structs(registry));
1852 items.extend(self.prereq_domain_constants(registry));
1853 items
1854 }
1855
1856 fn on_function(
1859 &self,
1860 f: &prebindgen_registry::flat::Function,
1861 registry: &Registry<()>,
1862 emit: &prebindgen_registry::Emit,
1863 ) -> TokenStream {
1864 self.emit_function_wrapper(f, registry, emit)
1865 }
1866
1867 fn on_struct(
1868 &self,
1869 _s: &prebindgen_registry::flat::Struct,
1870 _registry: &Registry<()>,
1871 _emit: &prebindgen_registry::Emit,
1872 ) -> TokenStream {
1873 TokenStream::new()
1876 }
1877
1878 fn on_variant(
1879 &self,
1880 _v: &prebindgen_registry::flat::Variant,
1881 _registry: &Registry<()>,
1882 _emit: &prebindgen_registry::Emit,
1883 ) -> TokenStream {
1884 TokenStream::new()
1885 }
1886
1887 fn on_enum(
1888 &self,
1889 _e: &prebindgen_registry::flat::Enum,
1890 _registry: &Registry<()>,
1891 _emit: &prebindgen_registry::Emit,
1892 ) -> TokenStream {
1893 TokenStream::new()
1894 }
1895}
1896
1897impl CbindgenBuilder {
1900 pub(crate) fn out_terminal(
1901 &self,
1902 ty: &TypeRef,
1903 _r: &impl Conversions<()>,
1904 emit: &prebindgen_registry::Emit,
1905 ) -> Option<ConverterImpl<()>> {
1906 if matches!(ty.kind(), TypeKind::Unit) {
1911 let function: syn::ItemFn = syn::parse_quote!(
1912 #[allow(non_snake_case, dead_code, unused_variables)]
1913 pub(crate) fn __cbg_out_unit(v: ()) {}
1914 );
1915 return Some(ConverterImpl {
1916 subs: vec![],
1917 destination: syn::parse_quote!(()),
1918 function,
1919 pre_stages: vec![],
1920 niches: Niches::empty(),
1921 metadata: (),
1922 });
1923 }
1924
1925 if r_is_string(ty) && !self.opaque.contains_key(&ty.key()) {
1930 let name = Self::out_name_of(&ty.key());
1931 let function: syn::ItemFn = syn::parse_quote!(
1932 #[allow(non_snake_case, unused_variables, dead_code)]
1933 pub(crate) fn #name(v: ::std::string::String) -> *mut ::core::ffi::c_char {
1934 __cbg_alloc_cstr(v)
1935 }
1936 );
1937 return Some(ConverterImpl {
1938 subs: vec![],
1939 destination: syn::parse_quote!(*mut ::core::ffi::c_char),
1940 function,
1941 pre_stages: vec![],
1942 niches: Niches::empty(),
1943 metadata: (),
1944 });
1945 }
1946
1947 if r_is_scalar(ty) {
1949 let name = Self::out_name_of(&ty.key());
1950 let spelled = scalar_ty(ty)?;
1951 let function: syn::ItemFn = syn::parse_quote!(
1952 #[allow(non_snake_case, unused_variables, dead_code)]
1953 pub(crate) fn #name(v: #spelled) -> #spelled {
1954 v
1955 }
1956 );
1957 return Some(ConverterImpl {
1958 subs: vec![],
1959 destination: spelled.clone(),
1960 function,
1961 pre_stages: vec![],
1962 niches: Niches::empty(),
1963 metadata: (),
1964 });
1965 }
1966
1967 let key = ty.key();
1968
1969 if self.opaque.contains_key(&key) {
1971 let name = Self::out_name_of(&ty.key());
1972 let c_struct = self.c_type_ident(&ty.key());
1973 let src = self.src_ty_of(&ty.key());
1974 let function: syn::ItemFn = syn::parse_quote!(
1975 #[allow(non_snake_case, unused_variables, dead_code)]
1976 pub(crate) fn #name(v: #src) -> *mut #c_struct {
1977 ::std::boxed::Box::into_raw(::std::boxed::Box::new(v)) as *mut #c_struct
1978 }
1979 );
1980 return Some(ConverterImpl {
1981 subs: vec![],
1982 destination: syn::parse_quote!(*mut #c_struct),
1983 function,
1984 pre_stages: vec![],
1985 niches: Niches::empty(),
1986 metadata: (),
1987 });
1988 }
1989
1990 if let Some(msg_fn) = self.opaque_errors.get(&key) {
1995 let name = Self::out_name_of(&ty.key());
1996 let src = self.src_ty_of(&ty.key());
1997 let msg_path = self.src_fn(msg_fn);
1998 let function: syn::ItemFn = syn::parse_quote!(
1999 #[allow(non_snake_case, unused_variables, dead_code)]
2000 pub(crate) fn #name(v: #src) -> *mut ::core::ffi::c_char {
2001 __cbg_alloc_cstr(#msg_path(&v))
2002 }
2003 );
2004 return Some(ConverterImpl {
2005 subs: vec![],
2006 destination: syn::parse_quote!(*mut ::core::ffi::c_char),
2007 function,
2008 pre_stages: vec![],
2009 niches: Niches::empty(),
2010 metadata: (),
2011 });
2012 }
2013
2014 if self.data.contains_key(&key) {
2017 let fields = self.struct_fields(_r, &ty.key())?;
2018 let name = Self::out_name_of(&ty.key());
2019 let c_struct = self.c_type_ident(&ty.key());
2020 let src = self.src_ty_of(&ty.key());
2021 let mut inits: Vec<TokenStream> = Vec::new();
2022 let mut subs: Vec<TypeKey> = Vec::new();
2023 for (fname, fty) in &fields {
2024 if r_is_string(fty) {
2025 inits.push(quote!(#fname: __cbg_alloc_cstr(v.#fname)));
2026 } else if self.tagged_unions.contains_key(&fty.key()) {
2027 let conv = Self::out_name_of(&fty.key());
2028 subs.push(fty.key());
2029 inits.push(quote!(#fname: #conv(v.#fname)));
2030 } else if r_is_bool(fty) {
2031 let wrap = bool_out_expr(quote!(v.#fname));
2032 inits.push(quote!(#fname: #wrap));
2033 } else {
2034 inits.push(quote!(#fname: v.#fname));
2035 }
2036 }
2037 let function: syn::ItemFn = syn::parse_quote!(
2038 #[allow(non_snake_case, unused_variables, dead_code)]
2039 pub(crate) fn #name(v: #src) -> #c_struct {
2040 #c_struct { #(#inits),* }
2041 }
2042 );
2043 return Some(ConverterImpl {
2044 subs,
2045 destination: syn::parse_quote!(#c_struct),
2046 function,
2047 pre_stages: vec![],
2048 niches: Niches::empty(),
2049 metadata: (),
2050 });
2051 }
2052
2053 if let Some(opaque) = self.value_opaque_ty_of(&ty.key()) {
2057 let opaque = opaque.clone();
2058 let name = Self::out_name_of(&ty.key());
2059 let src = self.src_ty_of(&ty.key());
2060 let function: syn::ItemFn = syn::parse_quote!(
2061 #[allow(non_snake_case, unused_variables, dead_code)]
2062 pub(crate) fn #name(v: #src) -> #opaque {
2063 <#opaque as ::prebindgen_c_runtime::Transmute>::from_rust(v)
2064 }
2065 );
2066 return Some(ConverterImpl {
2067 subs: vec![],
2068 destination: opaque,
2069 function,
2070 pre_stages: vec![],
2071 niches: Niches::empty(),
2072 metadata: (),
2073 });
2074 }
2075
2076 if self.enums.contains_key(&key) {
2078 let e = unit_enum(_r, &ty.key())?;
2079 let name = Self::out_name_of(&ty.key());
2080 let cname = self.c_type_ident(&ty.key());
2081 let src = self.src_ty_of(&ty.key());
2082 let arms = e.values.iter().map(|v| {
2083 let id = &v.name;
2084 quote!(#src::#id => #cname::#id,)
2085 });
2086 let function: syn::ItemFn = syn::parse_quote!(
2087 #[allow(non_snake_case, unused_variables, dead_code)]
2088 pub(crate) fn #name(v: #src) -> #cname {
2089 match v { #(#arms)* }
2090 }
2091 );
2092 return Some(ConverterImpl {
2093 subs: vec![],
2094 destination: syn::parse_quote!(#cname),
2095 function,
2096 pre_stages: vec![],
2097 niches: Niches::empty(),
2098 metadata: (),
2099 });
2100 }
2101
2102 if let Some(c) = self.out_tagged_union(ty, _r, emit) {
2105 return Some(c);
2106 }
2107
2108 None
2109 }
2110}
2111
2112impl CbindgenBuilder {
2116 pub(crate) fn in_wrappers(
2118 &self,
2119 ty: &TypeRef,
2120 r: &impl Conversions<()>,
2121 ) -> Option<ConverterImpl<()>> {
2122 if let Some(inner) = ty.optional_inner() {
2127 let entry = r.input_entry(inner)?;
2128 let inner_wire = entry.destination.clone();
2129 let inner_conv = entry.function.sig.ident.clone();
2130 let (inner_ok, fallible): (syn::Type, bool) = match &entry.function.sig.output {
2131 syn::ReturnType::Type(_, t) if is_result(t) => {
2132 let (ok, _e) = result_parts(t).expect("is_result ⇒ result_parts");
2133 (ok, true)
2134 }
2135 syn::ReturnType::Type(_, t) => ((**t).clone(), false),
2136 syn::ReturnType::Default => (syn::parse_quote!(()), false),
2137 };
2138 if let Some((slot, rest)) = entry.niches.clone().carve() {
2139 let pred = &slot.matches;
2140 let name = format_ident!("__cbg_in_option_{}", sanitize(&inner.key()));
2141 let function: syn::ItemFn = if fallible {
2142 syn::parse_quote!(
2143 #[allow(non_snake_case, unused_variables, dead_code)]
2144 pub(crate) unsafe fn #name(
2145 v: #inner_wire,
2146 ) -> ::core::result::Result<
2147 ::core::option::Option<#inner_ok>,
2148 ::std::string::String
2149 > {
2150 if #pred {
2151 ::core::result::Result::Ok(::core::option::Option::None)
2152 } else {
2153 #inner_conv(v).map(::core::option::Option::Some)
2154 }
2155 }
2156 )
2157 } else {
2158 syn::parse_quote!(
2159 #[allow(non_snake_case, unused_variables, dead_code)]
2160 pub(crate) unsafe fn #name(
2161 v: #inner_wire,
2162 ) -> ::core::option::Option<#inner_ok> {
2163 if #pred {
2164 ::core::option::Option::None
2165 } else {
2166 ::core::option::Option::Some(#inner_conv(v))
2167 }
2168 }
2169 )
2170 };
2171 return Some(ConverterImpl {
2172 subs: vec![inner.key()],
2173 destination: inner_wire,
2174 function,
2175 pre_stages: vec![],
2176 niches: rest,
2177 metadata: (),
2178 });
2179 }
2180 let is_ptr = matches!(inner_wire, syn::Type::Ptr(_));
2181 let wire: syn::Type = if is_ptr {
2182 inner_wire.clone()
2183 } else {
2184 syn::parse_quote!(*const #inner_wire)
2185 };
2186 let read = if is_ptr { quote!(v) } else { quote!(*v) };
2187 let name = format_ident!("__cbg_in_option_{}", sanitize(&inner.key()));
2188 let lt: TokenStream = if inner.borrow_target().is_some() {
2189 quote!(<'a>)
2190 } else {
2191 quote!()
2192 };
2193 let function: syn::ItemFn = if fallible {
2194 syn::parse_quote!(
2195 #[allow(non_snake_case, unused_variables, dead_code)]
2196 pub(crate) unsafe fn #name #lt(
2197 v: #wire,
2198 ) -> ::core::result::Result<::core::option::Option<#inner_ok>, ::std::string::String> {
2199 if v.is_null() {
2200 return ::core::result::Result::Ok(::core::option::Option::None);
2201 }
2202 match #inner_conv(#read) {
2203 ::core::result::Result::Ok(__x) => {
2204 ::core::result::Result::Ok(::core::option::Option::Some(__x))
2205 }
2206 ::core::result::Result::Err(__e) => ::core::result::Result::Err(__e),
2207 }
2208 }
2209 )
2210 } else {
2211 syn::parse_quote!(
2212 #[allow(non_snake_case, unused_variables, dead_code)]
2213 pub(crate) unsafe fn #name #lt(
2214 v: #wire,
2215 ) -> ::core::option::Option<#inner_ok> {
2216 if v.is_null() {
2217 ::core::option::Option::None
2218 } else {
2219 ::core::option::Option::Some(#inner_conv(#read))
2220 }
2221 }
2222 )
2223 };
2224 return Some(ConverterImpl {
2225 subs: vec![inner.key()],
2226 destination: wire,
2227 function,
2228 pre_stages: vec![],
2229 niches: Niches::empty(),
2230 metadata: (),
2231 });
2232 }
2233
2234 let TypeKind::Ref {
2239 mutable: rf_mut,
2240 inner: rf_inner,
2241 ..
2242 } = ty.kind()
2243 else {
2244 return None;
2245 };
2246 let elem = rf_inner;
2249
2250 if !*rf_mut {
2257 if let Some(e) = r_shared_slice_elem(ty) {
2258 if r_is_bool(e) {
2266 panic!(
2267 "Cbindgen: `&[bool]` cannot cross IN from C. A `bool` slice is \
2268 reinterpreted zero-copy from the caller's block, so a byte outside \
2269 `{{0, 1}}` would become a Rust `bool` with no chance to normalise it \
2270 (#170). Take the flags as an integer slice, or wrap them in a declared \
2271 `opaque_ptr` handle."
2272 );
2273 }
2274 if let Some(e_ty) = scalar_ty(e) {
2275 let name = format_ident!("__cbg_inmark_slice_{}", sanitize(&e.key()));
2276 let function: syn::ItemFn = syn::parse_quote!(
2277 #[allow(non_snake_case, dead_code, unused)]
2278 pub(crate) fn #name() {}
2279 );
2280 return Some(ConverterImpl {
2281 subs: vec![e.key()],
2282 destination: syn::parse_quote!(*const #e_ty),
2283 function,
2284 pre_stages: vec![],
2285 niches: Niches::empty(),
2286 metadata: (),
2287 });
2288 }
2289 if let Some(counterpart) = self.value_opaque_ty_of(&e.key()) {
2290 let counterpart = counterpart.clone();
2291 let name = format_ident!("__cbg_inmark_slice_{}", sanitize(&e.key()));
2292 let function: syn::ItemFn = syn::parse_quote!(
2293 #[allow(non_snake_case, dead_code, unused)]
2294 pub(crate) fn #name() {}
2295 );
2296 return Some(ConverterImpl {
2297 subs: vec![e.key()],
2298 destination: syn::parse_quote!(*const #counterpart),
2299 function,
2300 pre_stages: vec![],
2301 niches: Niches::empty(),
2302 metadata: (),
2303 });
2304 }
2305 }
2306 }
2307 if !*rf_mut && r_is_str(rf_inner) {
2309 let name = Self::in_name_of(&ty.key());
2310 let function: syn::ItemFn = syn::parse_quote!(
2311 #[allow(non_snake_case, unused_variables, dead_code)]
2312 pub(crate) unsafe fn #name<'a>(
2313 v: *const ::core::ffi::c_char,
2314 ) -> ::core::result::Result<&'a str, ::std::string::String> {
2315 if v.is_null() {
2316 return ::core::result::Result::Err(
2317 ::std::string::String::from("null pointer passed for str argument"),
2318 );
2319 }
2320 match ::std::ffi::CStr::from_ptr(v).to_str() {
2321 ::core::result::Result::Ok(s) => ::core::result::Result::Ok(s),
2322 ::core::result::Result::Err(_) => ::core::result::Result::Err(
2323 ::std::string::String::from("invalid UTF-8 in str argument"),
2324 ),
2325 }
2326 }
2327 );
2328 return Some(ConverterImpl {
2329 subs: vec![elem.key()],
2330 destination: syn::parse_quote!(*const ::core::ffi::c_char),
2331 function,
2332 pre_stages: vec![],
2333 niches: Niches::empty(),
2334 metadata: (),
2335 });
2336 }
2337 if *rf_mut {
2341 if let prebindgen_registry::flat::TypeKind::Uninit(inner) = elem.kind() {
2346 let op = self.value_opaque_ty_of(&inner.key())?.clone();
2347 let name = Self::in_name_of(&ty.key());
2348 let src = self.src_ty_of(&inner.key());
2349 let short = type_short(&inner.key());
2350 let null_ptr_msg = format!("null {short} pointer");
2351 let function: syn::ItemFn = syn::parse_quote!(
2352 #[allow(non_snake_case, unused_variables, dead_code)]
2353 pub(crate) unsafe fn #name<'a>(
2354 v: *mut #op,
2355 ) -> ::core::result::Result<&'a mut ::core::mem::MaybeUninit<#src>, ::std::string::String> {
2356 if v.is_null() {
2357 return ::core::result::Result::Err(
2358 ::std::string::String::from(#null_ptr_msg),
2359 );
2360 }
2361 ::core::result::Result::Ok(&mut *(v as *mut ::core::mem::MaybeUninit<#src>))
2362 }
2363 );
2364 return Some(ConverterImpl {
2365 subs: vec![inner.key()],
2366 destination: syn::parse_quote!(*mut #op),
2367 function,
2368 pre_stages: vec![],
2369 niches: Niches::empty(),
2370 metadata: (),
2371 });
2372 }
2373 let wire_ty: syn::Type = if self.opaque.contains_key(&elem.key()) {
2377 let c_struct = self.c_type_ident(&elem.key());
2378 syn::parse_quote!(#c_struct)
2379 } else {
2380 self.value_opaque_ty_of(&elem.key())?.clone()
2381 };
2382 let name = Self::in_name_of(&ty.key());
2383 let src = self.src_ty_of(&elem.key());
2384 let short = type_short(&elem.key());
2385 let null_ptr_msg = format!("null {short} pointer");
2386 let function: syn::ItemFn = syn::parse_quote!(
2387 #[allow(non_snake_case, unused_variables, dead_code)]
2388 pub(crate) unsafe fn #name<'a>(
2389 v: *mut #wire_ty,
2390 ) -> ::core::result::Result<&'a mut #src, ::std::string::String> {
2391 if v.is_null() {
2392 return ::core::result::Result::Err(
2393 ::std::string::String::from(#null_ptr_msg),
2394 );
2395 }
2396 ::core::result::Result::Ok(&mut *(v as *mut #src))
2397 }
2398 );
2399 return Some(ConverterImpl {
2400 subs: vec![elem.key()],
2401 destination: syn::parse_quote!(*mut #wire_ty),
2402 function,
2403 pre_stages: vec![],
2404 niches: Niches::empty(),
2405 metadata: (),
2406 });
2407 }
2408 let key1 = elem.key();
2410 let wire_ty: syn::Type = if self.opaque.contains_key(&key1) {
2411 let c_struct = self.c_type_ident(&elem.key());
2412 syn::parse_quote!(#c_struct)
2413 } else {
2414 self.value_opaque_ty_of(&elem.key())?.clone()
2415 };
2416 let name = Self::in_name_of(&ty.key());
2417 let src = self.src_ty_of(&elem.key());
2418 let short = type_short(&elem.key());
2419 let null_ptr_msg = format!("null {short} pointer");
2420 let function: syn::ItemFn = syn::parse_quote!(
2421 #[allow(non_snake_case, unused_variables, dead_code)]
2422 pub(crate) unsafe fn #name<'a>(
2423 v: *const #wire_ty,
2424 ) -> ::core::result::Result<&'a #src, ::std::string::String> {
2425 if v.is_null() {
2426 return ::core::result::Result::Err(::std::string::String::from(#null_ptr_msg));
2427 }
2428 ::core::result::Result::Ok(&*(v as *const #src))
2429 }
2430 );
2431 Some(ConverterImpl {
2432 subs: vec![elem.key()],
2433 destination: syn::parse_quote!(*const #wire_ty),
2434 function,
2435 pre_stages: vec![],
2436 niches: Niches::empty(),
2437 metadata: (),
2438 })
2439 }
2440
2441 pub(crate) fn out_wrappers(
2446 &self,
2447 ty: &TypeRef,
2448 r: &impl Conversions<()>,
2449 ) -> Option<ConverterImpl<()>> {
2450 if let Some(inner) = ty.optional_inner().or_else(|| ty.sequence_elem()) {
2452 r.output_entry(inner)?;
2453 let kind = if ty.optional_inner().is_some() {
2454 "option"
2455 } else {
2456 "vec"
2457 };
2458 let name = format_ident!("__cbg_outmark_{}_{}", kind, sanitize(&inner.key()));
2459 let function: syn::ItemFn = syn::parse_quote!(
2460 #[allow(non_snake_case, dead_code, unused)]
2461 pub(crate) fn #name() {}
2462 );
2463 return Some(ConverterImpl {
2464 subs: vec![inner.key()],
2465 destination: syn::parse_quote!(()),
2466 function,
2467 pre_stages: vec![],
2468 niches: Niches::empty(),
2469 metadata: (),
2470 });
2471 }
2472 if let Some(inner) = r_cow_slice_elem(ty) {
2475 r.output_entry(inner)?;
2476 let name = format_ident!("__cbg_outmark_cow_slice_{}", sanitize(&inner.key()));
2477 let function: syn::ItemFn = syn::parse_quote!(
2478 #[allow(non_snake_case, dead_code, unused)]
2479 pub(crate) fn #name() {}
2480 );
2481 return Some(ConverterImpl {
2482 subs: vec![inner.key()],
2483 destination: syn::parse_quote!(()),
2484 function,
2485 pre_stages: vec![],
2486 niches: Niches::empty(),
2487 metadata: (),
2488 });
2489 }
2490 if let Some(elem) = self
2497 .r_value_opaque_slice_elem(ty)
2498 .or_else(|| r_scalar_slice_elem(ty))
2499 {
2500 r.output_entry(elem)?;
2501 let name = format_ident!("__cbg_outmark_slice_{}", sanitize(&elem.key()));
2502 let function: syn::ItemFn = syn::parse_quote!(
2503 #[allow(non_snake_case, dead_code, unused)]
2504 pub(crate) fn #name() {}
2505 );
2506 return Some(ConverterImpl {
2507 subs: vec![elem.key()],
2508 destination: syn::parse_quote!(()),
2509 function,
2510 pre_stages: vec![],
2511 niches: Niches::empty(),
2512 metadata: (),
2513 });
2514 }
2515 if let TypeKind::Ref { mutable, inner, .. } = ty.kind() {
2517 if !*mutable {
2518 let key = inner.key();
2519 let wire_ty: syn::Type = if self.opaque.contains_key(&key) {
2520 let c_struct = self.c_type_ident(&key);
2521 syn::parse_quote!(#c_struct)
2522 } else {
2523 self.value_opaque_ty_of(&key)?.clone()
2524 };
2525 let src = self.src_ty_of(&key);
2526 let name = format_ident!("__cbg_out_ref_{}", sanitize(&key));
2527 let function: syn::ItemFn = syn::parse_quote!(
2528 #[allow(non_snake_case, dead_code, unused)]
2529 pub(crate) unsafe fn #name(v: &#src) -> *const #wire_ty {
2530 v as *const #src as *const #wire_ty
2531 }
2532 );
2533 return Some(ConverterImpl {
2534 subs: vec![key],
2535 destination: syn::parse_quote!(*const #wire_ty),
2536 function,
2537 pre_stages: vec![],
2538 niches: Niches::empty(),
2539 metadata: (),
2540 });
2541 }
2542 return None;
2543 }
2544 if ty.fallible_parts().is_some() {
2547 let (ok, err) = ty.fallible_parts()?;
2548 let name = format_ident!("__cbg_result_{}", sanitize(&ty.key()));
2549 let function: syn::ItemFn = syn::parse_quote!(
2550 #[allow(non_snake_case, dead_code, unused)]
2551 pub(crate) fn #name() {}
2552 );
2553 return Some(ConverterImpl {
2554 subs: vec![ok.key(), err.key()],
2555 destination: syn::parse_quote!(()),
2556 function,
2557 pre_stages: vec![],
2558 niches: Niches::empty(),
2559 metadata: (),
2560 });
2561 }
2562 None
2563 }
2564}
2565
2566impl CbindgenBuilder {
2572 pub(crate) fn declared_functions(&self) -> HashSet<syn::Ident> {
2573 self.functions.keys().cloned().collect()
2574 }
2575 pub(crate) fn ignored_functions(&self) -> HashSet<syn::Ident> {
2576 self.ignored_functions.clone()
2577 }
2578 pub(crate) fn helper_functions(&self) -> HashSet<syn::Ident> {
2579 self.convert_decls
2580 .iter()
2581 .flat_map(|decl| decl.input_spec().iter().chain(decl.output_spec().iter()))
2582 .filter_map(|spec| match spec {
2583 ConvertSpec::PrebindgenFn(ident) => Some(ident.clone()),
2584 ConvertSpec::Trait { .. } => None,
2585 })
2586 .filter(|ident| !self.functions.contains_key(ident))
2587 .collect()
2588 }
2589 pub(crate) fn declared_types(&self) -> HashMap<TypeKey, Origin<syn::Type>> {
2592 self.opaque
2593 .iter()
2594 .chain(self.data.iter())
2595 .map(|(k, c)| (k, &c.rust_type))
2596 .chain(self.value_opaque.iter().map(|(k, c)| (k, &c.cfg.rust_type)))
2597 .chain(
2598 self.enums
2599 .iter()
2600 .chain(self.tagged_unions.iter())
2601 .map(|(k, c)| (k, &c.rust_type)),
2602 )
2603 .map(|(k, t)| (k.clone(), t.clone()))
2604 .collect()
2605 }
2606 pub(crate) fn ignored_types(&self) -> HashSet<TypeKey> {
2607 self.ignored_types.clone()
2608 }
2609}