blob: 411f87e4baf4733269f4c8f0d314e1c7370402ee [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 Tolnay8684cc52020-10-07 17:09:48 -0700167
Joel Galensonc03402a2020-04-23 17:31:09 -0700168 quote! {
169 #doc
David Tolnay4a0c53a2020-11-27 11:46:16 -0800170 #[derive(PartialEq, Eq)] // required to be derived in order to be usable in patterns
Joel Galensonc03402a2020-04-23 17:31:09 -0700171 #[repr(transparent)]
Joel Galensondb1ec312020-05-01 13:57:32 -0700172 pub struct #ident {
David Tolnayc605e6f2020-05-10 23:37:12 -0700173 pub repr: #repr,
Joel Galensondb1ec312020-05-01 13:57:32 -0700174 }
Joel Galensonc03402a2020-04-23 17:31:09 -0700175
176 #[allow(non_upper_case_globals)]
177 impl #ident {
David Tolnayd7984c22020-04-30 20:09:31 -0700178 #(#variants)*
Joel Galensonc03402a2020-04-23 17:31:09 -0700179 }
David Tolnay8684cc52020-10-07 17:09:48 -0700180
181 unsafe impl ::cxx::ExternType for #ident {
182 type Id = #type_id;
183 type Kind = ::cxx::kind::Trivial;
184 }
David Tolnay4a0c53a2020-11-27 11:46:16 -0800185
186 impl ::std::marker::Copy for #ident {}
187
188 impl ::std::clone::Clone for #ident {
189 fn clone(&self) -> Self {
190 *self
191 }
192 }
Joel Galensonc03402a2020-04-23 17:31:09 -0700193 }
194}
195
Adrian Taylorc8713432020-10-21 18:20:55 -0700196fn expand_cxx_type(ety: &ExternType) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800197 let ident = &ety.name.rust;
David Tolnay7db73692019-10-20 14:51:12 -0400198 let doc = &ety.doc;
David Tolnay17a934c2020-11-02 00:40:04 -0800199 let type_id = type_id(&ety.name);
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700200
David Tolnay7db73692019-10-20 14:51:12 -0400201 quote! {
202 #doc
203 #[repr(C)]
204 pub struct #ident {
205 _private: ::cxx::private::Opaque,
206 }
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700207
208 unsafe impl ::cxx::ExternType for #ident {
209 type Id = #type_id;
David Tolnay38f5ad62020-10-03 18:06:44 -0700210 type Kind = ::cxx::kind::Opaque;
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700211 }
David Tolnay7db73692019-10-20 14:51:12 -0400212 }
213}
214
David Tolnay9eef6092020-11-15 17:56:41 -0800215fn expand_cxx_type_assert_pinned(ety: &ExternType) -> TokenStream {
216 let ident = &ety.name.rust;
217 let infer = Token![_](ident.span());
218
219 quote! {
220 let _ = {
221 // Derived from https://github.com/nvzqz/static-assertions-rs.
222 trait __AmbiguousIfImpl<A> {
223 fn infer() {}
224 }
225
226 impl<T: ?Sized> __AmbiguousIfImpl<()> for T {}
227
228 #[allow(dead_code)]
229 struct __Invalid;
230
231 impl<T: ?Sized + Unpin> __AmbiguousIfImpl<__Invalid> for T {}
232
233 // If there is only one specialized trait impl, type inference with
234 // `_` can be resolved and this can compile. Fails to compile if
235 // user has added a manual Unpin impl for their opaque C++ type as
236 // then `__AmbiguousIfImpl<__Invalid>` also exists.
237 <#ident as __AmbiguousIfImpl<#infer>>::infer
238 };
239 }
240}
241
Adrian Taylorc8713432020-10-21 18:20:55 -0700242fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
David Tolnay9938b642020-11-15 18:11:40 -0800243 let generics = &efn.generics;
David Tolnay18ba92c2020-04-22 16:17:30 -0700244 let receiver = efn.receiver.iter().map(|receiver| {
245 let receiver_type = receiver.ty();
246 quote!(_: #receiver_type)
247 });
David Tolnay39d575f2020-03-03 00:10:56 -0800248 let args = efn.args.iter().map(|arg| {
249 let ident = &arg.ident;
David Tolnay2f090422020-11-02 18:25:35 -0800250 let ty = expand_extern_type(&arg.ty, types, true);
David Tolnaya46a2372020-03-06 10:03:48 -0800251 if arg.ty == RustString {
252 quote!(#ident: *const #ty)
David Tolnay313b10e2020-04-25 16:30:51 -0700253 } else if let Type::RustVec(_) = arg.ty {
254 quote!(#ident: *const #ty)
David Tolnay75dca2e2020-03-25 20:17:52 -0700255 } else if let Type::Fn(_) = arg.ty {
256 quote!(#ident: ::cxx::private::FatFunction)
David Tolnaya46a2372020-03-06 10:03:48 -0800257 } else if types.needs_indirect_abi(&arg.ty) {
David Tolnay39d575f2020-03-03 00:10:56 -0800258 quote!(#ident: *mut #ty)
259 } else {
260 quote!(#ident: #ty)
261 }
262 });
Joel Galenson3d4f6122020-04-07 15:54:05 -0700263 let all_args = receiver.chain(args);
David Tolnayebef4a22020-03-17 15:33:47 -0700264 let ret = if efn.throws {
265 quote!(-> ::cxx::private::Result)
266 } else {
David Tolnay2f090422020-11-02 18:25:35 -0800267 expand_extern_return_type(&efn.ret, types, true)
David Tolnayebef4a22020-03-17 15:33:47 -0700268 };
David Tolnay7db73692019-10-20 14:51:12 -0400269 let mut outparam = None;
David Tolnay1e548172020-03-16 13:37:09 -0700270 if indirect_return(efn, types) {
David Tolnay2f090422020-11-02 18:25:35 -0800271 let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
David Tolnay7db73692019-10-20 14:51:12 -0400272 outparam = Some(quote!(__return: *mut #ret));
273 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700274 let link_name = mangle::extern_fn(efn, types);
David Tolnay17a934c2020-11-02 00:40:04 -0800275 let local_name = format_ident!("__{}", efn.name.rust);
David Tolnay7db73692019-10-20 14:51:12 -0400276 quote! {
277 #[link_name = #link_name]
David Tolnay9938b642020-11-15 18:11:40 -0800278 fn #local_name #generics(#(#all_args,)* #outparam) #ret;
David Tolnay7db73692019-10-20 14:51:12 -0400279 }
280}
281
Adrian Taylorc8713432020-10-21 18:20:55 -0700282fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
David Tolnay7db73692019-10-20 14:51:12 -0400283 let doc = &efn.doc;
Adrian Taylorc8713432020-10-21 18:20:55 -0700284 let decl = expand_cxx_function_decl(efn, types);
David Tolnayfb6e3862020-04-20 01:33:23 -0700285 let receiver = efn.receiver.iter().map(|receiver| {
David Tolnayf9ffb932020-04-20 02:22:57 -0700286 let var = receiver.var;
David Tolnayc9673842020-11-15 16:26:10 -0800287 if receiver.pinned {
288 let ty = receiver.ty();
289 quote!(#var: #ty)
290 } else {
291 let ampersand = receiver.ampersand;
David Tolnay9938b642020-11-15 18:11:40 -0800292 let lifetime = &receiver.lifetime;
David Tolnayc9673842020-11-15 16:26:10 -0800293 let mutability = receiver.mutability;
David Tolnay9938b642020-11-15 18:11:40 -0800294 quote!(#ampersand #lifetime #mutability #var)
David Tolnayc9673842020-11-15 16:26:10 -0800295 }
David Tolnayfb6e3862020-04-20 01:33:23 -0700296 });
Joel Galenson3d4f6122020-04-07 15:54:05 -0700297 let args = efn.args.iter().map(|arg| quote!(#arg));
298 let all_args = receiver.chain(args);
David Tolnayebef4a22020-03-17 15:33:47 -0700299 let ret = if efn.throws {
300 let ok = match &efn.ret {
301 Some(ret) => quote!(#ret),
302 None => quote!(()),
303 };
304 quote!(-> ::std::result::Result<#ok, ::cxx::Exception>)
305 } else {
306 expand_return_type(&efn.ret)
307 };
David Tolnay1e548172020-03-16 13:37:09 -0700308 let indirect_return = indirect_return(efn, types);
David Tolnayf9ffb932020-04-20 02:22:57 -0700309 let receiver_var = efn
310 .receiver
311 .iter()
312 .map(|receiver| receiver.var.to_token_stream());
Joel Galenson3d4f6122020-04-07 15:54:05 -0700313 let arg_vars = efn.args.iter().map(|arg| {
David Tolnay7db73692019-10-20 14:51:12 -0400314 let var = &arg.ident;
315 match &arg.ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700316 Type::Ident(ident) if ident.rust == RustString => {
David Tolnaya46a2372020-03-06 10:03:48 -0800317 quote!(#var.as_mut_ptr() as *const ::cxx::private::RustString)
David Tolnay7db73692019-10-20 14:51:12 -0400318 }
319 Type::RustBox(_) => quote!(::std::boxed::Box::into_raw(#var)),
David Tolnaybf7ae812020-11-16 23:31:45 -0800320 Type::UniquePtr(_) => quote!(::cxx::UniquePtr::into_raw(#var)),
David Tolnay313b10e2020-04-25 16:30:51 -0700321 Type::RustVec(_) => quote!(#var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
David Tolnay7db73692019-10-20 14:51:12 -0400322 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800323 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
324 false => quote!(::cxx::private::RustString::from_ref(#var)),
325 true => quote!(::cxx::private::RustString::from_mut(#var)),
David Tolnayf1c7f322020-08-27 00:46:01 -0700326 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800327 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
328 false => quote!(::cxx::private::RustVec::from_ref_vec_string(#var)),
329 true => quote!(::cxx::private::RustVec::from_mut_vec_string(#var)),
David Tolnay33f56ad2020-08-27 17:06:35 -0700330 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800331 Type::RustVec(_) => match ty.mutable {
332 false => quote!(::cxx::private::RustVec::from_ref(#var)),
333 true => quote!(::cxx::private::RustVec::from_mut(#var)),
David Tolnayf1c7f322020-08-27 00:46:01 -0700334 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800335 inner if types.is_considered_improper_ctype(inner) => match ty.mutable {
336 false => quote!(#var as *const #inner as *const ::std::ffi::c_void),
337 true => quote!(#var as *mut #inner as *mut ::std::ffi::c_void),
David Tolnay4cb97672020-11-02 16:13:34 -0800338 },
David Tolnay7db73692019-10-20 14:51:12 -0400339 _ => quote!(#var),
340 },
341 Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
David Tolnay73b72642020-11-25 17:44:05 -0800342 Type::SliceRef(ty) => match ty.mutable {
David Tolnay5515a9e2020-11-25 19:07:54 -0800343 false => quote!(::cxx::private::RustSlice::from_ref(#var)),
344 true => quote!(::cxx::private::RustSlice::from_mut(#var)),
David Tolnayc5629f02020-11-23 18:32:46 -0800345 },
David Tolnay7db73692019-10-20 14:51:12 -0400346 ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
347 _ => quote!(#var),
348 }
349 });
Joel Galenson3d4f6122020-04-07 15:54:05 -0700350 let vars = receiver_var.chain(arg_vars);
David Tolnay75dca2e2020-03-25 20:17:52 -0700351 let trampolines = efn
352 .args
353 .iter()
354 .filter_map(|arg| {
355 if let Type::Fn(f) = &arg.ty {
356 let var = &arg.ident;
Adrian Taylorc8713432020-10-21 18:20:55 -0700357 Some(expand_function_pointer_trampoline(efn, var, f, types))
David Tolnay75dca2e2020-03-25 20:17:52 -0700358 } else {
359 None
360 }
361 })
362 .collect::<TokenStream>();
David Tolnay7db73692019-10-20 14:51:12 -0400363 let mut setup = efn
364 .args
365 .iter()
366 .filter(|arg| types.needs_indirect_abi(&arg.ty))
367 .map(|arg| {
368 let var = &arg.ident;
369 // These are arguments for which C++ has taken ownership of the data
370 // behind the mut reference it received.
371 quote! {
David Tolnaycb4ee4b2020-04-24 11:28:08 -0700372 let mut #var = ::std::mem::MaybeUninit::new(#var);
David Tolnay7db73692019-10-20 14:51:12 -0400373 }
374 })
375 .collect::<TokenStream>();
David Tolnay17a934c2020-11-02 00:40:04 -0800376 let local_name = format_ident!("__{}", efn.name.rust);
David Tolnay7db73692019-10-20 14:51:12 -0400377 let call = if indirect_return {
David Tolnay2f090422020-11-02 18:25:35 -0800378 let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
David Tolnay7db73692019-10-20 14:51:12 -0400379 setup.extend(quote! {
380 let mut __return = ::std::mem::MaybeUninit::<#ret>::uninit();
David Tolnay7db73692019-10-20 14:51:12 -0400381 });
David Tolnay0d524852020-11-02 17:21:50 -0800382 setup.extend(if efn.throws {
383 quote! {
David Tolnayebef4a22020-03-17 15:33:47 -0700384 #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?;
David Tolnay0d524852020-11-02 17:21:50 -0800385 }
David Tolnayebef4a22020-03-17 15:33:47 -0700386 } else {
David Tolnay0d524852020-11-02 17:21:50 -0800387 quote! {
David Tolnayebef4a22020-03-17 15:33:47 -0700388 #local_name(#(#vars,)* __return.as_mut_ptr());
David Tolnay0d524852020-11-02 17:21:50 -0800389 }
390 });
391 quote!(__return.assume_init())
David Tolnayebef4a22020-03-17 15:33:47 -0700392 } else if efn.throws {
David Tolnay7db73692019-10-20 14:51:12 -0400393 quote! {
David Tolnayebef4a22020-03-17 15:33:47 -0700394 #local_name(#(#vars),*).exception()
David Tolnay7db73692019-10-20 14:51:12 -0400395 }
396 } else {
397 quote! {
398 #local_name(#(#vars),*)
399 }
400 };
David Tolnay2debdb22020-11-02 17:14:53 -0800401 let mut expr;
402 if efn.throws && efn.sig.ret.is_none() {
403 expr = call;
Myron Ahn84849302020-03-25 22:00:58 +0700404 } else {
David Tolnay0d524852020-11-02 17:21:50 -0800405 expr = match &efn.ret {
406 None => call,
407 Some(ret) => match ret {
408 Type::Ident(ident) if ident.rust == RustString => quote!(#call.into_string()),
409 Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#call)),
David Tolnaya1f02e52020-11-02 17:10:54 -0800410 Type::RustVec(vec) => {
411 if vec.inner == RustString {
David Tolnay0d524852020-11-02 17:21:50 -0800412 quote!(#call.into_vec_string())
David Tolnaya1f02e52020-11-02 17:10:54 -0800413 } else {
David Tolnay0d524852020-11-02 17:21:50 -0800414 quote!(#call.into_vec())
David Tolnaya1f02e52020-11-02 17:10:54 -0800415 }
David Tolnay33f56ad2020-08-27 17:06:35 -0700416 }
David Tolnaybf7ae812020-11-16 23:31:45 -0800417 Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#call)),
David Tolnaya1f02e52020-11-02 17:10:54 -0800418 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800419 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
420 false => quote!(#call.as_string()),
421 true => quote!(#call.as_mut_string()),
David Tolnaya1f02e52020-11-02 17:10:54 -0800422 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800423 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
424 false => quote!(#call.as_vec_string()),
425 true => quote!(#call.as_mut_vec_string()),
David Tolnaya1f02e52020-11-02 17:10:54 -0800426 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800427 Type::RustVec(_) => match ty.mutable {
428 false => quote!(#call.as_vec()),
429 true => quote!(#call.as_mut_vec()),
David Tolnaya1f02e52020-11-02 17:10:54 -0800430 },
David Tolnay4cb97672020-11-02 16:13:34 -0800431 inner if types.is_considered_improper_ctype(inner) => {
432 let mutability = ty.mutability;
433 quote!(&#mutability *#call.cast())
434 }
David Tolnay0d524852020-11-02 17:21:50 -0800435 _ => call,
David Tolnayf1c7f322020-08-27 00:46:01 -0700436 },
David Tolnay0d524852020-11-02 17:21:50 -0800437 Type::Str(_) => quote!(#call.as_str()),
David Tolnay5515a9e2020-11-25 19:07:54 -0800438 Type::SliceRef(slice) => {
439 let inner = &slice.inner;
440 match slice.mutable {
441 false => quote!(#call.as_slice::<#inner>()),
442 true => quote!(#call.as_mut_slice::<#inner>()),
443 }
444 }
David Tolnay0d524852020-11-02 17:21:50 -0800445 _ => call,
446 },
447 };
David Tolnay2debdb22020-11-02 17:14:53 -0800448 if efn.throws {
449 expr = quote!(::std::result::Result::Ok(#expr));
450 }
David Tolnaya1f02e52020-11-02 17:10:54 -0800451 };
David Tolnaye67bcf52020-09-06 23:50:44 -0700452 let mut dispatch = quote!(#setup #expr);
453 let unsafety = &efn.sig.unsafety;
454 if unsafety.is_none() {
455 dispatch = quote!(unsafe { #dispatch });
456 }
David Tolnay17a934c2020-11-02 00:40:04 -0800457 let ident = &efn.name.rust;
David Tolnay9938b642020-11-15 18:11:40 -0800458 let generics = &efn.generics;
David Tolnayc66cdbb2020-04-20 01:41:15 -0700459 let function_shim = quote! {
460 #doc
David Tolnay9938b642020-11-15 18:11:40 -0800461 pub #unsafety fn #ident #generics(#(#all_args,)*) #ret {
David Tolnayc66cdbb2020-04-20 01:41:15 -0700462 extern "C" {
463 #decl
David Tolnay7db73692019-10-20 14:51:12 -0400464 }
David Tolnayc66cdbb2020-04-20 01:41:15 -0700465 #trampolines
David Tolnaye67bcf52020-09-06 23:50:44 -0700466 #dispatch
David Tolnayc66cdbb2020-04-20 01:41:15 -0700467 }
468 };
469 match &efn.receiver {
470 None => function_shim,
471 Some(receiver) => {
David Tolnay05e11cc2020-04-20 02:13:56 -0700472 let receiver_type = &receiver.ty;
David Tolnayc66cdbb2020-04-20 01:41:15 -0700473 quote!(impl #receiver_type { #function_shim })
474 }
David Tolnay7db73692019-10-20 14:51:12 -0400475 }
476}
477
David Tolnay75dca2e2020-03-25 20:17:52 -0700478fn expand_function_pointer_trampoline(
David Tolnay75dca2e2020-03-25 20:17:52 -0700479 efn: &ExternFn,
480 var: &Ident,
481 sig: &Signature,
482 types: &Types,
483) -> TokenStream {
Adrian Taylorc8713432020-10-21 18:20:55 -0700484 let c_trampoline = mangle::c_trampoline(efn, var, types);
485 let r_trampoline = mangle::r_trampoline(efn, var, types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700486 let local_name = parse_quote!(__);
David Tolnay17a934c2020-11-02 00:40:04 -0800487 let catch_unwind_label = format!("::{}::{}", efn.name.rust, var);
David Tolnay75dca2e2020-03-25 20:17:52 -0700488 let shim = expand_rust_function_shim_impl(
489 sig,
490 types,
491 &r_trampoline,
492 local_name,
493 catch_unwind_label,
494 None,
495 );
496
497 quote! {
498 let #var = ::cxx::private::FatFunction {
499 trampoline: {
500 extern "C" {
501 #[link_name = #c_trampoline]
502 fn trampoline();
503 }
504 #shim
505 trampoline as usize as *const ()
506 },
507 ptr: #var as usize as *const (),
508 };
509 }
510}
511
David Tolnay62cae8e2020-11-17 07:54:54 -0800512fn expand_rust_type_import(ety: &ExternType) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800513 let ident = &ety.name.rust;
David Tolnay62cae8e2020-11-17 07:54:54 -0800514 let span = ident.span();
515
516 quote_spanned! {span=>
David Tolnay7db73692019-10-20 14:51:12 -0400517 use super::#ident;
518 }
519}
520
David Tolnay62cae8e2020-11-17 07:54:54 -0800521fn expand_rust_type_impl(ety: &ExternType) -> TokenStream {
522 let ident = &ety.name.rust;
523 let span = ident.span();
524 let unsafe_impl = quote_spanned!(ety.type_token.span=> unsafe impl);
525
526 quote_spanned! {span=>
527 #unsafe_impl ::cxx::private::RustType for #ident {}
528 }
529}
530
David Tolnayc8361022020-08-25 21:57:53 -0700531fn expand_rust_type_assert_sized(ety: &ExternType) -> TokenStream {
532 // Rustc will render as follows if not sized:
533 //
534 // type TheirType;
535 // -----^^^^^^^^^-
536 // | |
537 // | doesn't have a size known at compile-time
538 // required by this bound in `ffi::_::__AssertSized`
539
David Tolnay17a934c2020-11-02 00:40:04 -0800540 let ident = &ety.name.rust;
David Tolnayc8361022020-08-25 21:57:53 -0700541 let begin_span = Token![::](ety.type_token.span);
542 let sized = quote_spanned! {ety.semi_token.span=>
543 #begin_span std::marker::Sized
544 };
David Tolnay20fa62b2020-11-15 17:34:05 -0800545 let unpin = quote_spanned! {ety.semi_token.span=>
546 #begin_span std::marker::Unpin
547 };
David Tolnay17a934c2020-11-02 00:40:04 -0800548 quote_spanned! {ident.span()=>
David Tolnayc8361022020-08-25 21:57:53 -0700549 let _ = {
550 fn __AssertSized<T: ?#sized + #sized>() {}
David Tolnay20fa62b2020-11-15 17:34:05 -0800551 fn __AssertUnpin<T: #unpin>() {}
552 (__AssertSized::<#ident>, __AssertUnpin::<#ident>)
David Tolnayc8361022020-08-25 21:57:53 -0700553 };
554 }
555}
556
Adrian Taylorc8713432020-10-21 18:20:55 -0700557fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
558 let link_name = mangle::extern_fn(efn, types);
David Tolnay17a934c2020-11-02 00:40:04 -0800559 let local_name = format_ident!("__{}", efn.name.rust);
560 let catch_unwind_label = format!("::{}", efn.name.rust);
561 let invoke = Some(&efn.name.rust);
David Tolnay75dca2e2020-03-25 20:17:52 -0700562 expand_rust_function_shim_impl(
563 efn,
564 types,
565 &link_name,
566 local_name,
567 catch_unwind_label,
568 invoke,
569 )
570}
571
572fn expand_rust_function_shim_impl(
573 sig: &Signature,
574 types: &Types,
David Tolnay891061b2020-04-19 22:42:33 -0700575 link_name: &Symbol,
David Tolnay75dca2e2020-03-25 20:17:52 -0700576 local_name: Ident,
577 catch_unwind_label: String,
578 invoke: Option<&Ident>,
579) -> TokenStream {
David Tolnay9938b642020-11-15 18:11:40 -0800580 let generics = &sig.generics;
David Tolnayf9ffb932020-04-20 02:22:57 -0700581 let receiver_var = sig
582 .receiver
583 .as_ref()
584 .map(|receiver| quote_spanned!(receiver.var.span=> __self));
David Tolnay18ba92c2020-04-22 16:17:30 -0700585 let receiver = sig.receiver.as_ref().map(|receiver| {
586 let receiver_type = receiver.ty();
587 quote!(#receiver_var: #receiver_type)
588 });
David Tolnay75dca2e2020-03-25 20:17:52 -0700589 let args = sig.args.iter().map(|arg| {
David Tolnay39d575f2020-03-03 00:10:56 -0800590 let ident = &arg.ident;
David Tolnay2f090422020-11-02 18:25:35 -0800591 let ty = expand_extern_type(&arg.ty, types, false);
David Tolnay39d575f2020-03-03 00:10:56 -0800592 if types.needs_indirect_abi(&arg.ty) {
593 quote!(#ident: *mut #ty)
594 } else {
595 quote!(#ident: #ty)
596 }
597 });
David Tolnayf9ffb932020-04-20 02:22:57 -0700598 let all_args = receiver.into_iter().chain(args);
David Tolnay75dca2e2020-03-25 20:17:52 -0700599
David Tolnay3a45f2d2020-04-20 01:51:12 -0700600 let arg_vars = sig.args.iter().map(|arg| {
David Tolnay7db73692019-10-20 14:51:12 -0400601 let ident = &arg.ident;
David Tolnay17955e22020-01-20 17:58:24 -0800602 match &arg.ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700603 Type::Ident(i) if i.rust == RustString => {
David Tolnaycc3767f2020-03-06 10:41:51 -0800604 quote!(::std::mem::take((*#ident).as_mut_string()))
605 }
David Tolnay40226ab2020-03-03 00:05:35 -0800606 Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#ident)),
David Tolnay33f56ad2020-08-27 17:06:35 -0700607 Type::RustVec(vec) => {
608 if vec.inner == RustString {
609 quote!(::std::mem::take((*#ident).as_mut_vec_string()))
610 } else {
611 quote!(::std::mem::take((*#ident).as_mut_vec()))
612 }
613 }
David Tolnaybf7ae812020-11-16 23:31:45 -0800614 Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#ident)),
David Tolnay17955e22020-01-20 17:58:24 -0800615 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800616 Type::Ident(i) if i.rust == RustString => match ty.mutable {
617 false => quote!(#ident.as_string()),
618 true => quote!(#ident.as_mut_string()),
David Tolnayf1c7f322020-08-27 00:46:01 -0700619 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800620 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
621 false => quote!(#ident.as_vec_string()),
622 true => quote!(#ident.as_mut_vec_string()),
David Tolnay33f56ad2020-08-27 17:06:35 -0700623 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800624 Type::RustVec(_) => match ty.mutable {
625 false => quote!(#ident.as_vec()),
626 true => quote!(#ident.as_mut_vec()),
David Tolnayf1c7f322020-08-27 00:46:01 -0700627 },
David Tolnay40226ab2020-03-03 00:05:35 -0800628 _ => quote!(#ident),
David Tolnay17955e22020-01-20 17:58:24 -0800629 },
David Tolnay40226ab2020-03-03 00:05:35 -0800630 Type::Str(_) => quote!(#ident.as_str()),
David Tolnay5515a9e2020-11-25 19:07:54 -0800631 Type::SliceRef(slice) => {
632 let inner = &slice.inner;
633 match slice.mutable {
634 false => quote!(#ident.as_slice::<#inner>()),
635 true => quote!(#ident.as_mut_slice::<#inner>()),
636 }
637 }
David Tolnay40226ab2020-03-03 00:05:35 -0800638 ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
639 _ => quote!(#ident),
David Tolnay7db73692019-10-20 14:51:12 -0400640 }
641 });
David Tolnayf9ffb932020-04-20 02:22:57 -0700642 let vars = receiver_var.into_iter().chain(arg_vars);
David Tolnay75dca2e2020-03-25 20:17:52 -0700643
David Tolnay26219462020-11-09 19:47:28 -0800644 let wrap_super = invoke.map(|invoke| expand_rust_function_shim_super(sig, &local_name, invoke));
645
David Tolnay75dca2e2020-03-25 20:17:52 -0700646 let mut call = match invoke {
David Tolnay26219462020-11-09 19:47:28 -0800647 Some(_) => quote!(#local_name),
David Tolnayb8ebeb02020-10-31 23:52:06 -0700648 None => quote!(::std::mem::transmute::<*const (), #sig>(__extern)),
David Tolnay75dca2e2020-03-25 20:17:52 -0700649 };
650 call.extend(quote! { (#(#vars),*) });
651
David Tolnay22602b42020-09-21 18:04:05 -0400652 let conversion = sig.ret.as_ref().and_then(|ret| match ret {
Adrian Taylorc8713432020-10-21 18:20:55 -0700653 Type::Ident(ident) if ident.rust == RustString => {
654 Some(quote!(::cxx::private::RustString::from))
655 }
David Tolnay22602b42020-09-21 18:04:05 -0400656 Type::RustBox(_) => Some(quote!(::std::boxed::Box::into_raw)),
657 Type::RustVec(vec) => {
658 if vec.inner == RustString {
659 Some(quote!(::cxx::private::RustVec::from_vec_string))
660 } else {
661 Some(quote!(::cxx::private::RustVec::from))
David Tolnay7db73692019-10-20 14:51:12 -0400662 }
David Tolnay22602b42020-09-21 18:04:05 -0400663 }
David Tolnaybf7ae812020-11-16 23:31:45 -0800664 Type::UniquePtr(_) => Some(quote!(::cxx::UniquePtr::into_raw)),
David Tolnay22602b42020-09-21 18:04:05 -0400665 Type::Ref(ty) => match &ty.inner {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800666 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
667 false => Some(quote!(::cxx::private::RustString::from_ref)),
668 true => Some(quote!(::cxx::private::RustString::from_mut)),
David Tolnay7db73692019-10-20 14:51:12 -0400669 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800670 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
671 false => Some(quote!(::cxx::private::RustVec::from_ref_vec_string)),
672 true => Some(quote!(::cxx::private::RustVec::from_mut_vec_string)),
David Tolnay22602b42020-09-21 18:04:05 -0400673 },
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800674 Type::RustVec(_) => match ty.mutable {
675 false => Some(quote!(::cxx::private::RustVec::from_ref)),
676 true => Some(quote!(::cxx::private::RustVec::from_mut)),
David Tolnay22602b42020-09-21 18:04:05 -0400677 },
David Tolnay7db73692019-10-20 14:51:12 -0400678 _ => None,
David Tolnay22602b42020-09-21 18:04:05 -0400679 },
680 Type::Str(_) => Some(quote!(::cxx::private::RustStr::from)),
David Tolnay73b72642020-11-25 17:44:05 -0800681 Type::SliceRef(ty) => match ty.mutable {
David Tolnay5515a9e2020-11-25 19:07:54 -0800682 false => Some(quote!(::cxx::private::RustSlice::from_ref)),
683 true => Some(quote!(::cxx::private::RustSlice::from_mut)),
David Tolnayc5629f02020-11-23 18:32:46 -0800684 },
David Tolnay22602b42020-09-21 18:04:05 -0400685 _ => None,
686 });
687
688 let mut expr = match conversion {
689 None => call,
690 Some(conversion) if !sig.throws => quote!(#conversion(#call)),
691 Some(conversion) => quote!(::std::result::Result::map(#call, #conversion)),
692 };
David Tolnay75dca2e2020-03-25 20:17:52 -0700693
694 let mut outparam = None;
695 let indirect_return = indirect_return(sig, types);
David Tolnay1e548172020-03-16 13:37:09 -0700696 if indirect_return {
David Tolnay2f090422020-11-02 18:25:35 -0800697 let ret = expand_extern_type(sig.ret.as_ref().unwrap(), types, false);
David Tolnay75dca2e2020-03-25 20:17:52 -0700698 outparam = Some(quote!(__return: *mut #ret,));
David Tolnay1e548172020-03-16 13:37:09 -0700699 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700700 if sig.throws {
701 let out = match sig.ret {
David Tolnaycecada62020-03-17 01:45:58 -0700702 Some(_) => quote!(__return),
703 None => quote!(&mut ()),
704 };
705 expr = quote!(::cxx::private::r#try(#out, #expr));
David Tolnay1e548172020-03-16 13:37:09 -0700706 } else if indirect_return {
David Tolnay7db73692019-10-20 14:51:12 -0400707 expr = quote!(::std::ptr::write(__return, #expr));
708 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700709
David Tolnay1e548172020-03-16 13:37:09 -0700710 expr = quote!(::cxx::private::catch_unwind(__fn, move || #expr));
David Tolnay75dca2e2020-03-25 20:17:52 -0700711
712 let ret = if sig.throws {
David Tolnay486b6ec2020-03-17 01:19:57 -0700713 quote!(-> ::cxx::private::Result)
David Tolnay1e548172020-03-16 13:37:09 -0700714 } else {
David Tolnay2f090422020-11-02 18:25:35 -0800715 expand_extern_return_type(&sig.ret, types, false)
David Tolnay1e548172020-03-16 13:37:09 -0700716 };
David Tolnay75dca2e2020-03-25 20:17:52 -0700717
718 let pointer = match invoke {
David Tolnayb8ebeb02020-10-31 23:52:06 -0700719 None => Some(quote!(__extern: *const ())),
David Tolnay75dca2e2020-03-25 20:17:52 -0700720 Some(_) => None,
721 };
722
David Tolnay7db73692019-10-20 14:51:12 -0400723 quote! {
724 #[doc(hidden)]
725 #[export_name = #link_name]
David Tolnay9938b642020-11-15 18:11:40 -0800726 unsafe extern "C" fn #local_name #generics(#(#all_args,)* #outparam #pointer) #ret {
David Tolnay7db73692019-10-20 14:51:12 -0400727 let __fn = concat!(module_path!(), #catch_unwind_label);
David Tolnay26219462020-11-09 19:47:28 -0800728 #wrap_super
David Tolnay7db73692019-10-20 14:51:12 -0400729 #expr
730 }
731 }
732}
733
David Tolnay26219462020-11-09 19:47:28 -0800734// A wrapper like `fn f(x: Arg) { super::f(x) }` just to ensure we have the
735// accurate unsafety declaration and no problematic elided lifetimes.
736fn expand_rust_function_shim_super(
737 sig: &Signature,
738 local_name: &Ident,
739 invoke: &Ident,
740) -> TokenStream {
741 let unsafety = sig.unsafety;
David Tolnay9938b642020-11-15 18:11:40 -0800742 let generics = &sig.generics;
David Tolnay26219462020-11-09 19:47:28 -0800743
744 let receiver_var = sig
745 .receiver
746 .as_ref()
747 .map(|receiver| Ident::new("__self", receiver.var.span));
748 let receiver = sig.receiver.iter().map(|receiver| {
749 let receiver_type = receiver.ty();
750 quote!(#receiver_var: #receiver_type)
751 });
752 let args = sig.args.iter().map(|arg| quote!(#arg));
753 let all_args = receiver.chain(args);
754
David Tolnay5d164672020-11-09 20:23:17 -0800755 let ret = if let Some((result, _langle, rangle)) = sig.throws_tokens {
David Tolnay26219462020-11-09 19:47:28 -0800756 let ok = match &sig.ret {
757 Some(ret) => quote!(#ret),
758 None => quote!(()),
759 };
David Tolnay5d164672020-11-09 20:23:17 -0800760 let impl_trait = quote_spanned!(result.span=> impl);
761 let display = quote_spanned!(rangle.span=> ::std::fmt::Display);
762 quote!(-> ::std::result::Result<#ok, #impl_trait #display>)
David Tolnay26219462020-11-09 19:47:28 -0800763 } else {
764 expand_return_type(&sig.ret)
765 };
766
767 let arg_vars = sig.args.iter().map(|arg| &arg.ident);
768 let vars = receiver_var.iter().chain(arg_vars);
769
770 let span = invoke.span();
771 let call = match &sig.receiver {
772 None => quote_spanned!(span=> super::#invoke),
773 Some(receiver) => {
774 let receiver_type = &receiver.ty;
775 quote_spanned!(span=> #receiver_type::#invoke)
776 }
777 };
778
779 quote_spanned! {span=>
David Tolnay9938b642020-11-15 18:11:40 -0800780 #unsafety fn #local_name #generics(#(#all_args,)*) #ret {
David Tolnay26219462020-11-09 19:47:28 -0800781 #call(#(#vars,)*)
782 }
783 }
784}
785
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700786fn expand_type_alias(alias: &TypeAlias) -> TokenStream {
Bryan Henry890083d2020-09-13 10:34:31 -0700787 let doc = &alias.doc;
David Tolnay17a934c2020-11-02 00:40:04 -0800788 let ident = &alias.name.rust;
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700789 let ty = &alias.ty;
790 quote! {
Bryan Henry890083d2020-09-13 10:34:31 -0700791 #doc
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700792 pub type #ident = #ty;
793 }
794}
795
Adrian Taylorc8713432020-10-21 18:20:55 -0700796fn expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream {
David Tolnay17a934c2020-11-02 00:40:04 -0800797 let ident = &alias.name.rust;
798 let type_id = type_id(&alias.name);
David Tolnay83fe0f02020-05-07 20:00:15 -0700799 let begin_span = alias.type_token.span;
800 let end_span = alias.semi_token.span;
801 let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
802 let end = quote_spanned!(end_span=> >);
803
David Tolnay63a0e4e2020-10-03 18:52:32 -0700804 let mut verify = quote! {
David Tolnay83fe0f02020-05-07 20:00:15 -0700805 const _: fn() = #begin #ident, #type_id #end;
David Tolnay63a0e4e2020-10-03 18:52:32 -0700806 };
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700807
David Tolnay17a934c2020-11-02 00:40:04 -0800808 if types.required_trivial.contains_key(&alias.name.rust) {
David Tolnay63a0e4e2020-10-03 18:52:32 -0700809 let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_kind::<);
810 verify.extend(quote! {
811 const _: fn() = #begin #ident, ::cxx::kind::Trivial #end;
812 });
Adrian Taylorc7043292020-09-25 12:48:36 -0700813 }
David Tolnay63a0e4e2020-10-03 18:52:32 -0700814
815 verify
Adrian Taylorc7043292020-09-25 12:48:36 -0700816}
817
David Tolnay8faec772020-11-02 00:18:19 -0800818fn type_id(name: &Pair) -> TokenStream {
819 let path = name.to_fully_qualified();
David Tolnay5f9e8ca2020-05-07 17:21:05 -0700820 quote! {
821 ::cxx::type_id!(#path)
822 }
823}
824
Adrian Taylorc8713432020-10-21 18:20:55 -0700825fn expand_rust_box(ident: &ResolvableName, types: &Types) -> TokenStream {
David Tolnay0f0162f2020-11-16 23:43:37 -0800826 let link_prefix = format!("cxxbridge1$box${}$", types.resolve(ident).to_symbol());
David Tolnay7db73692019-10-20 14:51:12 -0400827 let link_uninit = format!("{}uninit", link_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400828 let link_drop = format!("{}drop", link_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400829
Adrian Taylorc8713432020-10-21 18:20:55 -0700830 let local_prefix = format_ident!("{}__box_", &ident.rust);
David Tolnay7db73692019-10-20 14:51:12 -0400831 let local_uninit = format_ident!("{}uninit", local_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400832 let local_drop = format_ident!("{}drop", local_prefix);
David Tolnay7db73692019-10-20 14:51:12 -0400833
834 let span = ident.span();
835 quote_spanned! {span=>
836 #[doc(hidden)]
837 #[export_name = #link_uninit]
838 unsafe extern "C" fn #local_uninit(
839 this: *mut ::std::boxed::Box<::std::mem::MaybeUninit<#ident>>,
840 ) {
841 ::std::ptr::write(
842 this,
843 ::std::boxed::Box::new(::std::mem::MaybeUninit::uninit()),
844 );
845 }
846 #[doc(hidden)]
David Tolnay7db73692019-10-20 14:51:12 -0400847 #[export_name = #link_drop]
848 unsafe extern "C" fn #local_drop(this: *mut ::std::boxed::Box<#ident>) {
849 ::std::ptr::drop_in_place(this);
850 }
David Tolnay7db73692019-10-20 14:51:12 -0400851 }
852}
853
Adrian Taylorc8713432020-10-21 18:20:55 -0700854fn expand_rust_vec(elem: &ResolvableName, types: &Types) -> TokenStream {
David Tolnay0f0162f2020-11-16 23:43:37 -0800855 let link_prefix = format!("cxxbridge1$rust_vec${}$", elem.to_symbol(types));
David Tolnayf97c2d52020-04-25 16:37:48 -0700856 let link_new = format!("{}new", link_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700857 let link_drop = format!("{}drop", link_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700858 let link_len = format!("{}len", link_prefix);
David Tolnay219c0792020-04-24 20:31:37 -0700859 let link_data = format!("{}data", link_prefix);
David Tolnayfb6b73c2020-11-10 14:32:16 -0800860 let link_reserve_total = format!("{}reserve_total", link_prefix);
861 let link_set_len = format!("{}set_len", link_prefix);
David Tolnay503d0192020-04-24 22:18:56 -0700862 let link_stride = format!("{}stride", link_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700863
Adrian Taylorc8713432020-10-21 18:20:55 -0700864 let local_prefix = format_ident!("{}__vec_", elem.rust);
David Tolnayf97c2d52020-04-25 16:37:48 -0700865 let local_new = format_ident!("{}new", local_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700866 let local_drop = format_ident!("{}drop", local_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700867 let local_len = format_ident!("{}len", local_prefix);
David Tolnay219c0792020-04-24 20:31:37 -0700868 let local_data = format_ident!("{}data", local_prefix);
David Tolnayfb6b73c2020-11-10 14:32:16 -0800869 let local_reserve_total = format_ident!("{}reserve_total", local_prefix);
870 let local_set_len = format_ident!("{}set_len", local_prefix);
David Tolnay503d0192020-04-24 22:18:56 -0700871 let local_stride = format_ident!("{}stride", local_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +0700872
David Tolnay83a7ec92020-04-25 12:37:42 -0700873 let span = elem.span();
Myron Ahneba35cf2020-02-05 19:41:51 +0700874 quote_spanned! {span=>
875 #[doc(hidden)]
David Tolnayf97c2d52020-04-25 16:37:48 -0700876 #[export_name = #link_new]
877 unsafe extern "C" fn #local_new(this: *mut ::cxx::private::RustVec<#elem>) {
878 ::std::ptr::write(this, ::cxx::private::RustVec::new());
879 }
880 #[doc(hidden)]
Myron Ahneba35cf2020-02-05 19:41:51 +0700881 #[export_name = #link_drop]
David Tolnay83a7ec92020-04-25 12:37:42 -0700882 unsafe extern "C" fn #local_drop(this: *mut ::cxx::private::RustVec<#elem>) {
David Tolnay4c64afb2020-04-24 11:30:18 -0700883 ::std::ptr::drop_in_place(this);
Myron Ahneba35cf2020-02-05 19:41:51 +0700884 }
David Tolnay85db5a02020-04-25 13:17:27 -0700885 #[doc(hidden)]
Myron Ahneba35cf2020-02-05 19:41:51 +0700886 #[export_name = #link_len]
David Tolnay83a7ec92020-04-25 12:37:42 -0700887 unsafe extern "C" fn #local_len(this: *const ::cxx::private::RustVec<#elem>) -> usize {
David Tolnay2cef5df2020-04-24 11:33:58 -0700888 (*this).len()
Myron Ahneba35cf2020-02-05 19:41:51 +0700889 }
David Tolnay219c0792020-04-24 20:31:37 -0700890 #[doc(hidden)]
891 #[export_name = #link_data]
David Tolnay83a7ec92020-04-25 12:37:42 -0700892 unsafe extern "C" fn #local_data(this: *const ::cxx::private::RustVec<#elem>) -> *const #elem {
David Tolnay219c0792020-04-24 20:31:37 -0700893 (*this).as_ptr()
894 }
David Tolnay503d0192020-04-24 22:18:56 -0700895 #[doc(hidden)]
David Tolnayfb6b73c2020-11-10 14:32:16 -0800896 #[export_name = #link_reserve_total]
897 unsafe extern "C" fn #local_reserve_total(this: *mut ::cxx::private::RustVec<#elem>, cap: usize) {
898 (*this).reserve_total(cap);
899 }
900 #[doc(hidden)]
901 #[export_name = #link_set_len]
902 unsafe extern "C" fn #local_set_len(this: *mut ::cxx::private::RustVec<#elem>, len: usize) {
903 (*this).set_len(len);
904 }
905 #[doc(hidden)]
David Tolnay503d0192020-04-24 22:18:56 -0700906 #[export_name = #link_stride]
907 unsafe extern "C" fn #local_stride() -> usize {
David Tolnay83a7ec92020-04-25 12:37:42 -0700908 ::std::mem::size_of::<#elem>()
David Tolnay503d0192020-04-24 22:18:56 -0700909 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700910 }
911}
912
David Tolnay0531f432020-10-03 23:50:28 -0700913fn expand_unique_ptr(
Adrian Taylorc8713432020-10-21 18:20:55 -0700914 ident: &ResolvableName,
David Tolnay0531f432020-10-03 23:50:28 -0700915 types: &Types,
916 explicit_impl: Option<&Impl>,
917) -> TokenStream {
Adrian Taylorc8713432020-10-21 18:20:55 -0700918 let name = ident.rust.to_string();
David Tolnay0f0162f2020-11-16 23:43:37 -0800919 let prefix = format!("cxxbridge1$unique_ptr${}$", ident.to_symbol(types));
David Tolnay7db73692019-10-20 14:51:12 -0400920 let link_null = format!("{}null", prefix);
921 let link_new = format!("{}new", prefix);
922 let link_raw = format!("{}raw", prefix);
923 let link_get = format!("{}get", prefix);
924 let link_release = format!("{}release", prefix);
925 let link_drop = format!("{}drop", prefix);
926
David Tolnay15609ab2020-11-25 07:14:12 -0800927 let can_construct_from_value = types.structs.contains_key(&ident.rust)
928 || types.enums.contains_key(&ident.rust)
929 || types.aliases.contains_key(&ident.rust);
930 let new_method = if can_construct_from_value {
931 Some(quote! {
932 fn __new(mut value: Self) -> *mut ::std::ffi::c_void {
933 extern "C" {
934 #[link_name = #link_new]
935 fn __new(this: *mut *mut ::std::ffi::c_void, value: *mut #ident);
David Tolnay53838912020-04-09 20:56:44 -0700936 }
David Tolnay15609ab2020-11-25 07:14:12 -0800937 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
938 unsafe { __new(&mut repr, &mut value) }
939 repr
940 }
941 })
942 } else {
943 None
944 };
David Tolnay53838912020-04-09 20:56:44 -0700945
David Tolnay0531f432020-10-03 23:50:28 -0700946 let begin_span =
947 explicit_impl.map_or_else(Span::call_site, |explicit| explicit.impl_token.span);
948 let end_span = explicit_impl.map_or_else(Span::call_site, |explicit| explicit.brace_token.span);
949 let unsafe_token = format_ident!("unsafe", span = begin_span);
950
951 quote_spanned! {end_span=>
952 #unsafe_token impl ::cxx::private::UniquePtrTarget for #ident {
David Tolnay3b40b6f2020-04-24 17:58:24 -0700953 const __NAME: &'static dyn ::std::fmt::Display = &#name;
David Tolnay7db73692019-10-20 14:51:12 -0400954 fn __null() -> *mut ::std::ffi::c_void {
955 extern "C" {
956 #[link_name = #link_null]
957 fn __null(this: *mut *mut ::std::ffi::c_void);
958 }
959 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
960 unsafe { __null(&mut repr) }
961 repr
962 }
David Tolnay53838912020-04-09 20:56:44 -0700963 #new_method
David Tolnay7db73692019-10-20 14:51:12 -0400964 unsafe fn __raw(raw: *mut Self) -> *mut ::std::ffi::c_void {
965 extern "C" {
966 #[link_name = #link_raw]
David Tolnay3b40b6f2020-04-24 17:58:24 -0700967 fn __raw(this: *mut *mut ::std::ffi::c_void, raw: *mut #ident);
David Tolnay7db73692019-10-20 14:51:12 -0400968 }
969 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
970 __raw(&mut repr, raw);
971 repr
972 }
973 unsafe fn __get(repr: *mut ::std::ffi::c_void) -> *const Self {
974 extern "C" {
975 #[link_name = #link_get]
David Tolnay3b40b6f2020-04-24 17:58:24 -0700976 fn __get(this: *const *mut ::std::ffi::c_void) -> *const #ident;
David Tolnay7db73692019-10-20 14:51:12 -0400977 }
978 __get(&repr)
979 }
980 unsafe fn __release(mut repr: *mut ::std::ffi::c_void) -> *mut Self {
981 extern "C" {
982 #[link_name = #link_release]
David Tolnay3b40b6f2020-04-24 17:58:24 -0700983 fn __release(this: *mut *mut ::std::ffi::c_void) -> *mut #ident;
David Tolnay7db73692019-10-20 14:51:12 -0400984 }
985 __release(&mut repr)
986 }
987 unsafe fn __drop(mut repr: *mut ::std::ffi::c_void) {
988 extern "C" {
989 #[link_name = #link_drop]
990 fn __drop(this: *mut *mut ::std::ffi::c_void);
991 }
992 __drop(&mut repr);
993 }
994 }
995 }
996}
997
David Tolnay0531f432020-10-03 23:50:28 -0700998fn expand_cxx_vector(
Adrian Taylorc8713432020-10-21 18:20:55 -0700999 elem: &ResolvableName,
David Tolnay0531f432020-10-03 23:50:28 -07001000 explicit_impl: Option<&Impl>,
Adrian Taylorc8713432020-10-21 18:20:55 -07001001 types: &Types,
David Tolnay0531f432020-10-03 23:50:28 -07001002) -> TokenStream {
1003 let _ = explicit_impl;
Adrian Taylorc8713432020-10-21 18:20:55 -07001004 let name = elem.rust.to_string();
David Tolnay0f0162f2020-11-16 23:43:37 -08001005 let prefix = format!("cxxbridge1$std$vector${}$", elem.to_symbol(types));
David Tolnaya83247c2020-04-24 14:36:10 -07001006 let link_size = format!("{}size", prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +07001007 let link_get_unchecked = format!("{}get_unchecked", prefix);
Adrian Taylorc8713432020-10-21 18:20:55 -07001008 let unique_ptr_prefix = format!(
David Tolnay0f0162f2020-11-16 23:43:37 -08001009 "cxxbridge1$unique_ptr$std$vector${}$",
Adrian Taylorc8713432020-10-21 18:20:55 -07001010 elem.to_symbol(types)
1011 );
David Tolnay3b40b6f2020-04-24 17:58:24 -07001012 let link_unique_ptr_null = format!("{}null", unique_ptr_prefix);
1013 let link_unique_ptr_raw = format!("{}raw", unique_ptr_prefix);
1014 let link_unique_ptr_get = format!("{}get", unique_ptr_prefix);
1015 let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
1016 let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix);
Myron Ahneba35cf2020-02-05 19:41:51 +07001017
David Tolnay0531f432020-10-03 23:50:28 -07001018 let begin_span =
1019 explicit_impl.map_or_else(Span::call_site, |explicit| explicit.impl_token.span);
1020 let end_span = explicit_impl.map_or_else(Span::call_site, |explicit| explicit.brace_token.span);
1021 let unsafe_token = format_ident!("unsafe", span = begin_span);
1022
1023 quote_spanned! {end_span=>
1024 #unsafe_token impl ::cxx::private::VectorElement for #elem {
David Tolnay3b40b6f2020-04-24 17:58:24 -07001025 const __NAME: &'static dyn ::std::fmt::Display = &#name;
David Tolnay17631102020-04-24 19:01:30 -07001026 fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
David Tolnayfa2119c2020-04-24 14:42:58 -07001027 extern "C" {
1028 #[link_name = #link_size]
David Tolnay17631102020-04-24 19:01:30 -07001029 fn __vector_size(_: &::cxx::CxxVector<#elem>) -> usize;
Myron Ahneba35cf2020-02-05 19:41:51 +07001030 }
David Tolnayfa2119c2020-04-24 14:42:58 -07001031 unsafe { __vector_size(v) }
Myron Ahneba35cf2020-02-05 19:41:51 +07001032 }
David Tolnay93637ca2020-09-24 15:58:20 -04001033 unsafe fn __get_unchecked(v: &::cxx::CxxVector<Self>, pos: usize) -> *const Self {
David Tolnaycc75ad22020-04-24 14:45:16 -07001034 extern "C" {
1035 #[link_name = #link_get_unchecked]
David Tolnay17631102020-04-24 19:01:30 -07001036 fn __get_unchecked(_: &::cxx::CxxVector<#elem>, _: usize) -> *const #elem;
David Tolnaycc75ad22020-04-24 14:45:16 -07001037 }
David Tolnay93637ca2020-09-24 15:58:20 -04001038 __get_unchecked(v, pos)
David Tolnaycc75ad22020-04-24 14:45:16 -07001039 }
David Tolnay3b40b6f2020-04-24 17:58:24 -07001040 fn __unique_ptr_null() -> *mut ::std::ffi::c_void {
1041 extern "C" {
1042 #[link_name = #link_unique_ptr_null]
1043 fn __unique_ptr_null(this: *mut *mut ::std::ffi::c_void);
1044 }
1045 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
1046 unsafe { __unique_ptr_null(&mut repr) }
1047 repr
1048 }
1049 unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> *mut ::std::ffi::c_void {
1050 extern "C" {
1051 #[link_name = #link_unique_ptr_raw]
1052 fn __unique_ptr_raw(this: *mut *mut ::std::ffi::c_void, raw: *mut ::cxx::CxxVector<#elem>);
1053 }
1054 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
1055 __unique_ptr_raw(&mut repr, raw);
1056 repr
1057 }
1058 unsafe fn __unique_ptr_get(repr: *mut ::std::ffi::c_void) -> *const ::cxx::CxxVector<Self> {
1059 extern "C" {
1060 #[link_name = #link_unique_ptr_get]
1061 fn __unique_ptr_get(this: *const *mut ::std::ffi::c_void) -> *const ::cxx::CxxVector<#elem>;
1062 }
1063 __unique_ptr_get(&repr)
1064 }
1065 unsafe fn __unique_ptr_release(mut repr: *mut ::std::ffi::c_void) -> *mut ::cxx::CxxVector<Self> {
1066 extern "C" {
1067 #[link_name = #link_unique_ptr_release]
1068 fn __unique_ptr_release(this: *mut *mut ::std::ffi::c_void) -> *mut ::cxx::CxxVector<#elem>;
1069 }
1070 __unique_ptr_release(&mut repr)
1071 }
1072 unsafe fn __unique_ptr_drop(mut repr: *mut ::std::ffi::c_void) {
1073 extern "C" {
1074 #[link_name = #link_unique_ptr_drop]
1075 fn __unique_ptr_drop(this: *mut *mut ::std::ffi::c_void);
1076 }
1077 __unique_ptr_drop(&mut repr);
1078 }
Myron Ahneba35cf2020-02-05 19:41:51 +07001079 }
1080 }
1081}
1082
David Tolnay7db73692019-10-20 14:51:12 -04001083fn expand_return_type(ret: &Option<Type>) -> TokenStream {
1084 match ret {
1085 Some(ret) => quote!(-> #ret),
1086 None => TokenStream::new(),
1087 }
1088}
1089
David Tolnay75dca2e2020-03-25 20:17:52 -07001090fn indirect_return(sig: &Signature, types: &Types) -> bool {
1091 sig.ret
David Tolnay1e548172020-03-16 13:37:09 -07001092 .as_ref()
David Tolnay75dca2e2020-03-25 20:17:52 -07001093 .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
David Tolnay7db73692019-10-20 14:51:12 -04001094}
1095
David Tolnay2f090422020-11-02 18:25:35 -08001096fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
David Tolnay7db73692019-10-20 14:51:12 -04001097 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -07001098 Type::Ident(ident) if ident.rust == RustString => quote!(::cxx::private::RustString),
David Tolnay7db73692019-10-20 14:51:12 -04001099 Type::RustBox(ty) | Type::UniquePtr(ty) => {
David Tolnay2f090422020-11-02 18:25:35 -08001100 let inner = expand_extern_type(&ty.inner, types, proper);
David Tolnay7db73692019-10-20 14:51:12 -04001101 quote!(*mut #inner)
1102 }
David Tolnaye6d50212020-04-25 15:38:23 -07001103 Type::RustVec(ty) => {
David Tolnay2f090422020-11-02 18:25:35 -08001104 let elem = expand_extern_type(&ty.inner, types, proper);
David Tolnaye6d50212020-04-25 15:38:23 -07001105 quote!(::cxx::private::RustVec<#elem>)
1106 }
David Tolnayf1c7f322020-08-27 00:46:01 -07001107 Type::Ref(ty) => {
1108 let mutability = ty.mutability;
1109 match &ty.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -07001110 Type::Ident(ident) if ident.rust == RustString => {
David Tolnayf1c7f322020-08-27 00:46:01 -07001111 quote!(&#mutability ::cxx::private::RustString)
1112 }
1113 Type::RustVec(ty) => {
David Tolnay2f090422020-11-02 18:25:35 -08001114 let inner = expand_extern_type(&ty.inner, types, proper);
David Tolnayf1c7f322020-08-27 00:46:01 -07001115 quote!(&#mutability ::cxx::private::RustVec<#inner>)
1116 }
David Tolnay9c4ac2e2020-11-15 21:14:03 -08001117 inner if proper && types.is_considered_improper_ctype(inner) => match ty.mutable {
1118 false => quote!(*const ::std::ffi::c_void),
1119 true => quote!(*#mutability ::std::ffi::c_void),
David Tolnay4cb97672020-11-02 16:13:34 -08001120 },
David Tolnayf1c7f322020-08-27 00:46:01 -07001121 _ => quote!(#ty),
Myron Ahneba35cf2020-02-05 19:41:51 +07001122 }
David Tolnayf1c7f322020-08-27 00:46:01 -07001123 }
David Tolnay7db73692019-10-20 14:51:12 -04001124 Type::Str(_) => quote!(::cxx::private::RustStr),
David Tolnay5515a9e2020-11-25 19:07:54 -08001125 Type::SliceRef(_) => quote!(::cxx::private::RustSlice),
David Tolnay7db73692019-10-20 14:51:12 -04001126 _ => quote!(#ty),
1127 }
1128}
1129
David Tolnay2f090422020-11-02 18:25:35 -08001130fn expand_extern_return_type(ret: &Option<Type>, types: &Types, proper: bool) -> TokenStream {
David Tolnay7db73692019-10-20 14:51:12 -04001131 let ret = match ret {
1132 Some(ret) if !types.needs_indirect_abi(ret) => ret,
1133 _ => return TokenStream::new(),
1134 };
David Tolnay2f090422020-11-02 18:25:35 -08001135 let ty = expand_extern_type(ret, types, proper);
David Tolnay7db73692019-10-20 14:51:12 -04001136 quote!(-> #ty)
1137}