blob: 09373ff1d233a064e5e5d2f6126043f383eb3985 [file] [log] [blame]
David Tolnayd8ad9702020-11-27 12:43:59 -08001use crate::derive;
David Tolnaya52602b2020-03-06 10:24:34 -08002use crate::syntax::atom::Atom::{self, *};
David Tolnay05ef6ff2020-08-29 11:27:05 -07003use crate::syntax::file::Module;
David Tolnay0dd85ff2020-05-03 23:43:33 -07004use crate::syntax::report::Errors;
David Tolnay891061b2020-04-19 22:42:33 -07005use crate::syntax::symbol::Symbol;
David Tolnay3caa50a2020-04-19 21:25:34 -07006use crate::syntax::{
David Tolnayb247df12020-11-27 12:06:12 -08007 self, check, mangle, Api, Enum, ExternFn, ExternType, Impl, Pair, ResolvableName, Signature,
David Tolnayd8ad9702020-11-27 12:43:59 -08008 Struct, Type, TypeAlias, Types,
David Tolnay3caa50a2020-04-19 21:25:34 -07009};
David Tolnay0531f432020-10-03 23:50:28 -070010use proc_macro2::{Ident, Span, TokenStream};
David Tolnayf9ffb932020-04-20 02:22:57 -070011use quote::{format_ident, quote, quote_spanned, ToTokens};
David Tolnay05ef6ff2020-08-29 11:27:05 -070012use std::mem;
13use syn::{parse_quote, Result, Token};
David Tolnay7db73692019-10-20 14:51:12 -040014
David Tolnay3c64a4e2020-08-29 14:07:38 -070015pub fn bridge(mut ffi: Module) -> Result<TokenStream> {
David Tolnay0dd85ff2020-05-03 23:43:33 -070016 let ref mut errors = Errors::new();
David Tolnay05ef6ff2020-08-29 11:27:05 -070017 let content = mem::take(&mut ffi.content);
David Tolnay805dca32020-08-29 19:09:55 -070018 let trusted = ffi.unsafety.is_some();
Adrian Taylorc8713432020-10-21 18:20:55 -070019 let namespace = &ffi.namespace;
20 let ref apis = syntax::parse_items(errors, content, trusted, namespace);
David Tolnay52759782020-05-03 23:59:40 -070021 let ref types = Types::collect(errors, apis);
22 errors.propagate()?;
Adrian Taylorc8713432020-10-21 18:20:55 -070023 check::typecheck(errors, apis, types);
David Tolnay0dd85ff2020-05-03 23:43:33 -070024 errors.propagate()?;
David Tolnay7db73692019-10-20 14:51:12 -040025
David Tolnay3c64a4e2020-08-29 14:07:38 -070026 Ok(expand(ffi, apis, types))
David Tolnaycbf3f032020-05-03 23:51:14 -070027}
28
David Tolnay3c64a4e2020-08-29 14:07:38 -070029fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
David Tolnay7db73692019-10-20 14:51:12 -040030 let mut expanded = TokenStream::new();
31 let mut hidden = TokenStream::new();
David Tolnay7db73692019-10-20 14:51:12 -040032
David Tolnay2ec14632020-05-04 00:47:10 -070033 for api in apis {
David Tolnay7db73692019-10-20 14:51:12 -040034 if let Api::RustType(ety) = api {
David Tolnay62cae8e2020-11-17 07:54:54 -080035 expanded.extend(expand_rust_type_import(ety));
David Tolnayc8361022020-08-25 21:57:53 -070036 hidden.extend(expand_rust_type_assert_sized(ety));
David Tolnay7db73692019-10-20 14:51:12 -040037 }
38 }
39
David Tolnay2ec14632020-05-04 00:47:10 -070040 for api in apis {
David Tolnay7db73692019-10-20 14:51:12 -040041 match api {
David Tolnay62cae8e2020-11-17 07:54:54 -080042 Api::Include(_) | Api::Impl(_) => {}
Adrian Taylorc8713432020-10-21 18:20:55 -070043 Api::Struct(strct) => expanded.extend(expand_struct(strct)),
44 Api::Enum(enm) => expanded.extend(expand_enum(enm)),
Joel Galenson905eb2e2020-05-04 14:58:14 -070045 Api::CxxType(ety) => {
David Tolnay17a934c2020-11-02 00:40:04 -080046 let ident = &ety.name.rust;
47 if !types.structs.contains_key(ident) && !types.enums.contains_key(ident) {
Adrian Taylorc8713432020-10-21 18:20:55 -070048 expanded.extend(expand_cxx_type(ety));
David Tolnay9eef6092020-11-15 17:56:41 -080049 hidden.extend(expand_cxx_type_assert_pinned(ety));
Joel Galenson905eb2e2020-05-04 14:58:14 -070050 }
51 }
David Tolnay7db73692019-10-20 14:51:12 -040052 Api::CxxFunction(efn) => {
Adrian Taylorc8713432020-10-21 18:20:55 -070053 expanded.extend(expand_cxx_function_shim(efn, types));
David Tolnay7db73692019-10-20 14:51:12 -040054 }
David Tolnay62cae8e2020-11-17 07:54:54 -080055 Api::RustType(ety) => expanded.extend(expand_rust_type_impl(ety)),
Adrian Taylorc8713432020-10-21 18:20:55 -070056 Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)),
David Tolnay5f9e8ca2020-05-07 17:21:05 -070057 Api::TypeAlias(alias) => {
58 expanded.extend(expand_type_alias(alias));
Adrian Taylorc8713432020-10-21 18:20:55 -070059 hidden.extend(expand_type_alias_verify(alias, types));
David Tolnay5f9e8ca2020-05-07 17:21:05 -070060 }
David Tolnay7db73692019-10-20 14:51:12 -040061 }
62 }
63
64 for ty in types {
David Tolnay0531f432020-10-03 23:50:28 -070065 let explicit_impl = types.explicit_impls.get(ty);
David Tolnay7db73692019-10-20 14:51:12 -040066 if let Type::RustBox(ty) = ty {
67 if let Type::Ident(ident) = &ty.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -070068 if Atom::from(&ident.rust).is_none() {
69 hidden.extend(expand_rust_box(ident, types));
David Tolnay7db73692019-10-20 14:51:12 -040070 }
71 }
Myron Ahneba35cf2020-02-05 19:41:51 +070072 } else if let Type::RustVec(ty) = ty {
73 if let Type::Ident(ident) = &ty.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -070074 if Atom::from(&ident.rust).is_none() {
75 hidden.extend(expand_rust_vec(ident, types));
David Tolnaya006bca2020-04-25 11:28:13 -070076 }
Myron Ahneba35cf2020-02-05 19:41:51 +070077 }
David Tolnay7db73692019-10-20 14:51:12 -040078 } else if let Type::UniquePtr(ptr) = ty {
79 if let Type::Ident(ident) = &ptr.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -070080 if Atom::from(&ident.rust).is_none()
81 && (explicit_impl.is_some() || !types.aliases.contains_key(&ident.rust))
David Tolnay7e69f892020-10-03 22:20:22 -070082 {
Adrian Taylorc8713432020-10-21 18:20:55 -070083 expanded.extend(expand_unique_ptr(ident, types, explicit_impl));
Myron Ahneba35cf2020-02-05 19:41:51 +070084 }
85 }
David Tolnay4377a9e2020-04-24 15:20:26 -070086 } else if let Type::CxxVector(ptr) = ty {
Myron Ahneba35cf2020-02-05 19:41:51 +070087 if let Type::Ident(ident) = &ptr.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -070088 if Atom::from(&ident.rust).is_none()
89 && (explicit_impl.is_some() || !types.aliases.contains_key(&ident.rust))
David Tolnay7e69f892020-10-03 22:20:22 -070090 {
David Tolnay17631102020-04-24 19:01:30 -070091 // Generate impl for CxxVector<T> if T is a struct or opaque
92 // C++ type. Impl for primitives is already provided by cxx
93 // crate.
Adrian Taylorc8713432020-10-21 18:20:55 -070094 expanded.extend(expand_cxx_vector(ident, explicit_impl, types));
David Tolnay7db73692019-10-20 14:51:12 -040095 }
96 }
97 }
98 }
99
100 // Work around https://github.com/rust-lang/rust/issues/67851.
101 if !hidden.is_empty() {
102 expanded.extend(quote! {
103 #[doc(hidden)]
104 const _: () = {
105 #hidden
106 };
107 });
108 }
109
110 let attrs = ffi
111 .attrs
112 .into_iter()
113 .filter(|attr| attr.path.is_ident("doc"));
114 let vis = &ffi.vis;
David Tolnaycbf3f032020-05-03 23:51:14 -0700115 let ident = &ffi.ident;
David Tolnay7db73692019-10-20 14:51:12 -0400116
David Tolnaycbf3f032020-05-03 23:51:14 -0700117 quote! {
David Tolnay7db73692019-10-20 14:51:12 -0400118 #(#attrs)*
119 #[deny(improper_ctypes)]
120 #[allow(non_snake_case)]
121 #vis mod #ident {
122 #expanded
123 }
David Tolnaycbf3f032020-05-03 23:51:14 -0700124 }
David Tolnay7db73692019-10-20 14:51:12 -0400125}
126
Adrian Taylorc8713432020-10-21 18:20:55 -0700127fn expand_struct(strct: &Struct) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800128 let ident = &strct.name.rust;
David Tolnay7db73692019-10-20 14:51:12 -0400129 let doc = &strct.doc;
David Tolnay17a934c2020-11-02 00:40:04 -0800130 let type_id = type_id(&strct.name);
David Tolnay7db73692019-10-20 14:51:12 -0400131 let fields = strct.fields.iter().map(|field| {
132 // This span on the pub makes "private type in public interface" errors
133 // appear in the right place.
134 let vis = Token![pub](field.ident.span());
135 quote!(#vis #field)
136 });
David Tolnayd8ad9702020-11-27 12:43:59 -0800137 let derived_traits = derive::expand_struct(strct);
David Tolnay8684cc52020-10-07 17:09:48 -0700138
David Tolnayd8ad9702020-11-27 12:43:59 -0800139 quote! {
David Tolnay7db73692019-10-20 14:51:12 -0400140 #doc
David Tolnay7db73692019-10-20 14:51:12 -0400141 #[repr(C)]
142 pub struct #ident {
143 #(#fields,)*
144 }
David Tolnay8684cc52020-10-07 17:09:48 -0700145
146 unsafe impl ::cxx::ExternType for #ident {
147 type Id = #type_id;
148 type Kind = ::cxx::kind::Trivial;
149 }
David Tolnay4a0c53a2020-11-27 11:46:16 -0800150
David Tolnayd8ad9702020-11-27 12:43:59 -0800151 #derived_traits
David Tolnay7db73692019-10-20 14:51:12 -0400152 }
153}
154
Adrian Taylorc8713432020-10-21 18:20:55 -0700155fn expand_enum(enm: &Enum) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800156 let ident = &enm.name.rust;
Joel Galensonc03402a2020-04-23 17:31:09 -0700157 let doc = &enm.doc;
David Tolnayc605e6f2020-05-10 23:37:12 -0700158 let repr = enm.repr;
David Tolnay17a934c2020-11-02 00:40:04 -0800159 let type_id = type_id(&enm.name);
Joel Galenson88547732020-05-05 08:23:42 -0700160 let variants = enm.variants.iter().map(|variant| {
161 let variant_ident = &variant.ident;
162 let discriminant = &variant.discriminant;
163 Some(quote! {
164 pub const #variant_ident: Self = #ident { repr: #discriminant };
165 })
166 });
David Tolnay05213732020-11-27 12:52:10 -0800167 let derives = quote! {
168 // Required to be derived in order for the enum's "variants" to be
169 // usable in patterns.
170 #[derive(::std::cmp::PartialEq, ::std::cmp::Eq)]
171 };
David Tolnay8684cc52020-10-07 17:09:48 -0700172
Joel Galensonc03402a2020-04-23 17:31:09 -0700173 quote! {
174 #doc
David Tolnay05213732020-11-27 12:52:10 -0800175 #derives
Joel Galensonc03402a2020-04-23 17:31:09 -0700176 #[repr(transparent)]
Joel Galensondb1ec312020-05-01 13:57:32 -0700177 pub struct #ident {
David Tolnayc605e6f2020-05-10 23:37:12 -0700178 pub repr: #repr,
Joel Galensondb1ec312020-05-01 13:57:32 -0700179 }
Joel Galensonc03402a2020-04-23 17:31:09 -0700180
181 #[allow(non_upper_case_globals)]
182 impl #ident {
David Tolnayd7984c22020-04-30 20:09:31 -0700183 #(#variants)*
Joel Galensonc03402a2020-04-23 17:31:09 -0700184 }
David Tolnay8684cc52020-10-07 17:09:48 -0700185
186 unsafe impl ::cxx::ExternType for #ident {
187 type Id = #type_id;
188 type Kind = ::cxx::kind::Trivial;
189 }
David Tolnay4a0c53a2020-11-27 11:46:16 -0800190
191 impl ::std::marker::Copy for #ident {}
192
193 impl ::std::clone::Clone for #ident {
194 fn clone(&self) -> Self {
195 *self
196 }
197 }
Joel Galensonc03402a2020-04-23 17:31:09 -0700198 }
199}
200
Adrian Taylorc8713432020-10-21 18:20:55 -0700201fn expand_cxx_type(ety: &ExternType) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800202 let ident = &ety.name.rust;
David Tolnay7db73692019-10-20 14:51:12 -0400203 let doc = &ety.doc;
David Tolnay17a934c2020-11-02 00:40:04 -0800204 let type_id = type_id(&ety.name);
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700205
David Tolnay7db73692019-10-20 14:51:12 -0400206 quote! {
207 #doc
208 #[repr(C)]
209 pub struct #ident {
210 _private: ::cxx::private::Opaque,
211 }
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700212
213 unsafe impl ::cxx::ExternType for #ident {
214 type Id = #type_id;
David Tolnay38f5ad62020-10-03 18:06:44 -0700215 type Kind = ::cxx::kind::Opaque;
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700216 }
David Tolnay7db73692019-10-20 14:51:12 -0400217 }
218}
219
David Tolnay9eef6092020-11-15 17:56:41 -0800220fn expand_cxx_type_assert_pinned(ety: &ExternType) -> TokenStream {
221 let ident = &ety.name.rust;
222 let infer = Token![_](ident.span());
223
224 quote! {
225 let _ = {
226 // Derived from https://github.com/nvzqz/static-assertions-rs.
227 trait __AmbiguousIfImpl<A> {
228 fn infer() {}
229 }
230
231 impl<T: ?Sized> __AmbiguousIfImpl<()> for T {}
232
233 #[allow(dead_code)]
234 struct __Invalid;
235
236 impl<T: ?Sized + Unpin> __AmbiguousIfImpl<__Invalid> for T {}
237
238 // If there is only one specialized trait impl, type inference with
239 // `_` can be resolved and this can compile. Fails to compile if
240 // user has added a manual Unpin impl for their opaque C++ type as
241 // then `__AmbiguousIfImpl<__Invalid>` also exists.
242 <#ident as __AmbiguousIfImpl<#infer>>::infer
243 };
244 }
245}
246
Adrian Taylorc8713432020-10-21 18:20:55 -0700247fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
David Tolnay9938b642020-11-15 18:11:40 -0800248 let generics = &efn.generics;
David Tolnay18ba92c2020-04-22 16:17:30 -0700249 let receiver = efn.receiver.iter().map(|receiver| {
250 let receiver_type = receiver.ty();
251 quote!(_: #receiver_type)
252 });
David Tolnay39d575f2020-03-03 00:10:56 -0800253 let args = efn.args.iter().map(|arg| {
254 let ident = &arg.ident;
David Tolnay2f090422020-11-02 18:25:35 -0800255 let ty = expand_extern_type(&arg.ty, types, true);
David Tolnaya46a2372020-03-06 10:03:48 -0800256 if arg.ty == RustString {
257 quote!(#ident: *const #ty)
David Tolnay313b10e2020-04-25 16:30:51 -0700258 } else if let Type::RustVec(_) = arg.ty {
259 quote!(#ident: *const #ty)
David Tolnay75dca2e2020-03-25 20:17:52 -0700260 } else if let Type::Fn(_) = arg.ty {
261 quote!(#ident: ::cxx::private::FatFunction)
David Tolnaya46a2372020-03-06 10:03:48 -0800262 } else if types.needs_indirect_abi(&arg.ty) {
David Tolnay39d575f2020-03-03 00:10:56 -0800263 quote!(#ident: *mut #ty)
264 } else {
265 quote!(#ident: #ty)
266 }
267 });
Joel Galenson3d4f6122020-04-07 15:54:05 -0700268 let all_args = receiver.chain(args);
David Tolnayebef4a22020-03-17 15:33:47 -0700269 let ret = if efn.throws {
270 quote!(-> ::cxx::private::Result)
271 } else {
David Tolnay2f090422020-11-02 18:25:35 -0800272 expand_extern_return_type(&efn.ret, types, true)
David Tolnayebef4a22020-03-17 15:33:47 -0700273 };
David Tolnay7db73692019-10-20 14:51:12 -0400274 let mut outparam = None;
David Tolnay1e548172020-03-16 13:37:09 -0700275 if indirect_return(efn, types) {
David Tolnay2f090422020-11-02 18:25:35 -0800276 let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
David Tolnay7db73692019-10-20 14:51:12 -0400277 outparam = Some(quote!(__return: *mut #ret));
278 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700279 let link_name = mangle::extern_fn(efn, types);
David Tolnay17a934c2020-11-02 00:40:04 -0800280 let local_name = format_ident!("__{}", efn.name.rust);
David Tolnay7db73692019-10-20 14:51:12 -0400281 quote! {
282 #[link_name = #link_name]
David Tolnay9938b642020-11-15 18:11:40 -0800283 fn #local_name #generics(#(#all_args,)* #outparam) #ret;
David Tolnay7db73692019-10-20 14:51:12 -0400284 }
285}
286
Adrian Taylorc8713432020-10-21 18:20:55 -0700287fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
David Tolnay7db73692019-10-20 14:51:12 -0400288 let doc = &efn.doc;
Adrian Taylorc8713432020-10-21 18:20:55 -0700289 let decl = expand_cxx_function_decl(efn, types);
David Tolnayfb6e3862020-04-20 01:33:23 -0700290 let receiver = efn.receiver.iter().map(|receiver| {
David Tolnayf9ffb932020-04-20 02:22:57 -0700291 let var = receiver.var;
David Tolnayc9673842020-11-15 16:26:10 -0800292 if receiver.pinned {
293 let ty = receiver.ty();
294 quote!(#var: #ty)
295 } else {
296 let ampersand = receiver.ampersand;
David Tolnay9938b642020-11-15 18:11:40 -0800297 let lifetime = &receiver.lifetime;
David Tolnayc9673842020-11-15 16:26:10 -0800298 let mutability = receiver.mutability;
David Tolnay9938b642020-11-15 18:11:40 -0800299 quote!(#ampersand #lifetime #mutability #var)
David Tolnayc9673842020-11-15 16:26:10 -0800300 }
David Tolnayfb6e3862020-04-20 01:33:23 -0700301 });
Joel Galenson3d4f6122020-04-07 15:54:05 -0700302 let args = efn.args.iter().map(|arg| quote!(#arg));
303 let all_args = receiver.chain(args);
David Tolnayebef4a22020-03-17 15:33:47 -0700304 let ret = if efn.throws {
305 let ok = match &efn.ret {
306 Some(ret) => quote!(#ret),
307 None => quote!(()),
308 };
309 quote!(-> ::std::result::Result<#ok, ::cxx::Exception>)
310 } else {
311 expand_return_type(&efn.ret)
312 };
David Tolnay1e548172020-03-16 13:37:09 -0700313 let indirect_return = indirect_return(efn, types);
David Tolnayf9ffb932020-04-20 02:22:57 -0700314 let receiver_var = efn
315 .receiver
316 .iter()
317 .map(|receiver| receiver.var.to_token_stream());
Joel Galenson3d4f6122020-04-07 15:54:05 -0700318 let arg_vars = efn.args.iter().map(|arg| {
David Tolnay7db73692019-10-20 14:51:12 -0400319 let var = &arg.ident;
320 match &arg.ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700321 Type::Ident(ident) if ident.rust == RustString => {
David Tolnaya46a2372020-03-06 10:03:48 -0800322 quote!(#var.as_mut_ptr() as *const ::cxx::private::RustString)
David Tolnay7db73692019-10-20 14:51:12 -0400323 }
324 Type::RustBox(_) => quote!(::std::boxed::Box::into_raw(#var)),
David Tolnaybf7ae812020-11-16 23:31:45 -0800325 Type::UniquePtr(_) => quote!(::cxx::UniquePtr::into_raw(#var)),
David Tolnay313b10e2020-04-25 16:30:51 -0700326 Type::RustVec(_) => quote!(#var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
David Tolnay7db73692019-10-20 14:51:12 -0400327 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800328 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
329 false => quote!(::cxx::private::RustString::from_ref(#var)),
330 true => quote!(::cxx::private::RustString::from_mut(#var)),
David Tolnayf1c7f322020-08-27 00:46:01 -0700331 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800332 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
333 false => quote!(::cxx::private::RustVec::from_ref_vec_string(#var)),
334 true => quote!(::cxx::private::RustVec::from_mut_vec_string(#var)),
David Tolnay33f56ad2020-08-27 17:06:35 -0700335 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800336 Type::RustVec(_) => match ty.mutable {
337 false => quote!(::cxx::private::RustVec::from_ref(#var)),
338 true => quote!(::cxx::private::RustVec::from_mut(#var)),
David Tolnayf1c7f322020-08-27 00:46:01 -0700339 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800340 inner if types.is_considered_improper_ctype(inner) => match ty.mutable {
341 false => quote!(#var as *const #inner as *const ::std::ffi::c_void),
342 true => quote!(#var as *mut #inner as *mut ::std::ffi::c_void),
David Tolnay4cb97672020-11-02 16:13:34 -0800343 },
David Tolnay7db73692019-10-20 14:51:12 -0400344 _ => quote!(#var),
345 },
346 Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
David Tolnay73b72642020-11-25 17:44:05 -0800347 Type::SliceRef(ty) => match ty.mutable {
David Tolnay5515a9e2020-11-25 19:07:54 -0800348 false => quote!(::cxx::private::RustSlice::from_ref(#var)),
349 true => quote!(::cxx::private::RustSlice::from_mut(#var)),
David Tolnayc5629f02020-11-23 18:32:46 -0800350 },
David Tolnay7db73692019-10-20 14:51:12 -0400351 ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
352 _ => quote!(#var),
353 }
354 });
Joel Galenson3d4f6122020-04-07 15:54:05 -0700355 let vars = receiver_var.chain(arg_vars);
David Tolnay75dca2e2020-03-25 20:17:52 -0700356 let trampolines = efn
357 .args
358 .iter()
359 .filter_map(|arg| {
360 if let Type::Fn(f) = &arg.ty {
361 let var = &arg.ident;
Adrian Taylorc8713432020-10-21 18:20:55 -0700362 Some(expand_function_pointer_trampoline(efn, var, f, types))
David Tolnay75dca2e2020-03-25 20:17:52 -0700363 } else {
364 None
365 }
366 })
367 .collect::<TokenStream>();
David Tolnay7db73692019-10-20 14:51:12 -0400368 let mut setup = efn
369 .args
370 .iter()
371 .filter(|arg| types.needs_indirect_abi(&arg.ty))
372 .map(|arg| {
373 let var = &arg.ident;
374 // These are arguments for which C++ has taken ownership of the data
375 // behind the mut reference it received.
376 quote! {
David Tolnaycb4ee4b2020-04-24 11:28:08 -0700377 let mut #var = ::std::mem::MaybeUninit::new(#var);
David Tolnay7db73692019-10-20 14:51:12 -0400378 }
379 })
380 .collect::<TokenStream>();
David Tolnay17a934c2020-11-02 00:40:04 -0800381 let local_name = format_ident!("__{}", efn.name.rust);
David Tolnay7db73692019-10-20 14:51:12 -0400382 let call = if indirect_return {
David Tolnay2f090422020-11-02 18:25:35 -0800383 let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
David Tolnay7db73692019-10-20 14:51:12 -0400384 setup.extend(quote! {
385 let mut __return = ::std::mem::MaybeUninit::<#ret>::uninit();
David Tolnay7db73692019-10-20 14:51:12 -0400386 });
David Tolnay0d524852020-11-02 17:21:50 -0800387 setup.extend(if efn.throws {
388 quote! {
David Tolnayebef4a22020-03-17 15:33:47 -0700389 #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?;
David Tolnay0d524852020-11-02 17:21:50 -0800390 }
David Tolnayebef4a22020-03-17 15:33:47 -0700391 } else {
David Tolnay0d524852020-11-02 17:21:50 -0800392 quote! {
David Tolnayebef4a22020-03-17 15:33:47 -0700393 #local_name(#(#vars,)* __return.as_mut_ptr());
David Tolnay0d524852020-11-02 17:21:50 -0800394 }
395 });
396 quote!(__return.assume_init())
David Tolnayebef4a22020-03-17 15:33:47 -0700397 } else if efn.throws {
David Tolnay7db73692019-10-20 14:51:12 -0400398 quote! {
David Tolnayebef4a22020-03-17 15:33:47 -0700399 #local_name(#(#vars),*).exception()
David Tolnay7db73692019-10-20 14:51:12 -0400400 }
401 } else {
402 quote! {
403 #local_name(#(#vars),*)
404 }
405 };
David Tolnay2debdb22020-11-02 17:14:53 -0800406 let mut expr;
407 if efn.throws && efn.sig.ret.is_none() {
408 expr = call;
Myron Ahn84849302020-03-25 22:00:58 +0700409 } else {
David Tolnay0d524852020-11-02 17:21:50 -0800410 expr = match &efn.ret {
411 None => call,
412 Some(ret) => match ret {
413 Type::Ident(ident) if ident.rust == RustString => quote!(#call.into_string()),
414 Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#call)),
David Tolnaya1f02e52020-11-02 17:10:54 -0800415 Type::RustVec(vec) => {
416 if vec.inner == RustString {
David Tolnay0d524852020-11-02 17:21:50 -0800417 quote!(#call.into_vec_string())
David Tolnaya1f02e52020-11-02 17:10:54 -0800418 } else {
David Tolnay0d524852020-11-02 17:21:50 -0800419 quote!(#call.into_vec())
David Tolnaya1f02e52020-11-02 17:10:54 -0800420 }
David Tolnay33f56ad2020-08-27 17:06:35 -0700421 }
David Tolnaybf7ae812020-11-16 23:31:45 -0800422 Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#call)),
David Tolnaya1f02e52020-11-02 17:10:54 -0800423 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800424 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
425 false => quote!(#call.as_string()),
426 true => quote!(#call.as_mut_string()),
David Tolnaya1f02e52020-11-02 17:10:54 -0800427 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800428 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
429 false => quote!(#call.as_vec_string()),
430 true => quote!(#call.as_mut_vec_string()),
David Tolnaya1f02e52020-11-02 17:10:54 -0800431 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800432 Type::RustVec(_) => match ty.mutable {
433 false => quote!(#call.as_vec()),
434 true => quote!(#call.as_mut_vec()),
David Tolnaya1f02e52020-11-02 17:10:54 -0800435 },
David Tolnay4cb97672020-11-02 16:13:34 -0800436 inner if types.is_considered_improper_ctype(inner) => {
437 let mutability = ty.mutability;
438 quote!(&#mutability *#call.cast())
439 }
David Tolnay0d524852020-11-02 17:21:50 -0800440 _ => call,
David Tolnayf1c7f322020-08-27 00:46:01 -0700441 },
David Tolnay0d524852020-11-02 17:21:50 -0800442 Type::Str(_) => quote!(#call.as_str()),
David Tolnay5515a9e2020-11-25 19:07:54 -0800443 Type::SliceRef(slice) => {
444 let inner = &slice.inner;
445 match slice.mutable {
446 false => quote!(#call.as_slice::<#inner>()),
447 true => quote!(#call.as_mut_slice::<#inner>()),
448 }
449 }
David Tolnay0d524852020-11-02 17:21:50 -0800450 _ => call,
451 },
452 };
David Tolnay2debdb22020-11-02 17:14:53 -0800453 if efn.throws {
454 expr = quote!(::std::result::Result::Ok(#expr));
455 }
David Tolnaya1f02e52020-11-02 17:10:54 -0800456 };
David Tolnaye67bcf52020-09-06 23:50:44 -0700457 let mut dispatch = quote!(#setup #expr);
458 let unsafety = &efn.sig.unsafety;
459 if unsafety.is_none() {
460 dispatch = quote!(unsafe { #dispatch });
461 }
David Tolnay17a934c2020-11-02 00:40:04 -0800462 let ident = &efn.name.rust;
David Tolnay9938b642020-11-15 18:11:40 -0800463 let generics = &efn.generics;
David Tolnayc66cdbb2020-04-20 01:41:15 -0700464 let function_shim = quote! {
465 #doc
David Tolnay9938b642020-11-15 18:11:40 -0800466 pub #unsafety fn #ident #generics(#(#all_args,)*) #ret {
David Tolnayc66cdbb2020-04-20 01:41:15 -0700467 extern "C" {
468 #decl
David Tolnay7db73692019-10-20 14:51:12 -0400469 }
David Tolnayc66cdbb2020-04-20 01:41:15 -0700470 #trampolines
David Tolnaye67bcf52020-09-06 23:50:44 -0700471 #dispatch
David Tolnayc66cdbb2020-04-20 01:41:15 -0700472 }
473 };
474 match &efn.receiver {
475 None => function_shim,
476 Some(receiver) => {
David Tolnay05e11cc2020-04-20 02:13:56 -0700477 let receiver_type = &receiver.ty;
David Tolnayc66cdbb2020-04-20 01:41:15 -0700478 quote!(impl #receiver_type { #function_shim })
479 }
David Tolnay7db73692019-10-20 14:51:12 -0400480 }
481}
482
David Tolnay75dca2e2020-03-25 20:17:52 -0700483fn expand_function_pointer_trampoline(
David Tolnay75dca2e2020-03-25 20:17:52 -0700484 efn: &ExternFn,
485 var: &Ident,
486 sig: &Signature,
487 types: &Types,
488) -> TokenStream {
Adrian Taylorc8713432020-10-21 18:20:55 -0700489 let c_trampoline = mangle::c_trampoline(efn, var, types);
490 let r_trampoline = mangle::r_trampoline(efn, var, types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700491 let local_name = parse_quote!(__);
David Tolnay17a934c2020-11-02 00:40:04 -0800492 let catch_unwind_label = format!("::{}::{}", efn.name.rust, var);
David Tolnay75dca2e2020-03-25 20:17:52 -0700493 let shim = expand_rust_function_shim_impl(
494 sig,
495 types,
496 &r_trampoline,
497 local_name,
498 catch_unwind_label,
499 None,
500 );
501
502 quote! {
503 let #var = ::cxx::private::FatFunction {
504 trampoline: {
505 extern "C" {
506 #[link_name = #c_trampoline]
507 fn trampoline();
508 }
509 #shim
510 trampoline as usize as *const ()
511 },
512 ptr: #var as usize as *const (),
513 };
514 }
515}
516
David Tolnay62cae8e2020-11-17 07:54:54 -0800517fn expand_rust_type_import(ety: &ExternType) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800518 let ident = &ety.name.rust;
David Tolnay62cae8e2020-11-17 07:54:54 -0800519 let span = ident.span();
520
521 quote_spanned! {span=>
David Tolnay7db73692019-10-20 14:51:12 -0400522 use super::#ident;
523 }
524}
525
David Tolnay62cae8e2020-11-17 07:54:54 -0800526fn expand_rust_type_impl(ety: &ExternType) -> TokenStream {
527 let ident = &ety.name.rust;
528 let span = ident.span();
529 let unsafe_impl = quote_spanned!(ety.type_token.span=> unsafe impl);
530
531 quote_spanned! {span=>
532 #unsafe_impl ::cxx::private::RustType for #ident {}
533 }
534}
535
David Tolnayc8361022020-08-25 21:57:53 -0700536fn expand_rust_type_assert_sized(ety: &ExternType) -> TokenStream {
537 // Rustc will render as follows if not sized:
538 //
539 // type TheirType;
540 // -----^^^^^^^^^-
541 // | |
542 // | doesn't have a size known at compile-time
543 // required by this bound in `ffi::_::__AssertSized`
544
David Tolnay17a934c2020-11-02 00:40:04 -0800545 let ident = &ety.name.rust;
David Tolnayc8361022020-08-25 21:57:53 -0700546 let begin_span = Token![::](ety.type_token.span);
547 let sized = quote_spanned! {ety.semi_token.span=>
548 #begin_span std::marker::Sized
549 };
David Tolnay20fa62b2020-11-15 17:34:05 -0800550 let unpin = quote_spanned! {ety.semi_token.span=>
551 #begin_span std::marker::Unpin
552 };
David Tolnay17a934c2020-11-02 00:40:04 -0800553 quote_spanned! {ident.span()=>
David Tolnayc8361022020-08-25 21:57:53 -0700554 let _ = {
555 fn __AssertSized<T: ?#sized + #sized>() {}
David Tolnay20fa62b2020-11-15 17:34:05 -0800556 fn __AssertUnpin<T: #unpin>() {}
557 (__AssertSized::<#ident>, __AssertUnpin::<#ident>)
David Tolnayc8361022020-08-25 21:57:53 -0700558 };
559 }
560}
561
Adrian Taylorc8713432020-10-21 18:20:55 -0700562fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
563 let link_name = mangle::extern_fn(efn, types);
David Tolnay17a934c2020-11-02 00:40:04 -0800564 let local_name = format_ident!("__{}", efn.name.rust);
565 let catch_unwind_label = format!("::{}", efn.name.rust);
566 let invoke = Some(&efn.name.rust);
David Tolnay75dca2e2020-03-25 20:17:52 -0700567 expand_rust_function_shim_impl(
568 efn,
569 types,
570 &link_name,
571 local_name,
572 catch_unwind_label,
573 invoke,
574 )
575}
576
577fn expand_rust_function_shim_impl(
578 sig: &Signature,
579 types: &Types,
David Tolnay891061b2020-04-19 22:42:33 -0700580 link_name: &Symbol,
David Tolnay75dca2e2020-03-25 20:17:52 -0700581 local_name: Ident,
582 catch_unwind_label: String,
583 invoke: Option<&Ident>,
584) -> TokenStream {
David Tolnay9938b642020-11-15 18:11:40 -0800585 let generics = &sig.generics;
David Tolnayf9ffb932020-04-20 02:22:57 -0700586 let receiver_var = sig
587 .receiver
588 .as_ref()
589 .map(|receiver| quote_spanned!(receiver.var.span=> __self));
David Tolnay18ba92c2020-04-22 16:17:30 -0700590 let receiver = sig.receiver.as_ref().map(|receiver| {
591 let receiver_type = receiver.ty();
592 quote!(#receiver_var: #receiver_type)
593 });
David Tolnay75dca2e2020-03-25 20:17:52 -0700594 let args = sig.args.iter().map(|arg| {
David Tolnay39d575f2020-03-03 00:10:56 -0800595 let ident = &arg.ident;
David Tolnay2f090422020-11-02 18:25:35 -0800596 let ty = expand_extern_type(&arg.ty, types, false);
David Tolnay39d575f2020-03-03 00:10:56 -0800597 if types.needs_indirect_abi(&arg.ty) {
598 quote!(#ident: *mut #ty)
599 } else {
600 quote!(#ident: #ty)
601 }
602 });
David Tolnayf9ffb932020-04-20 02:22:57 -0700603 let all_args = receiver.into_iter().chain(args);
David Tolnay75dca2e2020-03-25 20:17:52 -0700604
David Tolnay3a45f2d2020-04-20 01:51:12 -0700605 let arg_vars = sig.args.iter().map(|arg| {
David Tolnay7db73692019-10-20 14:51:12 -0400606 let ident = &arg.ident;
David Tolnay17955e22020-01-20 17:58:24 -0800607 match &arg.ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700608 Type::Ident(i) if i.rust == RustString => {
David Tolnaycc3767f2020-03-06 10:41:51 -0800609 quote!(::std::mem::take((*#ident).as_mut_string()))
610 }
David Tolnay40226ab2020-03-03 00:05:35 -0800611 Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#ident)),
David Tolnay33f56ad2020-08-27 17:06:35 -0700612 Type::RustVec(vec) => {
613 if vec.inner == RustString {
614 quote!(::std::mem::take((*#ident).as_mut_vec_string()))
615 } else {
616 quote!(::std::mem::take((*#ident).as_mut_vec()))
617 }
618 }
David Tolnaybf7ae812020-11-16 23:31:45 -0800619 Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#ident)),
David Tolnay17955e22020-01-20 17:58:24 -0800620 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800621 Type::Ident(i) if i.rust == RustString => match ty.mutable {
622 false => quote!(#ident.as_string()),
623 true => quote!(#ident.as_mut_string()),
David Tolnayf1c7f322020-08-27 00:46:01 -0700624 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800625 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
626 false => quote!(#ident.as_vec_string()),
627 true => quote!(#ident.as_mut_vec_string()),
David Tolnay33f56ad2020-08-27 17:06:35 -0700628 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800629 Type::RustVec(_) => match ty.mutable {
630 false => quote!(#ident.as_vec()),
631 true => quote!(#ident.as_mut_vec()),
David Tolnayf1c7f322020-08-27 00:46:01 -0700632 },
David Tolnay40226ab2020-03-03 00:05:35 -0800633 _ => quote!(#ident),
David Tolnay17955e22020-01-20 17:58:24 -0800634 },
David Tolnay40226ab2020-03-03 00:05:35 -0800635 Type::Str(_) => quote!(#ident.as_str()),
David Tolnay5515a9e2020-11-25 19:07:54 -0800636 Type::SliceRef(slice) => {
637 let inner = &slice.inner;
638 match slice.mutable {
639 false => quote!(#ident.as_slice::<#inner>()),
640 true => quote!(#ident.as_mut_slice::<#inner>()),
641 }
642 }
David Tolnay40226ab2020-03-03 00:05:35 -0800643 ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
644 _ => quote!(#ident),
David Tolnay7db73692019-10-20 14:51:12 -0400645 }
646 });
David Tolnayf9ffb932020-04-20 02:22:57 -0700647 let vars = receiver_var.into_iter().chain(arg_vars);
David Tolnay75dca2e2020-03-25 20:17:52 -0700648
David Tolnay26219462020-11-09 19:47:28 -0800649 let wrap_super = invoke.map(|invoke| expand_rust_function_shim_super(sig, &local_name, invoke));
650
David Tolnay75dca2e2020-03-25 20:17:52 -0700651 let mut call = match invoke {
David Tolnay26219462020-11-09 19:47:28 -0800652 Some(_) => quote!(#local_name),
David Tolnayb8ebeb02020-10-31 23:52:06 -0700653 None => quote!(::std::mem::transmute::<*const (), #sig>(__extern)),
David Tolnay75dca2e2020-03-25 20:17:52 -0700654 };
655 call.extend(quote! { (#(#vars),*) });
656
David Tolnay22602b42020-09-21 18:04:05 -0400657 let conversion = sig.ret.as_ref().and_then(|ret| match ret {
Adrian Taylorc8713432020-10-21 18:20:55 -0700658 Type::Ident(ident) if ident.rust == RustString => {
659 Some(quote!(::cxx::private::RustString::from))
660 }
David Tolnay22602b42020-09-21 18:04:05 -0400661 Type::RustBox(_) => Some(quote!(::std::boxed::Box::into_raw)),
662 Type::RustVec(vec) => {
663 if vec.inner == RustString {
664 Some(quote!(::cxx::private::RustVec::from_vec_string))
665 } else {
666 Some(quote!(::cxx::private::RustVec::from))
David Tolnay7db73692019-10-20 14:51:12 -0400667 }
David Tolnay22602b42020-09-21 18:04:05 -0400668 }
David Tolnaybf7ae812020-11-16 23:31:45 -0800669 Type::UniquePtr(_) => Some(quote!(::cxx::UniquePtr::into_raw)),
David Tolnay22602b42020-09-21 18:04:05 -0400670 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800671 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
672 false => Some(quote!(::cxx::private::RustString::from_ref)),
673 true => Some(quote!(::cxx::private::RustString::from_mut)),
David Tolnay7db73692019-10-20 14:51:12 -0400674 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800675 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
676 false => Some(quote!(::cxx::private::RustVec::from_ref_vec_string)),
677 true => Some(quote!(::cxx::private::RustVec::from_mut_vec_string)),
David Tolnay22602b42020-09-21 18:04:05 -0400678 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800679 Type::RustVec(_) => match ty.mutable {
680 false => Some(quote!(::cxx::private::RustVec::from_ref)),
681 true => Some(quote!(::cxx::private::RustVec::from_mut)),
David Tolnay22602b42020-09-21 18:04:05 -0400682 },
David Tolnay7db73692019-10-20 14:51:12 -0400683 _ => None,
David Tolnay22602b42020-09-21 18:04:05 -0400684 },
685 Type::Str(_) => Some(quote!(::cxx::private::RustStr::from)),
David Tolnay73b72642020-11-25 17:44:05 -0800686 Type::SliceRef(ty) => match ty.mutable {
David Tolnay5515a9e2020-11-25 19:07:54 -0800687 false => Some(quote!(::cxx::private::RustSlice::from_ref)),
688 true => Some(quote!(::cxx::private::RustSlice::from_mut)),
David Tolnayc5629f02020-11-23 18:32:46 -0800689 },
David Tolnay22602b42020-09-21 18:04:05 -0400690 _ => None,
691 });
692
693 let mut expr = match conversion {
694 None => call,
695 Some(conversion) if !sig.throws => quote!(#conversion(#call)),
696 Some(conversion) => quote!(::std::result::Result::map(#call, #conversion)),
697 };
David Tolnay75dca2e2020-03-25 20:17:52 -0700698
699 let mut outparam = None;
700 let indirect_return = indirect_return(sig, types);
David Tolnay1e548172020-03-16 13:37:09 -0700701 if indirect_return {
David Tolnay2f090422020-11-02 18:25:35 -0800702 let ret = expand_extern_type(sig.ret.as_ref().unwrap(), types, false);
David Tolnay75dca2e2020-03-25 20:17:52 -0700703 outparam = Some(quote!(__return: *mut #ret,));
David Tolnay1e548172020-03-16 13:37:09 -0700704 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700705 if sig.throws {
706 let out = match sig.ret {
David Tolnaycecada62020-03-17 01:45:58 -0700707 Some(_) => quote!(__return),
708 None => quote!(&mut ()),
709 };
710 expr = quote!(::cxx::private::r#try(#out, #expr));
David Tolnay1e548172020-03-16 13:37:09 -0700711 } else if indirect_return {
David Tolnay7db73692019-10-20 14:51:12 -0400712 expr = quote!(::std::ptr::write(__return, #expr));
713 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700714
David Tolnay1e548172020-03-16 13:37:09 -0700715 expr = quote!(::cxx::private::catch_unwind(__fn, move || #expr));
David Tolnay75dca2e2020-03-25 20:17:52 -0700716
717 let ret = if sig.throws {
David Tolnay486b6ec2020-03-17 01:19:57 -0700718 quote!(-> ::cxx::private::Result)
David Tolnay1e548172020-03-16 13:37:09 -0700719 } else {
David Tolnay2f090422020-11-02 18:25:35 -0800720 expand_extern_return_type(&sig.ret, types, false)
David Tolnay1e548172020-03-16 13:37:09 -0700721 };
David Tolnay75dca2e2020-03-25 20:17:52 -0700722
723 let pointer = match invoke {
David Tolnayb8ebeb02020-10-31 23:52:06 -0700724 None => Some(quote!(__extern: *const ())),
David Tolnay75dca2e2020-03-25 20:17:52 -0700725 Some(_) => None,
726 };
727
David Tolnay7db73692019-10-20 14:51:12 -0400728 quote! {
729 #[doc(hidden)]
730 #[export_name = #link_name]
David Tolnay9938b642020-11-15 18:11:40 -0800731 unsafe extern "C" fn #local_name #generics(#(#all_args,)* #outparam #pointer) #ret {
David Tolnay7db73692019-10-20 14:51:12 -0400732 let __fn = concat!(module_path!(), #catch_unwind_label);
David Tolnay26219462020-11-09 19:47:28 -0800733 #wrap_super
David Tolnay7db73692019-10-20 14:51:12 -0400734 #expr
735 }
736 }
737}
738
David Tolnay26219462020-11-09 19:47:28 -0800739// A wrapper like `fn f(x: Arg) { super::f(x) }` just to ensure we have the
740// accurate unsafety declaration and no problematic elided lifetimes.
741fn expand_rust_function_shim_super(
742 sig: &Signature,
743 local_name: &Ident,
744 invoke: &Ident,
745) -> TokenStream {
746 let unsafety = sig.unsafety;
David Tolnay9938b642020-11-15 18:11:40 -0800747 let generics = &sig.generics;
David Tolnay26219462020-11-09 19:47:28 -0800748
749 let receiver_var = sig
750 .receiver
751 .as_ref()
752 .map(|receiver| Ident::new("__self", receiver.var.span));
753 let receiver = sig.receiver.iter().map(|receiver| {
754 let receiver_type = receiver.ty();
755 quote!(#receiver_var: #receiver_type)
756 });
757 let args = sig.args.iter().map(|arg| quote!(#arg));
758 let all_args = receiver.chain(args);
759
David Tolnay5d164672020-11-09 20:23:17 -0800760 let ret = if let Some((result, _langle, rangle)) = sig.throws_tokens {
David Tolnay26219462020-11-09 19:47:28 -0800761 let ok = match &sig.ret {
762 Some(ret) => quote!(#ret),
763 None => quote!(()),
764 };
David Tolnay5d164672020-11-09 20:23:17 -0800765 let impl_trait = quote_spanned!(result.span=> impl);
766 let display = quote_spanned!(rangle.span=> ::std::fmt::Display);
767 quote!(-> ::std::result::Result<#ok, #impl_trait #display>)
David Tolnay26219462020-11-09 19:47:28 -0800768 } else {
769 expand_return_type(&sig.ret)
770 };
771
772 let arg_vars = sig.args.iter().map(|arg| &arg.ident);
773 let vars = receiver_var.iter().chain(arg_vars);
774
775 let span = invoke.span();
776 let call = match &sig.receiver {
777 None => quote_spanned!(span=> super::#invoke),
778 Some(receiver) => {
779 let receiver_type = &receiver.ty;
780 quote_spanned!(span=> #receiver_type::#invoke)
781 }
782 };
783
784 quote_spanned! {span=>
David Tolnay9938b642020-11-15 18:11:40 -0800785 #unsafety fn #local_name #generics(#(#all_args,)*) #ret {
David Tolnay26219462020-11-09 19:47:28 -0800786 #call(#(#vars,)*)
787 }
788 }
789}
790
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700791fn expand_type_alias(alias: &TypeAlias) -> TokenStream {
Bryan Henry890083d2020-09-13 10:34:31 -0700792 let doc = &alias.doc;
David Tolnay17a934c2020-11-02 00:40:04 -0800793 let ident = &alias.name.rust;
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700794 let ty = &alias.ty;
795 quote! {
Bryan Henry890083d2020-09-13 10:34:31 -0700796 #doc
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700797 pub type #ident = #ty;
798 }
799}
800
Adrian Taylorc8713432020-10-21 18:20:55 -0700801fn expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800802 let ident = &alias.name.rust;
803 let type_id = type_id(&alias.name);
David Tolnay83fe0f02020-05-07 20:00:15 -0700804 let begin_span = alias.type_token.span;
805 let end_span = alias.semi_token.span;
806 let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
807 let end = quote_spanned!(end_span=> >);
808
David Tolnay63a0e4e2020-10-03 18:52:32 -0700809 let mut verify = quote! {
David Tolnay83fe0f02020-05-07 20:00:15 -0700810 const _: fn() = #begin #ident, #type_id #end;
David Tolnay63a0e4e2020-10-03 18:52:32 -0700811 };
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700812
David Tolnay17a934c2020-11-02 00:40:04 -0800813 if types.required_trivial.contains_key(&alias.name.rust) {
David Tolnay63a0e4e2020-10-03 18:52:32 -0700814 let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_kind::<);
815 verify.extend(quote! {
816 const _: fn() = #begin #ident, ::cxx::kind::Trivial #end;
817 });
Adrian Taylorc7043292020-09-25 12:48:36 -0700818 }
David Tolnay63a0e4e2020-10-03 18:52:32 -0700819
820 verify
Adrian Taylorc7043292020-09-25 12:48:36 -0700821}
822
David Tolnay8faec772020-11-02 00:18:19 -0800823fn type_id(name: &Pair) -> TokenStream {
824 let path = name.to_fully_qualified();
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700825 quote! {
826 ::cxx::type_id!(#path)
827 }
828}
829
Adrian Taylorc8713432020-10-21 18:20:55 -0700830fn expand_rust_box(ident: &ResolvableName, types: &Types) -> TokenStream {
David Tolnay0f0162f2020-11-16 23:43:37 -0800831 let link_prefix = format!("cxxbridge1$box${}$", types.resolve(ident).to_symbol());
David Tolnay7db73692019-10-20 14:51:12 -0400832 let link_uninit = format!("{}uninit", link_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400833 let link_drop = format!("{}drop", link_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400834
Adrian Taylorc8713432020-10-21 18:20:55 -0700835 let local_prefix = format_ident!("{}__box_", &ident.rust);
David Tolnay7db73692019-10-20 14:51:12 -0400836 let local_uninit = format_ident!("{}uninit", local_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400837 let local_drop = format_ident!("{}drop", local_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400838
839 let span = ident.span();
840 quote_spanned! {span=>
841 #[doc(hidden)]
842 #[export_name = #link_uninit]
843 unsafe extern "C" fn #local_uninit(
844 this: *mut ::std::boxed::Box<::std::mem::MaybeUninit<#ident>>,
845 ) {
846 ::std::ptr::write(
847 this,
848 ::std::boxed::Box::new(::std::mem::MaybeUninit::uninit()),
849 );
850 }
851 #[doc(hidden)]
David Tolnay7db73692019-10-20 14:51:12 -0400852 #[export_name = #link_drop]
853 unsafe extern "C" fn #local_drop(this: *mut ::std::boxed::Box<#ident>) {
854 ::std::ptr::drop_in_place(this);
855 }
David Tolnay7db73692019-10-20 14:51:12 -0400856 }
857}
858
Adrian Taylorc8713432020-10-21 18:20:55 -0700859fn expand_rust_vec(elem: &ResolvableName, types: &Types) -> TokenStream {
David Tolnay0f0162f2020-11-16 23:43:37 -0800860 let link_prefix = format!("cxxbridge1$rust_vec${}$", elem.to_symbol(types));
David Tolnayf97c2d52020-04-25 16:37:48 -0700861 let link_new = format!("{}new", link_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700862 let link_drop = format!("{}drop", link_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700863 let link_len = format!("{}len", link_prefix);
David Tolnay219c0792020-04-24 20:31:37 -0700864 let link_data = format!("{}data", link_prefix);
David Tolnayfb6b73c2020-11-10 14:32:16 -0800865 let link_reserve_total = format!("{}reserve_total", link_prefix);
866 let link_set_len = format!("{}set_len", link_prefix);
David Tolnay503d0192020-04-24 22:18:56 -0700867 let link_stride = format!("{}stride", link_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700868
Adrian Taylorc8713432020-10-21 18:20:55 -0700869 let local_prefix = format_ident!("{}__vec_", elem.rust);
David Tolnayf97c2d52020-04-25 16:37:48 -0700870 let local_new = format_ident!("{}new", local_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700871 let local_drop = format_ident!("{}drop", local_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700872 let local_len = format_ident!("{}len", local_prefix);
David Tolnay219c0792020-04-24 20:31:37 -0700873 let local_data = format_ident!("{}data", local_prefix);
David Tolnayfb6b73c2020-11-10 14:32:16 -0800874 let local_reserve_total = format_ident!("{}reserve_total", local_prefix);
875 let local_set_len = format_ident!("{}set_len", local_prefix);
David Tolnay503d0192020-04-24 22:18:56 -0700876 let local_stride = format_ident!("{}stride", local_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700877
David Tolnay83a7ec92020-04-25 12:37:42 -0700878 let span = elem.span();
Myron Ahneba35cf2020-02-05 19:41:51 +0700879 quote_spanned! {span=>
880 #[doc(hidden)]
David Tolnayf97c2d52020-04-25 16:37:48 -0700881 #[export_name = #link_new]
882 unsafe extern "C" fn #local_new(this: *mut ::cxx::private::RustVec<#elem>) {
883 ::std::ptr::write(this, ::cxx::private::RustVec::new());
884 }
885 #[doc(hidden)]
Myron Ahneba35cf2020-02-05 19:41:51 +0700886 #[export_name = #link_drop]
David Tolnay83a7ec92020-04-25 12:37:42 -0700887 unsafe extern "C" fn #local_drop(this: *mut ::cxx::private::RustVec<#elem>) {
David Tolnay4c64afb2020-04-24 11:30:18 -0700888 ::std::ptr::drop_in_place(this);
Myron Ahneba35cf2020-02-05 19:41:51 +0700889 }
David Tolnay85db5a02020-04-25 13:17:27 -0700890 #[doc(hidden)]
Myron Ahneba35cf2020-02-05 19:41:51 +0700891 #[export_name = #link_len]
David Tolnay83a7ec92020-04-25 12:37:42 -0700892 unsafe extern "C" fn #local_len(this: *const ::cxx::private::RustVec<#elem>) -> usize {
David Tolnay2cef5df2020-04-24 11:33:58 -0700893 (*this).len()
Myron Ahneba35cf2020-02-05 19:41:51 +0700894 }
David Tolnay219c0792020-04-24 20:31:37 -0700895 #[doc(hidden)]
896 #[export_name = #link_data]
David Tolnay83a7ec92020-04-25 12:37:42 -0700897 unsafe extern "C" fn #local_data(this: *const ::cxx::private::RustVec<#elem>) -> *const #elem {
David Tolnay219c0792020-04-24 20:31:37 -0700898 (*this).as_ptr()
899 }
David Tolnay503d0192020-04-24 22:18:56 -0700900 #[doc(hidden)]
David Tolnayfb6b73c2020-11-10 14:32:16 -0800901 #[export_name = #link_reserve_total]
902 unsafe extern "C" fn #local_reserve_total(this: *mut ::cxx::private::RustVec<#elem>, cap: usize) {
903 (*this).reserve_total(cap);
904 }
905 #[doc(hidden)]
906 #[export_name = #link_set_len]
907 unsafe extern "C" fn #local_set_len(this: *mut ::cxx::private::RustVec<#elem>, len: usize) {
908 (*this).set_len(len);
909 }
910 #[doc(hidden)]
David Tolnay503d0192020-04-24 22:18:56 -0700911 #[export_name = #link_stride]
912 unsafe extern "C" fn #local_stride() -> usize {
David Tolnay83a7ec92020-04-25 12:37:42 -0700913 ::std::mem::size_of::<#elem>()
David Tolnay503d0192020-04-24 22:18:56 -0700914 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700915 }
916}
917
David Tolnay0531f432020-10-03 23:50:28 -0700918fn expand_unique_ptr(
Adrian Taylorc8713432020-10-21 18:20:55 -0700919 ident: &ResolvableName,
David Tolnay0531f432020-10-03 23:50:28 -0700920 types: &Types,
921 explicit_impl: Option<&Impl>,
922) -> TokenStream {
Adrian Taylorc8713432020-10-21 18:20:55 -0700923 let name = ident.rust.to_string();
David Tolnay0f0162f2020-11-16 23:43:37 -0800924 let prefix = format!("cxxbridge1$unique_ptr${}$", ident.to_symbol(types));
David Tolnay7db73692019-10-20 14:51:12 -0400925 let link_null = format!("{}null", prefix);
926 let link_new = format!("{}new", prefix);
927 let link_raw = format!("{}raw", prefix);
928 let link_get = format!("{}get", prefix);
929 let link_release = format!("{}release", prefix);
930 let link_drop = format!("{}drop", prefix);
931
David Tolnay15609ab2020-11-25 07:14:12 -0800932 let can_construct_from_value = types.structs.contains_key(&ident.rust)
933 || types.enums.contains_key(&ident.rust)
934 || types.aliases.contains_key(&ident.rust);
935 let new_method = if can_construct_from_value {
936 Some(quote! {
937 fn __new(mut value: Self) -> *mut ::std::ffi::c_void {
938 extern "C" {
939 #[link_name = #link_new]
940 fn __new(this: *mut *mut ::std::ffi::c_void, value: *mut #ident);
David Tolnay53838912020-04-09 20:56:44 -0700941 }
David Tolnay15609ab2020-11-25 07:14:12 -0800942 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
943 unsafe { __new(&mut repr, &mut value) }
944 repr
945 }
946 })
947 } else {
948 None
949 };
David Tolnay53838912020-04-09 20:56:44 -0700950
David Tolnay0531f432020-10-03 23:50:28 -0700951 let begin_span =
952 explicit_impl.map_or_else(Span::call_site, |explicit| explicit.impl_token.span);
953 let end_span = explicit_impl.map_or_else(Span::call_site, |explicit| explicit.brace_token.span);
954 let unsafe_token = format_ident!("unsafe", span = begin_span);
955
956 quote_spanned! {end_span=>
957 #unsafe_token impl ::cxx::private::UniquePtrTarget for #ident {
David Tolnay3b40b6f2020-04-24 17:58:24 -0700958 const __NAME: &'static dyn ::std::fmt::Display = &#name;
David Tolnay7db73692019-10-20 14:51:12 -0400959 fn __null() -> *mut ::std::ffi::c_void {
960 extern "C" {
961 #[link_name = #link_null]
962 fn __null(this: *mut *mut ::std::ffi::c_void);
963 }
964 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
965 unsafe { __null(&mut repr) }
966 repr
967 }
David Tolnay53838912020-04-09 20:56:44 -0700968 #new_method
David Tolnay7db73692019-10-20 14:51:12 -0400969 unsafe fn __raw(raw: *mut Self) -> *mut ::std::ffi::c_void {
970 extern "C" {
971 #[link_name = #link_raw]
David Tolnay3b40b6f2020-04-24 17:58:24 -0700972 fn __raw(this: *mut *mut ::std::ffi::c_void, raw: *mut #ident);
David Tolnay7db73692019-10-20 14:51:12 -0400973 }
974 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
975 __raw(&mut repr, raw);
976 repr
977 }
978 unsafe fn __get(repr: *mut ::std::ffi::c_void) -> *const Self {
979 extern "C" {
980 #[link_name = #link_get]
David Tolnay3b40b6f2020-04-24 17:58:24 -0700981 fn __get(this: *const *mut ::std::ffi::c_void) -> *const #ident;
David Tolnay7db73692019-10-20 14:51:12 -0400982 }
983 __get(&repr)
984 }
985 unsafe fn __release(mut repr: *mut ::std::ffi::c_void) -> *mut Self {
986 extern "C" {
987 #[link_name = #link_release]
David Tolnay3b40b6f2020-04-24 17:58:24 -0700988 fn __release(this: *mut *mut ::std::ffi::c_void) -> *mut #ident;
David Tolnay7db73692019-10-20 14:51:12 -0400989 }
990 __release(&mut repr)
991 }
992 unsafe fn __drop(mut repr: *mut ::std::ffi::c_void) {
993 extern "C" {
994 #[link_name = #link_drop]
995 fn __drop(this: *mut *mut ::std::ffi::c_void);
996 }
997 __drop(&mut repr);
998 }
999 }
1000 }
1001}
1002
David Tolnay0531f432020-10-03 23:50:28 -07001003fn expand_cxx_vector(
Adrian Taylorc8713432020-10-21 18:20:55 -07001004 elem: &ResolvableName,
David Tolnay0531f432020-10-03 23:50:28 -07001005 explicit_impl: Option<&Impl>,
Adrian Taylorc8713432020-10-21 18:20:55 -07001006 types: &Types,
David Tolnay0531f432020-10-03 23:50:28 -07001007) -> TokenStream {
1008 let _ = explicit_impl;
Adrian Taylorc8713432020-10-21 18:20:55 -07001009 let name = elem.rust.to_string();
David Tolnay0f0162f2020-11-16 23:43:37 -08001010 let prefix = format!("cxxbridge1$std$vector${}$", elem.to_symbol(types));
David Tolnaya83247c2020-04-24 14:36:10 -07001011 let link_size = format!("{}size", prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +07001012 let link_get_unchecked = format!("{}get_unchecked", prefix);
Adrian Taylorc8713432020-10-21 18:20:55 -07001013 let unique_ptr_prefix = format!(
David Tolnay0f0162f2020-11-16 23:43:37 -08001014 "cxxbridge1$unique_ptr$std$vector${}$",
Adrian Taylorc8713432020-10-21 18:20:55 -07001015 elem.to_symbol(types)
1016 );
David Tolnay3b40b6f2020-04-24 17:58:24 -07001017 let link_unique_ptr_null = format!("{}null", unique_ptr_prefix);
1018 let link_unique_ptr_raw = format!("{}raw", unique_ptr_prefix);
1019 let link_unique_ptr_get = format!("{}get", unique_ptr_prefix);
1020 let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
1021 let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +07001022
David Tolnay0531f432020-10-03 23:50:28 -07001023 let begin_span =
1024 explicit_impl.map_or_else(Span::call_site, |explicit| explicit.impl_token.span);
1025 let end_span = explicit_impl.map_or_else(Span::call_site, |explicit| explicit.brace_token.span);
1026 let unsafe_token = format_ident!("unsafe", span = begin_span);
1027
1028 quote_spanned! {end_span=>
1029 #unsafe_token impl ::cxx::private::VectorElement for #elem {
David Tolnay3b40b6f2020-04-24 17:58:24 -07001030 const __NAME: &'static dyn ::std::fmt::Display = &#name;
David Tolnay17631102020-04-24 19:01:30 -07001031 fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
David Tolnayfa2119c2020-04-24 14:42:58 -07001032 extern "C" {
1033 #[link_name = #link_size]
David Tolnay17631102020-04-24 19:01:30 -07001034 fn __vector_size(_: &::cxx::CxxVector<#elem>) -> usize;
Myron Ahneba35cf2020-02-05 19:41:51 +07001035 }
David Tolnayfa2119c2020-04-24 14:42:58 -07001036 unsafe { __vector_size(v) }
Myron Ahneba35cf2020-02-05 19:41:51 +07001037 }
David Tolnay93637ca2020-09-24 15:58:20 -04001038 unsafe fn __get_unchecked(v: &::cxx::CxxVector<Self>, pos: usize) -> *const Self {
David Tolnaycc75ad22020-04-24 14:45:16 -07001039 extern "C" {
1040 #[link_name = #link_get_unchecked]
David Tolnay17631102020-04-24 19:01:30 -07001041 fn __get_unchecked(_: &::cxx::CxxVector<#elem>, _: usize) -> *const #elem;
David Tolnaycc75ad22020-04-24 14:45:16 -07001042 }
David Tolnay93637ca2020-09-24 15:58:20 -04001043 __get_unchecked(v, pos)
David Tolnaycc75ad22020-04-24 14:45:16 -07001044 }
David Tolnay3b40b6f2020-04-24 17:58:24 -07001045 fn __unique_ptr_null() -> *mut ::std::ffi::c_void {
1046 extern "C" {
1047 #[link_name = #link_unique_ptr_null]
1048 fn __unique_ptr_null(this: *mut *mut ::std::ffi::c_void);
1049 }
1050 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
1051 unsafe { __unique_ptr_null(&mut repr) }
1052 repr
1053 }
1054 unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> *mut ::std::ffi::c_void {
1055 extern "C" {
1056 #[link_name = #link_unique_ptr_raw]
1057 fn __unique_ptr_raw(this: *mut *mut ::std::ffi::c_void, raw: *mut ::cxx::CxxVector<#elem>);
1058 }
1059 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
1060 __unique_ptr_raw(&mut repr, raw);
1061 repr
1062 }
1063 unsafe fn __unique_ptr_get(repr: *mut ::std::ffi::c_void) -> *const ::cxx::CxxVector<Self> {
1064 extern "C" {
1065 #[link_name = #link_unique_ptr_get]
1066 fn __unique_ptr_get(this: *const *mut ::std::ffi::c_void) -> *const ::cxx::CxxVector<#elem>;
1067 }
1068 __unique_ptr_get(&repr)
1069 }
1070 unsafe fn __unique_ptr_release(mut repr: *mut ::std::ffi::c_void) -> *mut ::cxx::CxxVector<Self> {
1071 extern "C" {
1072 #[link_name = #link_unique_ptr_release]
1073 fn __unique_ptr_release(this: *mut *mut ::std::ffi::c_void) -> *mut ::cxx::CxxVector<#elem>;
1074 }
1075 __unique_ptr_release(&mut repr)
1076 }
1077 unsafe fn __unique_ptr_drop(mut repr: *mut ::std::ffi::c_void) {
1078 extern "C" {
1079 #[link_name = #link_unique_ptr_drop]
1080 fn __unique_ptr_drop(this: *mut *mut ::std::ffi::c_void);
1081 }
1082 __unique_ptr_drop(&mut repr);
1083 }
Myron Ahneba35cf2020-02-05 19:41:51 +07001084 }
1085 }
1086}
1087
David Tolnay7db73692019-10-20 14:51:12 -04001088fn expand_return_type(ret: &Option<Type>) -> TokenStream {
1089 match ret {
1090 Some(ret) => quote!(-> #ret),
1091 None => TokenStream::new(),
1092 }
1093}
1094
David Tolnay75dca2e2020-03-25 20:17:52 -07001095fn indirect_return(sig: &Signature, types: &Types) -> bool {
1096 sig.ret
David Tolnay1e548172020-03-16 13:37:09 -07001097 .as_ref()
David Tolnay75dca2e2020-03-25 20:17:52 -07001098 .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
David Tolnay7db73692019-10-20 14:51:12 -04001099}
1100
David Tolnay2f090422020-11-02 18:25:35 -08001101fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
David Tolnay7db73692019-10-20 14:51:12 -04001102 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -07001103 Type::Ident(ident) if ident.rust == RustString => quote!(::cxx::private::RustString),
David Tolnay7db73692019-10-20 14:51:12 -04001104 Type::RustBox(ty) | Type::UniquePtr(ty) => {
David Tolnay2f090422020-11-02 18:25:35 -08001105 let inner = expand_extern_type(&ty.inner, types, proper);
David Tolnay7db73692019-10-20 14:51:12 -04001106 quote!(*mut #inner)
1107 }
David Tolnaye6d50212020-04-25 15:38:23 -07001108 Type::RustVec(ty) => {
David Tolnay2f090422020-11-02 18:25:35 -08001109 let elem = expand_extern_type(&ty.inner, types, proper);
David Tolnaye6d50212020-04-25 15:38:23 -07001110 quote!(::cxx::private::RustVec<#elem>)
1111 }
David Tolnayf1c7f322020-08-27 00:46:01 -07001112 Type::Ref(ty) => {
1113 let mutability = ty.mutability;
1114 match &ty.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -07001115 Type::Ident(ident) if ident.rust == RustString => {
David Tolnayf1c7f322020-08-27 00:46:01 -07001116 quote!(&#mutability ::cxx::private::RustString)
1117 }
1118 Type::RustVec(ty) => {
David Tolnay2f090422020-11-02 18:25:35 -08001119 let inner = expand_extern_type(&ty.inner, types, proper);
David Tolnayf1c7f322020-08-27 00:46:01 -07001120 quote!(&#mutability ::cxx::private::RustVec<#inner>)
1121 }
David Tolnay9c4ac2e2020-11-15 21:14:03 -08001122 inner if proper && types.is_considered_improper_ctype(inner) => match ty.mutable {
1123 false => quote!(*const ::std::ffi::c_void),
1124 true => quote!(*#mutability ::std::ffi::c_void),
David Tolnay4cb97672020-11-02 16:13:34 -08001125 },
David Tolnayf1c7f322020-08-27 00:46:01 -07001126 _ => quote!(#ty),
Myron Ahneba35cf2020-02-05 19:41:51 +07001127 }
David Tolnayf1c7f322020-08-27 00:46:01 -07001128 }
David Tolnay7db73692019-10-20 14:51:12 -04001129 Type::Str(_) => quote!(::cxx::private::RustStr),
David Tolnay5515a9e2020-11-25 19:07:54 -08001130 Type::SliceRef(_) => quote!(::cxx::private::RustSlice),
David Tolnay7db73692019-10-20 14:51:12 -04001131 _ => quote!(#ty),
1132 }
1133}
1134
David Tolnay2f090422020-11-02 18:25:35 -08001135fn expand_extern_return_type(ret: &Option<Type>, types: &Types, proper: bool) -> TokenStream {
David Tolnay7db73692019-10-20 14:51:12 -04001136 let ret = match ret {
1137 Some(ret) if !types.needs_indirect_abi(ret) => ret,
1138 _ => return TokenStream::new(),
1139 };
David Tolnay2f090422020-11-02 18:25:35 -08001140 let ty = expand_extern_type(ret, types, proper);
David Tolnay7db73692019-10-20 14:51:12 -04001141 quote!(-> #ty)
1142}