1 use crate::syntax::atom::Atom::*;
2 use crate::syntax::attrs::{self, OtherAttrs};
3 use crate::syntax::cfg::CfgExpr;
4 use crate::syntax::file::Module;
5 use crate::syntax::instantiate::{ImplKey, NamedImplKey};
6 use crate::syntax::qualified::QualifiedName;
7 use crate::syntax::report::Errors;
8 use crate::syntax::symbol::Symbol;
9 use crate::syntax::{
10 self, check, mangle, Api, Doc, Enum, ExternFn, ExternType, Impl, Lifetimes, Pair, Signature,
11 Struct, Trait, Type, TypeAlias, Types,
12 };
13 use crate::type_id::Crate;
14 use crate::{derive, generics};
15 use proc_macro2::{Ident, Span, TokenStream};
16 use quote::{format_ident, quote, quote_spanned, ToTokens};
17 use std::mem;
18 use syn::{parse_quote, punctuated, Generics, Lifetime, Result, Token};
19
bridge(mut ffi: Module) -> Result<TokenStream>20 pub fn bridge(mut ffi: Module) -> Result<TokenStream> {
21 let ref mut errors = Errors::new();
22
23 let mut cfg = CfgExpr::Unconditional;
24 let mut doc = Doc::new();
25 let attrs = attrs::parse(
26 errors,
27 mem::take(&mut ffi.attrs),
28 attrs::Parser {
29 cfg: Some(&mut cfg),
30 doc: Some(&mut doc),
31 ..Default::default()
32 },
33 );
34
35 let content = mem::take(&mut ffi.content);
36 let trusted = ffi.unsafety.is_some();
37 let namespace = &ffi.namespace;
38 let ref mut apis = syntax::parse_items(errors, content, trusted, namespace);
39 #[cfg(feature = "experimental-enum-variants-from-header")]
40 crate::load::load(errors, apis);
41 let ref types = Types::collect(errors, apis);
42 errors.propagate()?;
43
44 let generator = check::Generator::Macro;
45 check::typecheck(errors, apis, types, generator);
46 errors.propagate()?;
47
48 Ok(expand(ffi, doc, attrs, apis, types))
49 }
50
expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) -> TokenStream51 fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) -> TokenStream {
52 let mut expanded = TokenStream::new();
53 let mut hidden = TokenStream::new();
54 let mut forbid = TokenStream::new();
55
56 for api in apis {
57 if let Api::RustType(ety) = api {
58 expanded.extend(expand_rust_type_import(ety));
59 hidden.extend(expand_rust_type_assert_unpin(ety, types));
60 }
61 }
62
63 for api in apis {
64 match api {
65 Api::Include(_) | Api::Impl(_) => {}
66 Api::Struct(strct) => {
67 expanded.extend(expand_struct(strct));
68 hidden.extend(expand_struct_operators(strct));
69 forbid.extend(expand_struct_forbid_drop(strct));
70 }
71 Api::Enum(enm) => expanded.extend(expand_enum(enm)),
72 Api::CxxType(ety) => {
73 let ident = &ety.name.rust;
74 if !types.structs.contains_key(ident) && !types.enums.contains_key(ident) {
75 expanded.extend(expand_cxx_type(ety));
76 hidden.extend(expand_cxx_type_assert_pinned(ety, types));
77 }
78 }
79 Api::CxxFunction(efn) => {
80 expanded.extend(expand_cxx_function_shim(efn, types));
81 }
82 Api::RustType(ety) => {
83 expanded.extend(expand_rust_type_impl(ety));
84 hidden.extend(expand_rust_type_layout(ety, types));
85 }
86 Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)),
87 Api::TypeAlias(alias) => {
88 expanded.extend(expand_type_alias(alias));
89 hidden.extend(expand_type_alias_verify(alias, types));
90 }
91 }
92 }
93
94 for (impl_key, &explicit_impl) in &types.impls {
95 match *impl_key {
96 ImplKey::RustBox(ident) => {
97 hidden.extend(expand_rust_box(ident, types, explicit_impl));
98 }
99 ImplKey::RustVec(ident) => {
100 hidden.extend(expand_rust_vec(ident, types, explicit_impl));
101 }
102 ImplKey::UniquePtr(ident) => {
103 expanded.extend(expand_unique_ptr(ident, types, explicit_impl));
104 }
105 ImplKey::SharedPtr(ident) => {
106 expanded.extend(expand_shared_ptr(ident, types, explicit_impl));
107 }
108 ImplKey::WeakPtr(ident) => {
109 expanded.extend(expand_weak_ptr(ident, types, explicit_impl));
110 }
111 ImplKey::CxxVector(ident) => {
112 expanded.extend(expand_cxx_vector(ident, explicit_impl, types));
113 }
114 }
115 }
116
117 if !forbid.is_empty() {
118 hidden.extend(expand_forbid(forbid));
119 }
120
121 // Work around https://github.com/rust-lang/rust/issues/67851.
122 if !hidden.is_empty() {
123 expanded.extend(quote! {
124 #[doc(hidden)]
125 const _: () = {
126 #hidden
127 };
128 });
129 }
130
131 let vis = &ffi.vis;
132 let mod_token = &ffi.mod_token;
133 let ident = &ffi.ident;
134 let span = ffi.brace_token.span;
135 let expanded = quote_spanned!(span=> {#expanded});
136
137 quote! {
138 #doc
139 #attrs
140 #[deny(improper_ctypes, improper_ctypes_definitions)]
141 #[allow(clippy::unknown_clippy_lints)]
142 #[allow(
143 non_camel_case_types,
144 non_snake_case,
145 clippy::extra_unused_type_parameters,
146 clippy::ptr_as_ptr,
147 clippy::upper_case_acronyms,
148 clippy::use_self,
149 )]
150 #vis #mod_token #ident #expanded
151 }
152 }
153
expand_struct(strct: &Struct) -> TokenStream154 fn expand_struct(strct: &Struct) -> TokenStream {
155 let ident = &strct.name.rust;
156 let doc = &strct.doc;
157 let attrs = &strct.attrs;
158 let generics = &strct.generics;
159 let type_id = type_id(&strct.name);
160 let fields = strct.fields.iter().map(|field| {
161 let doc = &field.doc;
162 let attrs = &field.attrs;
163 // This span on the pub makes "private type in public interface" errors
164 // appear in the right place.
165 let vis = field.visibility;
166 quote!(#doc #attrs #vis #field)
167 });
168 let mut derives = None;
169 let derived_traits = derive::expand_struct(strct, &mut derives);
170
171 let span = ident.span();
172 let visibility = strct.visibility;
173 let struct_token = strct.struct_token;
174 let struct_def = quote_spanned! {span=>
175 #visibility #struct_token #ident #generics {
176 #(#fields,)*
177 }
178 };
179
180 quote! {
181 #doc
182 #derives
183 #attrs
184 #[repr(C)]
185 #struct_def
186
187 unsafe impl #generics ::cxx::ExternType for #ident #generics {
188 #[allow(unused_attributes)] // incorrect lint
189 #[doc(hidden)]
190 type Id = #type_id;
191 type Kind = ::cxx::kind::Trivial;
192 }
193
194 #derived_traits
195 }
196 }
197
expand_struct_operators(strct: &Struct) -> TokenStream198 fn expand_struct_operators(strct: &Struct) -> TokenStream {
199 let ident = &strct.name.rust;
200 let generics = &strct.generics;
201 let mut operators = TokenStream::new();
202
203 for derive in &strct.derives {
204 let span = derive.span;
205 match derive.what {
206 Trait::PartialEq => {
207 let link_name = mangle::operator(&strct.name, "eq");
208 let local_name = format_ident!("__operator_eq_{}", strct.name.rust);
209 let prevent_unwind_label = format!("::{} as PartialEq>::eq", strct.name.rust);
210 operators.extend(quote_spanned! {span=>
211 #[doc(hidden)]
212 #[export_name = #link_name]
213 extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
214 let __fn = concat!("<", module_path!(), #prevent_unwind_label);
215 ::cxx::private::prevent_unwind(__fn, || *lhs == *rhs)
216 }
217 });
218
219 if !derive::contains(&strct.derives, Trait::Eq) {
220 let link_name = mangle::operator(&strct.name, "ne");
221 let local_name = format_ident!("__operator_ne_{}", strct.name.rust);
222 let prevent_unwind_label = format!("::{} as PartialEq>::ne", strct.name.rust);
223 operators.extend(quote_spanned! {span=>
224 #[doc(hidden)]
225 #[export_name = #link_name]
226 extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
227 let __fn = concat!("<", module_path!(), #prevent_unwind_label);
228 ::cxx::private::prevent_unwind(__fn, || *lhs != *rhs)
229 }
230 });
231 }
232 }
233 Trait::PartialOrd => {
234 let link_name = mangle::operator(&strct.name, "lt");
235 let local_name = format_ident!("__operator_lt_{}", strct.name.rust);
236 let prevent_unwind_label = format!("::{} as PartialOrd>::lt", strct.name.rust);
237 operators.extend(quote_spanned! {span=>
238 #[doc(hidden)]
239 #[export_name = #link_name]
240 extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
241 let __fn = concat!("<", module_path!(), #prevent_unwind_label);
242 ::cxx::private::prevent_unwind(__fn, || *lhs < *rhs)
243 }
244 });
245
246 let link_name = mangle::operator(&strct.name, "le");
247 let local_name = format_ident!("__operator_le_{}", strct.name.rust);
248 let prevent_unwind_label = format!("::{} as PartialOrd>::le", strct.name.rust);
249 operators.extend(quote_spanned! {span=>
250 #[doc(hidden)]
251 #[export_name = #link_name]
252 extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
253 let __fn = concat!("<", module_path!(), #prevent_unwind_label);
254 ::cxx::private::prevent_unwind(__fn, || *lhs <= *rhs)
255 }
256 });
257
258 if !derive::contains(&strct.derives, Trait::Ord) {
259 let link_name = mangle::operator(&strct.name, "gt");
260 let local_name = format_ident!("__operator_gt_{}", strct.name.rust);
261 let prevent_unwind_label = format!("::{} as PartialOrd>::gt", strct.name.rust);
262 operators.extend(quote_spanned! {span=>
263 #[doc(hidden)]
264 #[export_name = #link_name]
265 extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
266 let __fn = concat!("<", module_path!(), #prevent_unwind_label);
267 ::cxx::private::prevent_unwind(__fn, || *lhs > *rhs)
268 }
269 });
270
271 let link_name = mangle::operator(&strct.name, "ge");
272 let local_name = format_ident!("__operator_ge_{}", strct.name.rust);
273 let prevent_unwind_label = format!("::{} as PartialOrd>::ge", strct.name.rust);
274 operators.extend(quote_spanned! {span=>
275 #[doc(hidden)]
276 #[export_name = #link_name]
277 extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
278 let __fn = concat!("<", module_path!(), #prevent_unwind_label);
279 ::cxx::private::prevent_unwind(__fn, || *lhs >= *rhs)
280 }
281 });
282 }
283 }
284 Trait::Hash => {
285 let link_name = mangle::operator(&strct.name, "hash");
286 let local_name = format_ident!("__operator_hash_{}", strct.name.rust);
287 let prevent_unwind_label = format!("::{} as Hash>::hash", strct.name.rust);
288 operators.extend(quote_spanned! {span=>
289 #[doc(hidden)]
290 #[export_name = #link_name]
291 #[allow(clippy::cast_possible_truncation)]
292 extern "C" fn #local_name #generics(this: &#ident #generics) -> usize {
293 let __fn = concat!("<", module_path!(), #prevent_unwind_label);
294 ::cxx::private::prevent_unwind(__fn, || ::cxx::private::hash(this))
295 }
296 });
297 }
298 _ => {}
299 }
300 }
301
302 operators
303 }
304
expand_struct_forbid_drop(strct: &Struct) -> TokenStream305 fn expand_struct_forbid_drop(strct: &Struct) -> TokenStream {
306 let ident = &strct.name.rust;
307 let generics = &strct.generics;
308 let span = ident.span();
309 let impl_token = Token;
310
311 quote_spanned! {span=>
312 #impl_token #generics self::Drop for super::#ident #generics {}
313 }
314 }
315
expand_enum(enm: &Enum) -> TokenStream316 fn expand_enum(enm: &Enum) -> TokenStream {
317 let ident = &enm.name.rust;
318 let doc = &enm.doc;
319 let attrs = &enm.attrs;
320 let repr = &enm.repr;
321 let type_id = type_id(&enm.name);
322 let variants = enm.variants.iter().map(|variant| {
323 let doc = &variant.doc;
324 let attrs = &variant.attrs;
325 let variant_ident = &variant.name.rust;
326 let discriminant = &variant.discriminant;
327 let span = variant_ident.span();
328 Some(quote_spanned! {span=>
329 #doc
330 #attrs
331 #[allow(dead_code)]
332 pub const #variant_ident: Self = #ident { repr: #discriminant };
333 })
334 });
335 let mut derives = None;
336 let derived_traits = derive::expand_enum(enm, &mut derives);
337
338 let span = ident.span();
339 let visibility = enm.visibility;
340 let struct_token = Token;
341 let enum_repr = quote! {
342 #[allow(missing_docs)]
343 pub repr: #repr,
344 };
345 let enum_def = quote_spanned! {span=>
346 #visibility #struct_token #ident {
347 #enum_repr
348 }
349 };
350
351 quote! {
352 #doc
353 #derives
354 #attrs
355 #[repr(transparent)]
356 #enum_def
357
358 #[allow(non_upper_case_globals)]
359 impl #ident {
360 #(#variants)*
361 }
362
363 unsafe impl ::cxx::ExternType for #ident {
364 #[allow(unused_attributes)] // incorrect lint
365 #[doc(hidden)]
366 type Id = #type_id;
367 type Kind = ::cxx::kind::Trivial;
368 }
369
370 #derived_traits
371 }
372 }
373
expand_cxx_type(ety: &ExternType) -> TokenStream374 fn expand_cxx_type(ety: &ExternType) -> TokenStream {
375 let ident = &ety.name.rust;
376 let doc = &ety.doc;
377 let attrs = &ety.attrs;
378 let generics = &ety.generics;
379 let type_id = type_id(&ety.name);
380
381 let lifetime_fields = ety.generics.lifetimes.iter().map(|lifetime| {
382 let field = format_ident!("_lifetime_{}", lifetime.ident);
383 quote!(#field: ::cxx::core::marker::PhantomData<&#lifetime ()>)
384 });
385 let repr_fields = quote! {
386 _private: ::cxx::private::Opaque,
387 #(#lifetime_fields,)*
388 };
389
390 let span = ident.span();
391 let visibility = &ety.visibility;
392 let struct_token = Token;
393 let extern_type_def = quote_spanned! {span=>
394 #visibility #struct_token #ident #generics {
395 #repr_fields
396 }
397 };
398
399 quote! {
400 #doc
401 #attrs
402 #[repr(C)]
403 #extern_type_def
404
405 unsafe impl #generics ::cxx::ExternType for #ident #generics {
406 #[allow(unused_attributes)] // incorrect lint
407 #[doc(hidden)]
408 type Id = #type_id;
409 type Kind = ::cxx::kind::Opaque;
410 }
411 }
412 }
413
expand_cxx_type_assert_pinned(ety: &ExternType, types: &Types) -> TokenStream414 fn expand_cxx_type_assert_pinned(ety: &ExternType, types: &Types) -> TokenStream {
415 let ident = &ety.name.rust;
416 let infer = Token);
417
418 let resolve = types.resolve(ident);
419 let lifetimes = resolve.generics.to_underscore_lifetimes();
420
421 quote! {
422 let _: fn() = {
423 // Derived from https://github.com/nvzqz/static-assertions-rs.
424 trait __AmbiguousIfImpl<A> {
425 fn infer() {}
426 }
427
428 impl<T> __AmbiguousIfImpl<()> for T
429 where
430 T: ?::cxx::core::marker::Sized
431 {}
432
433 #[allow(dead_code)]
434 struct __Invalid;
435
436 impl<T> __AmbiguousIfImpl<__Invalid> for T
437 where
438 T: ?::cxx::core::marker::Sized + ::cxx::core::marker::Unpin,
439 {}
440
441 // If there is only one specialized trait impl, type inference with
442 // `_` can be resolved and this can compile. Fails to compile if
443 // user has added a manual Unpin impl for their opaque C++ type as
444 // then `__AmbiguousIfImpl<__Invalid>` also exists.
445 <#ident #lifetimes as __AmbiguousIfImpl<#infer>>::infer
446 };
447 }
448 }
449
expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream450 fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
451 let generics = &efn.generics;
452 let receiver = efn.receiver.iter().map(|receiver| {
453 let receiver_type = receiver.ty();
454 quote!(_: #receiver_type)
455 });
456 let args = efn.args.iter().map(|arg| {
457 let var = &arg.name.rust;
458 let colon = arg.colon_token;
459 let ty = expand_extern_type(&arg.ty, types, true);
460 if arg.ty == RustString {
461 quote!(#var #colon *const #ty)
462 } else if let Type::RustVec(_) = arg.ty {
463 quote!(#var #colon *const #ty)
464 } else if let Type::Fn(_) = arg.ty {
465 quote!(#var #colon ::cxx::private::FatFunction)
466 } else if types.needs_indirect_abi(&arg.ty) {
467 quote!(#var #colon *mut #ty)
468 } else {
469 quote!(#var #colon #ty)
470 }
471 });
472 let all_args = receiver.chain(args);
473 let ret = if efn.throws {
474 quote!(-> ::cxx::private::Result)
475 } else {
476 expand_extern_return_type(&efn.ret, types, true)
477 };
478 let mut outparam = None;
479 if indirect_return(efn, types) {
480 let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
481 outparam = Some(quote!(__return: *mut #ret));
482 }
483 let link_name = mangle::extern_fn(efn, types);
484 let local_name = format_ident!("__{}", efn.name.rust);
485 quote! {
486 #[link_name = #link_name]
487 fn #local_name #generics(#(#all_args,)* #outparam) #ret;
488 }
489 }
490
expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream491 fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
492 let doc = &efn.doc;
493 let attrs = &efn.attrs;
494 let decl = expand_cxx_function_decl(efn, types);
495 let receiver = efn.receiver.iter().map(|receiver| {
496 let var = receiver.var;
497 if receiver.pinned {
498 let colon = receiver.colon_token;
499 let ty = receiver.ty_self();
500 quote!(#var #colon #ty)
501 } else {
502 let ampersand = receiver.ampersand;
503 let lifetime = &receiver.lifetime;
504 let mutability = receiver.mutability;
505 quote!(#ampersand #lifetime #mutability #var)
506 }
507 });
508 let args = efn.args.iter().map(|arg| quote!(#arg));
509 let all_args = receiver.chain(args);
510 let ret = if efn.throws {
511 let ok = match &efn.ret {
512 Some(ret) => quote!(#ret),
513 None => quote!(()),
514 };
515 quote!(-> ::cxx::core::result::Result<#ok, ::cxx::Exception>)
516 } else {
517 expand_return_type(&efn.ret)
518 };
519 let indirect_return = indirect_return(efn, types);
520 let receiver_var = efn
521 .receiver
522 .iter()
523 .map(|receiver| receiver.var.to_token_stream());
524 let arg_vars = efn.args.iter().map(|arg| {
525 let var = &arg.name.rust;
526 let span = var.span();
527 match &arg.ty {
528 Type::Ident(ident) if ident.rust == RustString => {
529 quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustString)
530 }
531 Type::RustBox(ty) => {
532 if types.is_considered_improper_ctype(&ty.inner) {
533 quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw(#var).cast())
534 } else {
535 quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw(#var))
536 }
537 }
538 Type::UniquePtr(ty) => {
539 if types.is_considered_improper_ctype(&ty.inner) {
540 quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var).cast())
541 } else {
542 quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var))
543 }
544 }
545 Type::RustVec(_) => quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
546 Type::Ref(ty) => match &ty.inner {
547 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
548 false => quote_spanned!(span=> ::cxx::private::RustString::from_ref(#var)),
549 true => quote_spanned!(span=> ::cxx::private::RustString::from_mut(#var)),
550 },
551 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
552 false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string(#var)),
553 true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string(#var)),
554 },
555 Type::RustVec(_) => match ty.mutable {
556 false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref(#var)),
557 true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut(#var)),
558 },
559 inner if types.is_considered_improper_ctype(inner) => {
560 let var = match ty.pinned {
561 false => quote!(#var),
562 true => quote_spanned!(span=> ::cxx::core::pin::Pin::into_inner_unchecked(#var)),
563 };
564 match ty.mutable {
565 false => {
566 quote_spanned!(span=> #var as *const #inner as *const ::cxx::core::ffi::c_void)
567 }
568 true => quote_spanned!(span=> #var as *mut #inner as *mut ::cxx::core::ffi::c_void),
569 }
570 }
571 _ => quote!(#var),
572 },
573 Type::Ptr(ty) => {
574 if types.is_considered_improper_ctype(&ty.inner) {
575 quote_spanned!(span=> #var.cast())
576 } else {
577 quote!(#var)
578 }
579 }
580 Type::Str(_) => quote_spanned!(span=> ::cxx::private::RustStr::from(#var)),
581 Type::SliceRef(ty) => match ty.mutable {
582 false => quote_spanned!(span=> ::cxx::private::RustSlice::from_ref(#var)),
583 true => quote_spanned!(span=> ::cxx::private::RustSlice::from_mut(#var)),
584 },
585 ty if types.needs_indirect_abi(ty) => quote_spanned!(span=> #var.as_mut_ptr()),
586 _ => quote!(#var),
587 }
588 });
589 let vars = receiver_var.chain(arg_vars);
590 let trampolines = efn
591 .args
592 .iter()
593 .filter_map(|arg| {
594 if let Type::Fn(f) = &arg.ty {
595 let var = &arg.name;
596 Some(expand_function_pointer_trampoline(efn, var, f, types))
597 } else {
598 None
599 }
600 })
601 .collect::<TokenStream>();
602 let mut setup = efn
603 .args
604 .iter()
605 .filter(|arg| types.needs_indirect_abi(&arg.ty))
606 .map(|arg| {
607 let var = &arg.name.rust;
608 let span = var.span();
609 // These are arguments for which C++ has taken ownership of the data
610 // behind the mut reference it received.
611 quote_spanned! {span=>
612 let mut #var = ::cxx::core::mem::MaybeUninit::new(#var);
613 }
614 })
615 .collect::<TokenStream>();
616 let local_name = format_ident!("__{}", efn.name.rust);
617 let span = efn.semi_token.span;
618 let call = if indirect_return {
619 let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
620 setup.extend(quote_spanned! {span=>
621 let mut __return = ::cxx::core::mem::MaybeUninit::<#ret>::uninit();
622 });
623 setup.extend(if efn.throws {
624 quote_spanned! {span=>
625 #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?;
626 }
627 } else {
628 quote_spanned! {span=>
629 #local_name(#(#vars,)* __return.as_mut_ptr());
630 }
631 });
632 quote_spanned!(span=> __return.assume_init())
633 } else if efn.throws {
634 quote_spanned! {span=>
635 #local_name(#(#vars),*).exception()
636 }
637 } else {
638 quote_spanned! {span=>
639 #local_name(#(#vars),*)
640 }
641 };
642 let mut expr;
643 if efn.throws && efn.sig.ret.is_none() {
644 expr = call;
645 } else {
646 expr = match &efn.ret {
647 None => call,
648 Some(ret) => match ret {
649 Type::Ident(ident) if ident.rust == RustString => {
650 quote_spanned!(span=> #call.into_string())
651 }
652 Type::RustBox(ty) => {
653 if types.is_considered_improper_ctype(&ty.inner) {
654 quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#call.cast()))
655 } else {
656 quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#call))
657 }
658 }
659 Type::RustVec(vec) => {
660 if vec.inner == RustString {
661 quote_spanned!(span=> #call.into_vec_string())
662 } else {
663 quote_spanned!(span=> #call.into_vec())
664 }
665 }
666 Type::UniquePtr(ty) => {
667 if types.is_considered_improper_ctype(&ty.inner) {
668 quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call.cast()))
669 } else {
670 quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call))
671 }
672 }
673 Type::Ref(ty) => match &ty.inner {
674 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
675 false => quote_spanned!(span=> #call.as_string()),
676 true => quote_spanned!(span=> #call.as_mut_string()),
677 },
678 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
679 false => quote_spanned!(span=> #call.as_vec_string()),
680 true => quote_spanned!(span=> #call.as_mut_vec_string()),
681 },
682 Type::RustVec(_) => match ty.mutable {
683 false => quote_spanned!(span=> #call.as_vec()),
684 true => quote_spanned!(span=> #call.as_mut_vec()),
685 },
686 inner if types.is_considered_improper_ctype(inner) => {
687 let mutability = ty.mutability;
688 let deref_mut = quote_spanned!(span=> &#mutability *#call.cast());
689 match ty.pinned {
690 false => deref_mut,
691 true => {
692 quote_spanned!(span=> ::cxx::core::pin::Pin::new_unchecked(#deref_mut))
693 }
694 }
695 }
696 _ => call,
697 },
698 Type::Ptr(ty) => {
699 if types.is_considered_improper_ctype(&ty.inner) {
700 quote_spanned!(span=> #call.cast())
701 } else {
702 call
703 }
704 }
705 Type::Str(_) => quote_spanned!(span=> #call.as_str()),
706 Type::SliceRef(slice) => {
707 let inner = &slice.inner;
708 match slice.mutable {
709 false => quote_spanned!(span=> #call.as_slice::<#inner>()),
710 true => quote_spanned!(span=> #call.as_mut_slice::<#inner>()),
711 }
712 }
713 _ => call,
714 },
715 };
716 if efn.throws {
717 expr = quote_spanned!(span=> ::cxx::core::result::Result::Ok(#expr));
718 }
719 };
720 let mut dispatch = quote!(#setup #expr);
721 let visibility = efn.visibility;
722 let unsafety = &efn.sig.unsafety;
723 if unsafety.is_none() {
724 dispatch = quote_spanned!(span=> unsafe { #dispatch });
725 }
726 let fn_token = efn.sig.fn_token;
727 let ident = &efn.name.rust;
728 let generics = &efn.generics;
729 let arg_list = quote_spanned!(efn.sig.paren_token.span=> (#(#all_args,)*));
730 let fn_body = quote_spanned!(span=> {
731 extern "C" {
732 #decl
733 }
734 #trampolines
735 #dispatch
736 });
737 match &efn.receiver {
738 None => {
739 quote! {
740 #doc
741 #attrs
742 #visibility #unsafety #fn_token #ident #generics #arg_list #ret #fn_body
743 }
744 }
745 Some(receiver) => {
746 let elided_generics;
747 let receiver_ident = &receiver.ty.rust;
748 let resolve = types.resolve(&receiver.ty);
749 let receiver_generics = if receiver.ty.generics.lt_token.is_some() {
750 &receiver.ty.generics
751 } else {
752 elided_generics = Lifetimes {
753 lt_token: resolve.generics.lt_token,
754 lifetimes: resolve
755 .generics
756 .lifetimes
757 .pairs()
758 .map(|pair| {
759 let lifetime = Lifetime::new("'_", pair.value().apostrophe);
760 let punct = pair.punct().map(|&&comma| comma);
761 punctuated::Pair::new(lifetime, punct)
762 })
763 .collect(),
764 gt_token: resolve.generics.gt_token,
765 };
766 &elided_generics
767 };
768 quote_spanned! {ident.span()=>
769 impl #generics #receiver_ident #receiver_generics {
770 #doc
771 #attrs
772 #visibility #unsafety #fn_token #ident #arg_list #ret #fn_body
773 }
774 }
775 }
776 }
777 }
778
expand_function_pointer_trampoline( efn: &ExternFn, var: &Pair, sig: &Signature, types: &Types, ) -> TokenStream779 fn expand_function_pointer_trampoline(
780 efn: &ExternFn,
781 var: &Pair,
782 sig: &Signature,
783 types: &Types,
784 ) -> TokenStream {
785 let c_trampoline = mangle::c_trampoline(efn, var, types);
786 let r_trampoline = mangle::r_trampoline(efn, var, types);
787 let local_name = parse_quote!(__);
788 let prevent_unwind_label = format!("::{}::{}", efn.name.rust, var.rust);
789 let body_span = efn.semi_token.span;
790 let shim = expand_rust_function_shim_impl(
791 sig,
792 types,
793 &r_trampoline,
794 local_name,
795 prevent_unwind_label,
796 None,
797 Some(&efn.generics),
798 &efn.attrs,
799 body_span,
800 );
801 let var = &var.rust;
802
803 quote! {
804 let #var = ::cxx::private::FatFunction {
805 trampoline: {
806 extern "C" {
807 #[link_name = #c_trampoline]
808 fn trampoline();
809 }
810 #shim
811 trampoline as usize as *const ::cxx::core::ffi::c_void
812 },
813 ptr: #var as usize as *const ::cxx::core::ffi::c_void,
814 };
815 }
816 }
817
expand_rust_type_import(ety: &ExternType) -> TokenStream818 fn expand_rust_type_import(ety: &ExternType) -> TokenStream {
819 let ident = &ety.name.rust;
820 let span = ident.span();
821
822 quote_spanned! {span=>
823 use super::#ident;
824 }
825 }
826
expand_rust_type_impl(ety: &ExternType) -> TokenStream827 fn expand_rust_type_impl(ety: &ExternType) -> TokenStream {
828 let ident = &ety.name.rust;
829 let generics = &ety.generics;
830 let span = ident.span();
831 let unsafe_impl = quote_spanned!(ety.type_token.span=> unsafe impl);
832
833 let mut impls = quote_spanned! {span=>
834 #[doc(hidden)]
835 #unsafe_impl #generics ::cxx::private::RustType for #ident #generics {}
836 };
837
838 for derive in &ety.derives {
839 if derive.what == Trait::ExternType {
840 let type_id = type_id(&ety.name);
841 let span = derive.span;
842 impls.extend(quote_spanned! {span=>
843 unsafe impl #generics ::cxx::ExternType for #ident #generics {
844 #[allow(unused_attributes)] // incorrect lint
845 #[doc(hidden)]
846 type Id = #type_id;
847 type Kind = ::cxx::kind::Opaque;
848 }
849 });
850 }
851 }
852
853 impls
854 }
855
expand_rust_type_assert_unpin(ety: &ExternType, types: &Types) -> TokenStream856 fn expand_rust_type_assert_unpin(ety: &ExternType, types: &Types) -> TokenStream {
857 let ident = &ety.name.rust;
858 let begin_span = Token;
859 let unpin = quote_spanned! {ety.semi_token.span=>
860 #begin_span cxx::core::marker::Unpin
861 };
862
863 let resolve = types.resolve(ident);
864 let lifetimes = resolve.generics.to_underscore_lifetimes();
865
866 quote_spanned! {ident.span()=>
867 let _ = {
868 fn __AssertUnpin<T: ?::cxx::core::marker::Sized + #unpin>() {}
869 __AssertUnpin::<#ident #lifetimes>
870 };
871 }
872 }
873
expand_rust_type_layout(ety: &ExternType, types: &Types) -> TokenStream874 fn expand_rust_type_layout(ety: &ExternType, types: &Types) -> TokenStream {
875 // Rustc will render as follows if not sized:
876 //
877 // type TheirType;
878 // -----^^^^^^^^^-
879 // | |
880 // | doesn't have a size known at compile-time
881 // required by this bound in `__AssertSized`
882
883 let ident = &ety.name.rust;
884 let begin_span = Token;
885 let sized = quote_spanned! {ety.semi_token.span=>
886 #begin_span cxx::core::marker::Sized
887 };
888
889 let link_sizeof = mangle::operator(&ety.name, "sizeof");
890 let link_alignof = mangle::operator(&ety.name, "alignof");
891
892 let local_sizeof = format_ident!("__sizeof_{}", ety.name.rust);
893 let local_alignof = format_ident!("__alignof_{}", ety.name.rust);
894
895 let resolve = types.resolve(ident);
896 let lifetimes = resolve.generics.to_underscore_lifetimes();
897
898 quote_spanned! {ident.span()=>
899 {
900 #[doc(hidden)]
901 fn __AssertSized<T: ?#sized + #sized>() -> ::cxx::core::alloc::Layout {
902 ::cxx::core::alloc::Layout::new::<T>()
903 }
904 #[doc(hidden)]
905 #[export_name = #link_sizeof]
906 extern "C" fn #local_sizeof() -> usize {
907 __AssertSized::<#ident #lifetimes>().size()
908 }
909 #[doc(hidden)]
910 #[export_name = #link_alignof]
911 extern "C" fn #local_alignof() -> usize {
912 __AssertSized::<#ident #lifetimes>().align()
913 }
914 }
915 }
916 }
917
expand_forbid(impls: TokenStream) -> TokenStream918 fn expand_forbid(impls: TokenStream) -> TokenStream {
919 quote! {
920 mod forbid {
921 pub trait Drop {}
922 #[allow(drop_bounds)]
923 impl<T: ?::cxx::core::marker::Sized + ::cxx::core::ops::Drop> self::Drop for T {}
924 #impls
925 }
926 }
927 }
928
expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream929 fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
930 let link_name = mangle::extern_fn(efn, types);
931 let local_name = match &efn.receiver {
932 None => format_ident!("__{}", efn.name.rust),
933 Some(receiver) => format_ident!("__{}__{}", receiver.ty.rust, efn.name.rust),
934 };
935 let prevent_unwind_label = match &efn.receiver {
936 None => format!("::{}", efn.name.rust),
937 Some(receiver) => format!("::{}::{}", receiver.ty.rust, efn.name.rust),
938 };
939 let invoke = Some(&efn.name.rust);
940 let body_span = efn.semi_token.span;
941 expand_rust_function_shim_impl(
942 efn,
943 types,
944 &link_name,
945 local_name,
946 prevent_unwind_label,
947 invoke,
948 None,
949 &efn.attrs,
950 body_span,
951 )
952 }
953
expand_rust_function_shim_impl( sig: &Signature, types: &Types, link_name: &Symbol, local_name: Ident, prevent_unwind_label: String, invoke: Option<&Ident>, outer_generics: Option<&Generics>, attrs: &OtherAttrs, body_span: Span, ) -> TokenStream954 fn expand_rust_function_shim_impl(
955 sig: &Signature,
956 types: &Types,
957 link_name: &Symbol,
958 local_name: Ident,
959 prevent_unwind_label: String,
960 invoke: Option<&Ident>,
961 outer_generics: Option<&Generics>,
962 attrs: &OtherAttrs,
963 body_span: Span,
964 ) -> TokenStream {
965 let generics = outer_generics.unwrap_or(&sig.generics);
966 let receiver_var = sig
967 .receiver
968 .as_ref()
969 .map(|receiver| quote_spanned!(receiver.var.span=> __self));
970 let receiver = sig.receiver.as_ref().map(|receiver| {
971 let colon = receiver.colon_token;
972 let receiver_type = receiver.ty();
973 quote!(#receiver_var #colon #receiver_type)
974 });
975 let args = sig.args.iter().map(|arg| {
976 let var = &arg.name.rust;
977 let colon = arg.colon_token;
978 let ty = expand_extern_type(&arg.ty, types, false);
979 if types.needs_indirect_abi(&arg.ty) {
980 quote!(#var #colon *mut #ty)
981 } else {
982 quote!(#var #colon #ty)
983 }
984 });
985 let all_args = receiver.into_iter().chain(args);
986
987 let arg_vars = sig.args.iter().map(|arg| {
988 let var = &arg.name.rust;
989 let span = var.span();
990 match &arg.ty {
991 Type::Ident(i) if i.rust == RustString => {
992 quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_string()))
993 }
994 Type::RustBox(_) => quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#var)),
995 Type::RustVec(vec) => {
996 if vec.inner == RustString {
997 quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_vec_string()))
998 } else {
999 quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_vec()))
1000 }
1001 }
1002 Type::UniquePtr(_) => quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#var)),
1003 Type::Ref(ty) => match &ty.inner {
1004 Type::Ident(i) if i.rust == RustString => match ty.mutable {
1005 false => quote_spanned!(span=> #var.as_string()),
1006 true => quote_spanned!(span=> #var.as_mut_string()),
1007 },
1008 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
1009 false => quote_spanned!(span=> #var.as_vec_string()),
1010 true => quote_spanned!(span=> #var.as_mut_vec_string()),
1011 },
1012 Type::RustVec(_) => match ty.mutable {
1013 false => quote_spanned!(span=> #var.as_vec()),
1014 true => quote_spanned!(span=> #var.as_mut_vec()),
1015 },
1016 _ => quote!(#var),
1017 },
1018 Type::Str(_) => quote_spanned!(span=> #var.as_str()),
1019 Type::SliceRef(slice) => {
1020 let inner = &slice.inner;
1021 match slice.mutable {
1022 false => quote_spanned!(span=> #var.as_slice::<#inner>()),
1023 true => quote_spanned!(span=> #var.as_mut_slice::<#inner>()),
1024 }
1025 }
1026 ty if types.needs_indirect_abi(ty) => {
1027 quote_spanned!(span=> ::cxx::core::ptr::read(#var))
1028 }
1029 _ => quote!(#var),
1030 }
1031 });
1032 let vars: Vec<_> = receiver_var.into_iter().chain(arg_vars).collect();
1033
1034 let wrap_super = invoke.map(|invoke| expand_rust_function_shim_super(sig, &local_name, invoke));
1035
1036 let mut requires_closure;
1037 let mut call = match invoke {
1038 Some(_) => {
1039 requires_closure = false;
1040 quote!(#local_name)
1041 }
1042 None => {
1043 requires_closure = true;
1044 quote!(::cxx::core::mem::transmute::<*const (), #sig>(__extern))
1045 }
1046 };
1047 requires_closure |= !vars.is_empty();
1048 call.extend(quote! { (#(#vars),*) });
1049
1050 let span = body_span;
1051 let conversion = sig.ret.as_ref().and_then(|ret| match ret {
1052 Type::Ident(ident) if ident.rust == RustString => {
1053 Some(quote_spanned!(span=> ::cxx::private::RustString::from))
1054 }
1055 Type::RustBox(_) => Some(quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw)),
1056 Type::RustVec(vec) => {
1057 if vec.inner == RustString {
1058 Some(quote_spanned!(span=> ::cxx::private::RustVec::from_vec_string))
1059 } else {
1060 Some(quote_spanned!(span=> ::cxx::private::RustVec::from))
1061 }
1062 }
1063 Type::UniquePtr(_) => Some(quote_spanned!(span=> ::cxx::UniquePtr::into_raw)),
1064 Type::Ref(ty) => match &ty.inner {
1065 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
1066 false => Some(quote_spanned!(span=> ::cxx::private::RustString::from_ref)),
1067 true => Some(quote_spanned!(span=> ::cxx::private::RustString::from_mut)),
1068 },
1069 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
1070 false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string)),
1071 true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string)),
1072 },
1073 Type::RustVec(_) => match ty.mutable {
1074 false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref)),
1075 true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut)),
1076 },
1077 _ => None,
1078 },
1079 Type::Str(_) => Some(quote_spanned!(span=> ::cxx::private::RustStr::from)),
1080 Type::SliceRef(ty) => match ty.mutable {
1081 false => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_ref)),
1082 true => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_mut)),
1083 },
1084 _ => None,
1085 });
1086
1087 let mut expr = match conversion {
1088 None => call,
1089 Some(conversion) if !sig.throws => {
1090 requires_closure = true;
1091 quote_spanned!(span=> #conversion(#call))
1092 }
1093 Some(conversion) => {
1094 requires_closure = true;
1095 quote_spanned!(span=> ::cxx::core::result::Result::map(#call, #conversion))
1096 }
1097 };
1098
1099 let mut outparam = None;
1100 let indirect_return = indirect_return(sig, types);
1101 if indirect_return {
1102 let ret = expand_extern_type(sig.ret.as_ref().unwrap(), types, false);
1103 outparam = Some(quote_spanned!(span=> __return: *mut #ret,));
1104 }
1105 if sig.throws {
1106 let out = match sig.ret {
1107 Some(_) => quote_spanned!(span=> __return),
1108 None => quote_spanned!(span=> &mut ()),
1109 };
1110 requires_closure = true;
1111 expr = quote_spanned!(span=> ::cxx::private::r#try(#out, #expr));
1112 } else if indirect_return {
1113 requires_closure = true;
1114 expr = quote_spanned!(span=> ::cxx::core::ptr::write(__return, #expr));
1115 }
1116
1117 let closure = if requires_closure {
1118 quote_spanned!(span=> move || #expr)
1119 } else {
1120 quote!(#local_name)
1121 };
1122
1123 expr = quote_spanned!(span=> ::cxx::private::prevent_unwind(__fn, #closure));
1124
1125 let ret = if sig.throws {
1126 quote!(-> ::cxx::private::Result)
1127 } else {
1128 expand_extern_return_type(&sig.ret, types, false)
1129 };
1130
1131 let pointer = match invoke {
1132 None => Some(quote_spanned!(span=> __extern: *const ())),
1133 Some(_) => None,
1134 };
1135
1136 quote_spanned! {span=>
1137 #attrs
1138 #[doc(hidden)]
1139 #[export_name = #link_name]
1140 unsafe extern "C" fn #local_name #generics(#(#all_args,)* #outparam #pointer) #ret {
1141 let __fn = ::cxx::private::concat!(::cxx::private::module_path!(), #prevent_unwind_label);
1142 #wrap_super
1143 #expr
1144 }
1145 }
1146 }
1147
1148 // A wrapper like `fn f(x: Arg) { super::f(x) }` just to ensure we have the
1149 // accurate unsafety declaration and no problematic elided lifetimes.
expand_rust_function_shim_super( sig: &Signature, local_name: &Ident, invoke: &Ident, ) -> TokenStream1150 fn expand_rust_function_shim_super(
1151 sig: &Signature,
1152 local_name: &Ident,
1153 invoke: &Ident,
1154 ) -> TokenStream {
1155 let unsafety = sig.unsafety;
1156 let generics = &sig.generics;
1157
1158 let receiver_var = sig
1159 .receiver
1160 .as_ref()
1161 .map(|receiver| Ident::new("__self", receiver.var.span));
1162 let receiver = sig.receiver.iter().map(|receiver| {
1163 let receiver_type = receiver.ty();
1164 quote!(#receiver_var: #receiver_type)
1165 });
1166 let args = sig.args.iter().map(|arg| quote!(#arg));
1167 let all_args = receiver.chain(args);
1168
1169 let ret = if let Some((result, _langle, rangle)) = sig.throws_tokens {
1170 let ok = match &sig.ret {
1171 Some(ret) => quote!(#ret),
1172 None => quote!(()),
1173 };
1174 // Set spans that result in the `Result<...>` written by the user being
1175 // highlighted as the cause if their error type has no Display impl.
1176 let result_begin = quote_spanned!(result.span=> ::cxx::core::result::Result<#ok, impl);
1177 let result_end = quote_spanned!(rangle.span=> ::cxx::core::fmt::Display>);
1178 quote!(-> #result_begin #result_end)
1179 } else {
1180 expand_return_type(&sig.ret)
1181 };
1182
1183 let arg_vars = sig.args.iter().map(|arg| &arg.name.rust);
1184 let vars = receiver_var.iter().chain(arg_vars);
1185
1186 let span = invoke.span();
1187 let call = match &sig.receiver {
1188 None => quote_spanned!(span=> super::#invoke),
1189 Some(receiver) => {
1190 let receiver_type = &receiver.ty.rust;
1191 quote_spanned!(span=> #receiver_type::#invoke)
1192 }
1193 };
1194
1195 quote_spanned! {span=>
1196 #unsafety fn #local_name #generics(#(#all_args,)*) #ret {
1197 #call(#(#vars,)*)
1198 }
1199 }
1200 }
1201
expand_type_alias(alias: &TypeAlias) -> TokenStream1202 fn expand_type_alias(alias: &TypeAlias) -> TokenStream {
1203 let doc = &alias.doc;
1204 let attrs = &alias.attrs;
1205 let visibility = alias.visibility;
1206 let type_token = alias.type_token;
1207 let ident = &alias.name.rust;
1208 let generics = &alias.generics;
1209 let eq_token = alias.eq_token;
1210 let ty = &alias.ty;
1211 let semi_token = alias.semi_token;
1212
1213 quote! {
1214 #doc
1215 #attrs
1216 #visibility #type_token #ident #generics #eq_token #ty #semi_token
1217 }
1218 }
1219
expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream1220 fn expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream {
1221 let ident = &alias.name.rust;
1222 let type_id = type_id(&alias.name);
1223 let begin_span = alias.type_token.span;
1224 let end_span = alias.semi_token.span;
1225 let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
1226 let end = quote_spanned!(end_span=> >);
1227
1228 let mut verify = quote! {
1229 const _: fn() = #begin #ident, #type_id #end;
1230 };
1231
1232 if types.required_trivial.contains_key(&alias.name.rust) {
1233 let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_kind::<);
1234 verify.extend(quote! {
1235 const _: fn() = #begin #ident, ::cxx::kind::Trivial #end;
1236 });
1237 }
1238
1239 verify
1240 }
1241
type_id(name: &Pair) -> TokenStream1242 fn type_id(name: &Pair) -> TokenStream {
1243 let namespace_segments = name.namespace.iter();
1244 let mut segments = Vec::with_capacity(namespace_segments.len() + 1);
1245 segments.extend(namespace_segments.cloned());
1246 segments.push(Ident::new(&name.cxx.to_string(), Span::call_site()));
1247 let qualified = QualifiedName { segments };
1248 crate::type_id::expand(Crate::Cxx, qualified)
1249 }
1250
expand_rust_box(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream1251 fn expand_rust_box(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1252 let ident = key.rust;
1253 let resolve = types.resolve(ident);
1254 let link_prefix = format!("cxxbridge1$box${}$", resolve.name.to_symbol());
1255 let link_alloc = format!("{}alloc", link_prefix);
1256 let link_dealloc = format!("{}dealloc", link_prefix);
1257 let link_drop = format!("{}drop", link_prefix);
1258
1259 let local_prefix = format_ident!("{}__box_", ident);
1260 let local_alloc = format_ident!("{}alloc", local_prefix);
1261 let local_dealloc = format_ident!("{}dealloc", local_prefix);
1262 let local_drop = format_ident!("{}drop", local_prefix);
1263
1264 let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1265
1266 let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1267 let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1268 let unsafe_token = format_ident!("unsafe", span = begin_span);
1269 let prevent_unwind_drop_label = format!("::{} as Drop>::drop", ident);
1270
1271 quote_spanned! {end_span=>
1272 #[doc(hidden)]
1273 #unsafe_token impl #impl_generics ::cxx::private::ImplBox for #ident #ty_generics {}
1274 #[doc(hidden)]
1275 #[export_name = #link_alloc]
1276 unsafe extern "C" fn #local_alloc #impl_generics() -> *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics> {
1277 // No prevent_unwind: the global allocator is not allowed to panic.
1278 //
1279 // TODO: replace with Box::new_uninit when stable.
1280 // https://doc.rust-lang.org/std/boxed/struct.Box.html#method.new_uninit
1281 // https://github.com/rust-lang/rust/issues/63291
1282 ::cxx::alloc::boxed::Box::into_raw(::cxx::alloc::boxed::Box::new(::cxx::core::mem::MaybeUninit::uninit()))
1283 }
1284 #[doc(hidden)]
1285 #[export_name = #link_dealloc]
1286 unsafe extern "C" fn #local_dealloc #impl_generics(ptr: *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics>) {
1287 // No prevent_unwind: the global allocator is not allowed to panic.
1288 let _ = ::cxx::alloc::boxed::Box::from_raw(ptr);
1289 }
1290 #[doc(hidden)]
1291 #[export_name = #link_drop]
1292 unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::alloc::boxed::Box<#ident #ty_generics>) {
1293 let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1294 ::cxx::private::prevent_unwind(__fn, || ::cxx::core::ptr::drop_in_place(this));
1295 }
1296 }
1297 }
1298
expand_rust_vec(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream1299 fn expand_rust_vec(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1300 let elem = key.rust;
1301 let resolve = types.resolve(elem);
1302 let link_prefix = format!("cxxbridge1$rust_vec${}$", resolve.name.to_symbol());
1303 let link_new = format!("{}new", link_prefix);
1304 let link_drop = format!("{}drop", link_prefix);
1305 let link_len = format!("{}len", link_prefix);
1306 let link_capacity = format!("{}capacity", link_prefix);
1307 let link_data = format!("{}data", link_prefix);
1308 let link_reserve_total = format!("{}reserve_total", link_prefix);
1309 let link_set_len = format!("{}set_len", link_prefix);
1310 let link_truncate = format!("{}truncate", link_prefix);
1311
1312 let local_prefix = format_ident!("{}__vec_", elem);
1313 let local_new = format_ident!("{}new", local_prefix);
1314 let local_drop = format_ident!("{}drop", local_prefix);
1315 let local_len = format_ident!("{}len", local_prefix);
1316 let local_capacity = format_ident!("{}capacity", local_prefix);
1317 let local_data = format_ident!("{}data", local_prefix);
1318 let local_reserve_total = format_ident!("{}reserve_total", local_prefix);
1319 let local_set_len = format_ident!("{}set_len", local_prefix);
1320 let local_truncate = format_ident!("{}truncate", local_prefix);
1321
1322 let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1323
1324 let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1325 let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1326 let unsafe_token = format_ident!("unsafe", span = begin_span);
1327 let prevent_unwind_drop_label = format!("::{} as Drop>::drop", elem);
1328
1329 quote_spanned! {end_span=>
1330 #[doc(hidden)]
1331 #unsafe_token impl #impl_generics ::cxx::private::ImplVec for #elem #ty_generics {}
1332 #[doc(hidden)]
1333 #[export_name = #link_new]
1334 unsafe extern "C" fn #local_new #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1335 // No prevent_unwind: cannot panic.
1336 ::cxx::core::ptr::write(this, ::cxx::private::RustVec::new());
1337 }
1338 #[doc(hidden)]
1339 #[export_name = #link_drop]
1340 unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1341 let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1342 ::cxx::private::prevent_unwind(__fn, || ::cxx::core::ptr::drop_in_place(this));
1343 }
1344 #[doc(hidden)]
1345 #[export_name = #link_len]
1346 unsafe extern "C" fn #local_len #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1347 // No prevent_unwind: cannot panic.
1348 (*this).len()
1349 }
1350 #[doc(hidden)]
1351 #[export_name = #link_capacity]
1352 unsafe extern "C" fn #local_capacity #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1353 // No prevent_unwind: cannot panic.
1354 (*this).capacity()
1355 }
1356 #[doc(hidden)]
1357 #[export_name = #link_data]
1358 unsafe extern "C" fn #local_data #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> *const #elem #ty_generics {
1359 // No prevent_unwind: cannot panic.
1360 (*this).as_ptr()
1361 }
1362 #[doc(hidden)]
1363 #[export_name = #link_reserve_total]
1364 unsafe extern "C" fn #local_reserve_total #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, new_cap: usize) {
1365 // No prevent_unwind: the global allocator is not allowed to panic.
1366 (*this).reserve_total(new_cap);
1367 }
1368 #[doc(hidden)]
1369 #[export_name = #link_set_len]
1370 unsafe extern "C" fn #local_set_len #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1371 // No prevent_unwind: cannot panic.
1372 (*this).set_len(len);
1373 }
1374 #[doc(hidden)]
1375 #[export_name = #link_truncate]
1376 unsafe extern "C" fn #local_truncate #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1377 let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1378 ::cxx::private::prevent_unwind(__fn, || (*this).truncate(len));
1379 }
1380 }
1381 }
1382
expand_unique_ptr( key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>, ) -> TokenStream1383 fn expand_unique_ptr(
1384 key: NamedImplKey,
1385 types: &Types,
1386 explicit_impl: Option<&Impl>,
1387 ) -> TokenStream {
1388 let ident = key.rust;
1389 let name = ident.to_string();
1390 let resolve = types.resolve(ident);
1391 let prefix = format!("cxxbridge1$unique_ptr${}$", resolve.name.to_symbol());
1392 let link_null = format!("{}null", prefix);
1393 let link_uninit = format!("{}uninit", prefix);
1394 let link_raw = format!("{}raw", prefix);
1395 let link_get = format!("{}get", prefix);
1396 let link_release = format!("{}release", prefix);
1397 let link_drop = format!("{}drop", prefix);
1398
1399 let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1400
1401 let can_construct_from_value = types.is_maybe_trivial(ident);
1402 let new_method = if can_construct_from_value {
1403 Some(quote! {
1404 fn __new(value: Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1405 extern "C" {
1406 #[link_name = #link_uninit]
1407 fn __uninit(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1408 }
1409 let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1410 unsafe { __uninit(&mut repr).cast::<#ident #ty_generics>().write(value) }
1411 repr
1412 }
1413 })
1414 } else {
1415 None
1416 };
1417
1418 let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1419 let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1420 let unsafe_token = format_ident!("unsafe", span = begin_span);
1421
1422 quote_spanned! {end_span=>
1423 #unsafe_token impl #impl_generics ::cxx::private::UniquePtrTarget for #ident #ty_generics {
1424 fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1425 f.write_str(#name)
1426 }
1427 fn __null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1428 extern "C" {
1429 #[link_name = #link_null]
1430 fn __null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1431 }
1432 let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1433 unsafe { __null(&mut repr) }
1434 repr
1435 }
1436 #new_method
1437 unsafe fn __raw(raw: *mut Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1438 extern "C" {
1439 #[link_name = #link_raw]
1440 fn __raw(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::core::ffi::c_void);
1441 }
1442 let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1443 __raw(&mut repr, raw.cast());
1444 repr
1445 }
1446 unsafe fn __get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const Self {
1447 extern "C" {
1448 #[link_name = #link_get]
1449 fn __get(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::core::ffi::c_void;
1450 }
1451 __get(&repr).cast()
1452 }
1453 unsafe fn __release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut Self {
1454 extern "C" {
1455 #[link_name = #link_release]
1456 fn __release(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1457 }
1458 __release(&mut repr).cast()
1459 }
1460 unsafe fn __drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
1461 extern "C" {
1462 #[link_name = #link_drop]
1463 fn __drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1464 }
1465 __drop(&mut repr);
1466 }
1467 }
1468 }
1469 }
1470
expand_shared_ptr( key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>, ) -> TokenStream1471 fn expand_shared_ptr(
1472 key: NamedImplKey,
1473 types: &Types,
1474 explicit_impl: Option<&Impl>,
1475 ) -> TokenStream {
1476 let ident = key.rust;
1477 let name = ident.to_string();
1478 let resolve = types.resolve(ident);
1479 let prefix = format!("cxxbridge1$shared_ptr${}$", resolve.name.to_symbol());
1480 let link_null = format!("{}null", prefix);
1481 let link_uninit = format!("{}uninit", prefix);
1482 let link_clone = format!("{}clone", prefix);
1483 let link_get = format!("{}get", prefix);
1484 let link_drop = format!("{}drop", prefix);
1485
1486 let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1487
1488 let can_construct_from_value = types.is_maybe_trivial(ident);
1489 let new_method = if can_construct_from_value {
1490 Some(quote! {
1491 unsafe fn __new(value: Self, new: *mut ::cxx::core::ffi::c_void) {
1492 extern "C" {
1493 #[link_name = #link_uninit]
1494 fn __uninit(new: *mut ::cxx::core::ffi::c_void) -> *mut ::cxx::core::ffi::c_void;
1495 }
1496 __uninit(new).cast::<#ident #ty_generics>().write(value);
1497 }
1498 })
1499 } else {
1500 None
1501 };
1502
1503 let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1504 let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1505 let unsafe_token = format_ident!("unsafe", span = begin_span);
1506
1507 quote_spanned! {end_span=>
1508 #unsafe_token impl #impl_generics ::cxx::private::SharedPtrTarget for #ident #ty_generics {
1509 fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1510 f.write_str(#name)
1511 }
1512 unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
1513 extern "C" {
1514 #[link_name = #link_null]
1515 fn __null(new: *mut ::cxx::core::ffi::c_void);
1516 }
1517 __null(new);
1518 }
1519 #new_method
1520 unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
1521 extern "C" {
1522 #[link_name = #link_clone]
1523 fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
1524 }
1525 __clone(this, new);
1526 }
1527 unsafe fn __get(this: *const ::cxx::core::ffi::c_void) -> *const Self {
1528 extern "C" {
1529 #[link_name = #link_get]
1530 fn __get(this: *const ::cxx::core::ffi::c_void) -> *const ::cxx::core::ffi::c_void;
1531 }
1532 __get(this).cast()
1533 }
1534 unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
1535 extern "C" {
1536 #[link_name = #link_drop]
1537 fn __drop(this: *mut ::cxx::core::ffi::c_void);
1538 }
1539 __drop(this);
1540 }
1541 }
1542 }
1543 }
1544
expand_weak_ptr(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream1545 fn expand_weak_ptr(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1546 let ident = key.rust;
1547 let name = ident.to_string();
1548 let resolve = types.resolve(ident);
1549 let prefix = format!("cxxbridge1$weak_ptr${}$", resolve.name.to_symbol());
1550 let link_null = format!("{}null", prefix);
1551 let link_clone = format!("{}clone", prefix);
1552 let link_downgrade = format!("{}downgrade", prefix);
1553 let link_upgrade = format!("{}upgrade", prefix);
1554 let link_drop = format!("{}drop", prefix);
1555
1556 let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1557
1558 let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1559 let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1560 let unsafe_token = format_ident!("unsafe", span = begin_span);
1561
1562 quote_spanned! {end_span=>
1563 #unsafe_token impl #impl_generics ::cxx::private::WeakPtrTarget for #ident #ty_generics {
1564 fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1565 f.write_str(#name)
1566 }
1567 unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
1568 extern "C" {
1569 #[link_name = #link_null]
1570 fn __null(new: *mut ::cxx::core::ffi::c_void);
1571 }
1572 __null(new);
1573 }
1574 unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
1575 extern "C" {
1576 #[link_name = #link_clone]
1577 fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
1578 }
1579 __clone(this, new);
1580 }
1581 unsafe fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void) {
1582 extern "C" {
1583 #[link_name = #link_downgrade]
1584 fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void);
1585 }
1586 __downgrade(shared, weak);
1587 }
1588 unsafe fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void) {
1589 extern "C" {
1590 #[link_name = #link_upgrade]
1591 fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void);
1592 }
1593 __upgrade(weak, shared);
1594 }
1595 unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
1596 extern "C" {
1597 #[link_name = #link_drop]
1598 fn __drop(this: *mut ::cxx::core::ffi::c_void);
1599 }
1600 __drop(this);
1601 }
1602 }
1603 }
1604 }
1605
expand_cxx_vector( key: NamedImplKey, explicit_impl: Option<&Impl>, types: &Types, ) -> TokenStream1606 fn expand_cxx_vector(
1607 key: NamedImplKey,
1608 explicit_impl: Option<&Impl>,
1609 types: &Types,
1610 ) -> TokenStream {
1611 let elem = key.rust;
1612 let name = elem.to_string();
1613 let resolve = types.resolve(elem);
1614 let prefix = format!("cxxbridge1$std$vector${}$", resolve.name.to_symbol());
1615 let link_size = format!("{}size", prefix);
1616 let link_get_unchecked = format!("{}get_unchecked", prefix);
1617 let link_push_back = format!("{}push_back", prefix);
1618 let link_pop_back = format!("{}pop_back", prefix);
1619 let unique_ptr_prefix = format!(
1620 "cxxbridge1$unique_ptr$std$vector${}$",
1621 resolve.name.to_symbol(),
1622 );
1623 let link_unique_ptr_null = format!("{}null", unique_ptr_prefix);
1624 let link_unique_ptr_raw = format!("{}raw", unique_ptr_prefix);
1625 let link_unique_ptr_get = format!("{}get", unique_ptr_prefix);
1626 let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
1627 let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix);
1628
1629 let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1630
1631 let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1632 let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1633 let unsafe_token = format_ident!("unsafe", span = begin_span);
1634
1635 let can_pass_element_by_value = types.is_maybe_trivial(elem);
1636 let by_value_methods = if can_pass_element_by_value {
1637 Some(quote_spanned! {end_span=>
1638 unsafe fn __push_back(
1639 this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
1640 value: &mut ::cxx::core::mem::ManuallyDrop<Self>,
1641 ) {
1642 extern "C" {
1643 #[link_name = #link_push_back]
1644 fn __push_back #impl_generics(
1645 this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
1646 value: *mut ::cxx::core::ffi::c_void,
1647 );
1648 }
1649 __push_back(this, value as *mut ::cxx::core::mem::ManuallyDrop<Self> as *mut ::cxx::core::ffi::c_void);
1650 }
1651 unsafe fn __pop_back(
1652 this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
1653 out: &mut ::cxx::core::mem::MaybeUninit<Self>,
1654 ) {
1655 extern "C" {
1656 #[link_name = #link_pop_back]
1657 fn __pop_back #impl_generics(
1658 this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
1659 out: *mut ::cxx::core::ffi::c_void,
1660 );
1661 }
1662 __pop_back(this, out as *mut ::cxx::core::mem::MaybeUninit<Self> as *mut ::cxx::core::ffi::c_void);
1663 }
1664 })
1665 } else {
1666 None
1667 };
1668
1669 quote_spanned! {end_span=>
1670 #unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics {
1671 fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1672 f.write_str(#name)
1673 }
1674 fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
1675 extern "C" {
1676 #[link_name = #link_size]
1677 fn __vector_size #impl_generics(_: &::cxx::CxxVector<#elem #ty_generics>) -> usize;
1678 }
1679 unsafe { __vector_size(v) }
1680 }
1681 unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector<Self>, pos: usize) -> *mut Self {
1682 extern "C" {
1683 #[link_name = #link_get_unchecked]
1684 fn __get_unchecked #impl_generics(
1685 v: *mut ::cxx::CxxVector<#elem #ty_generics>,
1686 pos: usize,
1687 ) -> *mut ::cxx::core::ffi::c_void;
1688 }
1689 __get_unchecked(v, pos) as *mut Self
1690 }
1691 #by_value_methods
1692 fn __unique_ptr_null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1693 extern "C" {
1694 #[link_name = #link_unique_ptr_null]
1695 fn __unique_ptr_null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1696 }
1697 let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1698 unsafe { __unique_ptr_null(&mut repr) }
1699 repr
1700 }
1701 unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1702 extern "C" {
1703 #[link_name = #link_unique_ptr_raw]
1704 fn __unique_ptr_raw #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::CxxVector<#elem #ty_generics>);
1705 }
1706 let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1707 __unique_ptr_raw(&mut repr, raw);
1708 repr
1709 }
1710 unsafe fn __unique_ptr_get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<Self> {
1711 extern "C" {
1712 #[link_name = #link_unique_ptr_get]
1713 fn __unique_ptr_get #impl_generics(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<#elem #ty_generics>;
1714 }
1715 __unique_ptr_get(&repr)
1716 }
1717 unsafe fn __unique_ptr_release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<Self> {
1718 extern "C" {
1719 #[link_name = #link_unique_ptr_release]
1720 fn __unique_ptr_release #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<#elem #ty_generics>;
1721 }
1722 __unique_ptr_release(&mut repr)
1723 }
1724 unsafe fn __unique_ptr_drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
1725 extern "C" {
1726 #[link_name = #link_unique_ptr_drop]
1727 fn __unique_ptr_drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1728 }
1729 __unique_ptr_drop(&mut repr);
1730 }
1731 }
1732 }
1733 }
1734
expand_return_type(ret: &Option<Type>) -> TokenStream1735 fn expand_return_type(ret: &Option<Type>) -> TokenStream {
1736 match ret {
1737 Some(ret) => quote!(-> #ret),
1738 None => TokenStream::new(),
1739 }
1740 }
1741
indirect_return(sig: &Signature, types: &Types) -> bool1742 fn indirect_return(sig: &Signature, types: &Types) -> bool {
1743 sig.ret
1744 .as_ref()
1745 .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
1746 }
1747
expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream1748 fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
1749 match ty {
1750 Type::Ident(ident) if ident.rust == RustString => {
1751 let span = ident.rust.span();
1752 quote_spanned!(span=> ::cxx::private::RustString)
1753 }
1754 Type::RustBox(ty) | Type::UniquePtr(ty) => {
1755 let span = ty.name.span();
1756 if proper && types.is_considered_improper_ctype(&ty.inner) {
1757 quote_spanned!(span=> *mut ::cxx::core::ffi::c_void)
1758 } else {
1759 let inner = expand_extern_type(&ty.inner, types, proper);
1760 quote_spanned!(span=> *mut #inner)
1761 }
1762 }
1763 Type::RustVec(ty) => {
1764 let span = ty.name.span();
1765 let langle = ty.langle;
1766 let elem = expand_extern_type(&ty.inner, types, proper);
1767 let rangle = ty.rangle;
1768 quote_spanned!(span=> ::cxx::private::RustVec #langle #elem #rangle)
1769 }
1770 Type::Ref(ty) => {
1771 let ampersand = ty.ampersand;
1772 let lifetime = &ty.lifetime;
1773 let mutability = ty.mutability;
1774 match &ty.inner {
1775 Type::Ident(ident) if ident.rust == RustString => {
1776 let span = ident.rust.span();
1777 quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustString)
1778 }
1779 Type::RustVec(ty) => {
1780 let span = ty.name.span();
1781 let langle = ty.langle;
1782 let inner = expand_extern_type(&ty.inner, types, proper);
1783 let rangle = ty.rangle;
1784 quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustVec #langle #inner #rangle)
1785 }
1786 inner if proper && types.is_considered_improper_ctype(inner) => {
1787 let star = Token;
1788 match ty.mutable {
1789 false => quote!(#star const ::cxx::core::ffi::c_void),
1790 true => quote!(#star #mutability ::cxx::core::ffi::c_void),
1791 }
1792 }
1793 _ => quote!(#ty),
1794 }
1795 }
1796 Type::Ptr(ty) => {
1797 if proper && types.is_considered_improper_ctype(&ty.inner) {
1798 let star = ty.star;
1799 let mutability = ty.mutability;
1800 let constness = ty.constness;
1801 quote!(#star #mutability #constness ::cxx::core::ffi::c_void)
1802 } else {
1803 quote!(#ty)
1804 }
1805 }
1806 Type::Str(ty) => {
1807 let span = ty.ampersand.span;
1808 let rust_str = Ident::new("RustStr", syn::spanned::Spanned::span(&ty.inner));
1809 quote_spanned!(span=> ::cxx::private::#rust_str)
1810 }
1811 Type::SliceRef(ty) => {
1812 let span = ty.ampersand.span;
1813 let rust_slice = Ident::new("RustSlice", ty.bracket.span.join());
1814 quote_spanned!(span=> ::cxx::private::#rust_slice)
1815 }
1816 _ => quote!(#ty),
1817 }
1818 }
1819
expand_extern_return_type(ret: &Option<Type>, types: &Types, proper: bool) -> TokenStream1820 fn expand_extern_return_type(ret: &Option<Type>, types: &Types, proper: bool) -> TokenStream {
1821 let ret = match ret {
1822 Some(ret) if !types.needs_indirect_abi(ret) => ret,
1823 _ => return TokenStream::new(),
1824 };
1825 let ty = expand_extern_type(ret, types, proper);
1826 quote!(-> #ty)
1827 }
1828