Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crash...
[gecko.git] / third_party / rust / uniffi_macros / src / export / callback_interface.rs
blob2f2561bbc223289511bc9bbab37748c4263e02a1
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 use crate::{
6     export::ImplItem,
7     fnsig::{FnKind, FnSignature, ReceiverArg},
8     util::{create_metadata_items, ident_to_string, mod_path, tagged_impl_header},
9 };
10 use proc_macro2::{Span, TokenStream};
11 use quote::quote;
12 use std::iter;
13 use syn::Ident;
15 pub(super) fn trait_impl(
16     ident: &Ident,
17     trait_ident: &Ident,
18     internals_ident: &Ident,
19     items: &[ImplItem],
20 ) -> syn::Result<TokenStream> {
21     let trait_impl_methods = items
22         .iter()
23         .map(|item| match item {
24             ImplItem::Method(sig) => gen_method_impl(sig, internals_ident),
25             _ => unreachable!("traits have no constructors"),
26         })
27         .collect::<syn::Result<TokenStream>>()?;
28     let ffi_converter_tokens = ffi_converter_callback_interface_impl(trait_ident, ident, false);
30     Ok(quote! {
31         #[doc(hidden)]
32         #[derive(Debug)]
33         struct #ident {
34             handle: u64,
35         }
37         impl #ident {
38             fn new(handle: u64) -> Self {
39                 Self { handle }
40             }
41         }
43         impl ::std::ops::Drop for #ident {
44             fn drop(&mut self) {
45                 #internals_ident.invoke_callback::<(), crate::UniFfiTag>(
46                     self.handle, uniffi::IDX_CALLBACK_FREE, Default::default()
47                 )
48             }
49         }
51         ::uniffi::deps::static_assertions::assert_impl_all!(#ident: Send);
53         impl #trait_ident for #ident {
54             #trait_impl_methods
55         }
57         #ffi_converter_tokens
58     })
61 pub fn ffi_converter_callback_interface_impl(
62     trait_ident: &Ident,
63     trait_impl_ident: &Ident,
64     udl_mode: bool,
65 ) -> TokenStream {
66     let name = ident_to_string(trait_ident);
67     let dyn_trait = quote! { dyn #trait_ident };
68     let box_dyn_trait = quote! { ::std::boxed::Box<#dyn_trait> };
69     let lift_impl_spec = tagged_impl_header("Lift", &box_dyn_trait, udl_mode);
70     let lift_ref_impl_spec = tagged_impl_header("LiftRef", &dyn_trait, udl_mode);
71     let mod_path = match mod_path() {
72         Ok(p) => p,
73         Err(e) => return e.into_compile_error(),
74     };
76     quote! {
77         #[doc(hidden)]
78         #[automatically_derived]
79         unsafe #lift_impl_spec {
80             type FfiType = u64;
82             fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<Self> {
83                 Ok(::std::boxed::Box::new(<#trait_impl_ident>::new(v)))
84             }
86             fn try_read(buf: &mut &[u8]) -> ::uniffi::deps::anyhow::Result<Self> {
87                 use uniffi::deps::bytes::Buf;
88                 ::uniffi::check_remaining(buf, 8)?;
89                 <Self as ::uniffi::Lift<crate::UniFfiTag>>::try_lift(buf.get_u64())
90             }
92             const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(
93                 ::uniffi::metadata::codes::TYPE_CALLBACK_INTERFACE,
94             )
95             .concat_str(#mod_path)
96             .concat_str(#name);
97         }
99         unsafe #lift_ref_impl_spec {
100             type LiftType = #box_dyn_trait;
101         }
102     }
105 fn gen_method_impl(sig: &FnSignature, internals_ident: &Ident) -> syn::Result<TokenStream> {
106     let FnSignature {
107         ident,
108         return_ty,
109         kind,
110         receiver,
111         ..
112     } = sig;
113     let index = match kind {
114         // Note: the callback index is 1-based, since 0 is reserved for the free function
115         FnKind::TraitMethod { index, .. } => index + 1,
116         k => {
117             return Err(syn::Error::new(
118                 sig.span,
119                 format!(
120                     "Internal UniFFI error: Unexpected function kind for callback interface {k:?}"
121                 ),
122             ));
123         }
124     };
126     let self_param = match receiver {
127         None => {
128             return Err(syn::Error::new(
129                 sig.span,
130                 "callback interface methods must take &self as their first argument",
131             ));
132         }
133         Some(ReceiverArg::Ref) => quote! { &self },
134         Some(ReceiverArg::Arc) => quote! { self: Arc<Self> },
135     };
136     let params = sig.params();
137     let buf_ident = Ident::new("uniffi_args_buf", Span::call_site());
138     let write_exprs = sig.write_exprs(&buf_ident);
140     Ok(quote! {
141         fn #ident(#self_param, #(#params),*) -> #return_ty {
142             #[allow(unused_mut)]
143             let mut #buf_ident = ::std::vec::Vec::new();
144             #(#write_exprs;)*
145             let uniffi_args_rbuf = uniffi::RustBuffer::from_vec(#buf_ident);
147             #internals_ident.invoke_callback::<#return_ty, crate::UniFfiTag>(self.handle, #index, uniffi_args_rbuf)
148         }
149     })
152 pub(super) fn metadata_items(
153     self_ident: &Ident,
154     items: &[ImplItem],
155     module_path: &str,
156 ) -> syn::Result<Vec<TokenStream>> {
157     let trait_name = ident_to_string(self_ident);
158     let callback_interface_items = create_metadata_items(
159         "callback_interface",
160         &trait_name,
161         quote! {
162             ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::CALLBACK_INTERFACE)
163                 .concat_str(#module_path)
164                 .concat_str(#trait_name)
165         },
166         None,
167     );
169     iter::once(Ok(callback_interface_items))
170         .chain(items.iter().map(|item| match item {
171             ImplItem::Method(sig) => sig.metadata_items(),
172             _ => unreachable!("traits have no constructors"),
173         }))
174         .collect()