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/. */
7 fnsig::{FnKind, FnSignature, ReceiverArg},
8 util::{create_metadata_items, ident_to_string, mod_path, tagged_impl_header},
10 use proc_macro2::{Span, TokenStream};
15 pub(super) fn trait_impl(
18 internals_ident: &Ident,
20 ) -> syn::Result<TokenStream> {
21 let trait_impl_methods = items
23 .map(|item| match item {
24 ImplItem::Method(sig) => gen_method_impl(sig, internals_ident),
25 _ => unreachable!("traits have no constructors"),
27 .collect::<syn::Result<TokenStream>>()?;
28 let ffi_converter_tokens = ffi_converter_callback_interface_impl(trait_ident, ident, false);
38 fn new(handle: u64) -> Self {
43 impl ::std::ops::Drop for #ident {
45 #internals_ident.invoke_callback::<(), crate::UniFfiTag>(
46 self.handle, uniffi::IDX_CALLBACK_FREE, Default::default()
51 ::uniffi::deps::static_assertions::assert_impl_all!(#ident: Send);
53 impl #trait_ident for #ident {
61 pub fn ffi_converter_callback_interface_impl(
63 trait_impl_ident: &Ident,
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() {
73 Err(e) => return e.into_compile_error(),
78 #[automatically_derived]
79 unsafe #lift_impl_spec {
82 fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<Self> {
83 Ok(::std::boxed::Box::new(<#trait_impl_ident>::new(v)))
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())
92 const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(
93 ::uniffi::metadata::codes::TYPE_CALLBACK_INTERFACE,
95 .concat_str(#mod_path)
99 unsafe #lift_ref_impl_spec {
100 type LiftType = #box_dyn_trait;
105 fn gen_method_impl(sig: &FnSignature, internals_ident: &Ident) -> syn::Result<TokenStream> {
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,
117 return Err(syn::Error::new(
120 "Internal UniFFI error: Unexpected function kind for callback interface {k:?}"
126 let self_param = match receiver {
128 return Err(syn::Error::new(
130 "callback interface methods must take &self as their first argument",
133 Some(ReceiverArg::Ref) => quote! { &self },
134 Some(ReceiverArg::Arc) => quote! { self: Arc<Self> },
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);
141 fn #ident(#self_param, #(#params),*) -> #return_ty {
143 let mut #buf_ident = ::std::vec::Vec::new();
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)
152 pub(super) fn metadata_items(
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",
162 ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::CALLBACK_INTERFACE)
163 .concat_str(#module_path)
164 .concat_str(#trait_name)
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"),