Skip to content

Commit

Permalink
Recactored callback interface macro code
Browse files Browse the repository at this point in the history
The goal is to re-use this for trait interfaces
  • Loading branch information
bendk committed Oct 18, 2023
1 parent 1c4df96 commit 0924af3
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 48 deletions.
42 changes: 8 additions & 34 deletions uniffi_macros/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use proc_macro2::{Ident, Span, TokenStream};
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::{visit_mut::VisitMut, Item, Type};

Expand Down Expand Up @@ -75,45 +75,19 @@ pub(crate) fn expand_export(
callback_interface: true,
} => {
let trait_name = ident_to_string(&self_ident);
let trait_impl_ident = Ident::new(
&format!("UniFFICallbackHandler{trait_name}"),
Span::call_site(),
);
let internals_ident = Ident::new(
&format!(
"UNIFFI_FOREIGN_CALLBACK_INTERNALS_{}",
trait_name.to_ascii_uppercase()
),
Span::call_site(),
);

let trait_impl = callback_interface::trait_impl(
&trait_impl_ident,
&self_ident,
&internals_ident,
&items,
)
.unwrap_or_else(|e| e.into_compile_error());
let trait_impl_ident = callback_interface::trait_impl_ident(&trait_name);
let trait_impl = callback_interface::trait_impl(&mod_path, &self_ident, &items)
.unwrap_or_else(|e| e.into_compile_error());
let metadata_items = callback_interface::metadata_items(&self_ident, &items, &mod_path)
.unwrap_or_else(|e| vec![e.into_compile_error()]);

let init_ident = Ident::new(
&uniffi_meta::init_callback_fn_symbol_name(&mod_path, &trait_name),
Span::call_site(),
);
let ffi_converter_tokens =
ffi_converter_callback_interface_impl(&self_ident, &trait_impl_ident, udl_mode);

Ok(quote! {
#[doc(hidden)]
static #internals_ident: ::uniffi::ForeignCallbackInternals = ::uniffi::ForeignCallbackInternals::new();

#[doc(hidden)]
#[no_mangle]
pub extern "C" fn #init_ident(callback: ::uniffi::ForeignCallback, _: &mut ::uniffi::RustCallStatus) {
#internals_ident.set_callback(callback);
}

#trait_impl

#ffi_converter_tokens

#(#metadata_items)*
})
}
Expand Down
57 changes: 43 additions & 14 deletions uniffi_macros/src/export/callback_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,57 +13,86 @@ use std::iter;
use syn::Ident;

pub(super) fn trait_impl(
ident: &Ident,
mod_path: &str,
trait_ident: &Ident,
internals_ident: &Ident,
items: &[ImplItem],
) -> syn::Result<TokenStream> {
let trait_name = ident_to_string(trait_ident);
let trait_impl_ident = trait_impl_ident(&trait_name);
let internals_ident = internals_ident(&trait_name);
let init_ident = Ident::new(
&uniffi_meta::init_callback_fn_symbol_name(&mod_path, &trait_name),
Span::call_site(),
);

let trait_impl_methods = items
.iter()
.map(|item| match item {
ImplItem::Method(sig) => gen_method_impl(sig, internals_ident),
ImplItem::Method(sig) => gen_method_impl(sig, &internals_ident),
_ => unreachable!("traits have no constructors"),
})
.collect::<syn::Result<TokenStream>>()?;
let ffi_converter_tokens = ffi_converter_callback_interface_impl(trait_ident, ident, false);

Ok(quote! {
#[doc(hidden)]
static #internals_ident: ::uniffi::ForeignCallbackInternals = ::uniffi::ForeignCallbackInternals::new();

#[doc(hidden)]
#[no_mangle]
pub extern "C" fn #init_ident(callback: ::uniffi::ForeignCallback, _: &mut ::uniffi::RustCallStatus) {
#internals_ident.set_callback(callback);
}

#[doc(hidden)]
#[derive(Debug)]
struct #ident {
struct #trait_impl_ident {
handle: u64,
}

impl #ident {
impl #trait_impl_ident {
fn new(handle: u64) -> Self {
Self { handle }
}
}

impl ::std::ops::Drop for #ident {
impl ::std::ops::Drop for #trait_impl_ident {
fn drop(&mut self) {
#internals_ident.invoke_callback::<(), crate::UniFfiTag>(
self.handle, uniffi::IDX_CALLBACK_FREE, Default::default()
)
}
}

::uniffi::deps::static_assertions::assert_impl_all!(#ident: Send);
::uniffi::deps::static_assertions::assert_impl_all!(#trait_impl_ident: Send);

impl #trait_ident for #ident {
impl #trait_ident for #trait_impl_ident {
#trait_impl_methods
}

#ffi_converter_tokens
})
}

pub fn trait_impl_ident(trait_name: &str) -> Ident {
Ident::new(
&format!("UniFFICallbackHandler{trait_name}"),
Span::call_site(),
)
}

pub fn internals_ident(trait_name: &str) -> Ident {
Ident::new(
&format!(
"UNIFFI_FOREIGN_CALLBACK_INTERNALS_{}",
trait_name.to_ascii_uppercase()
),
Span::call_site(),
)
}

pub fn ffi_converter_callback_interface_impl(
trait_ident: &Ident,
trait_impl_ident: &Ident,
udl_mode: bool,
) -> TokenStream {
let name = ident_to_string(trait_ident);
let trait_name = ident_to_string(trait_ident);
let dyn_trait = quote! { dyn #trait_ident };
let box_dyn_trait = quote! { ::std::boxed::Box<#dyn_trait> };
let lift_impl_spec = tagged_impl_header("Lift", &box_dyn_trait, udl_mode);
Expand Down Expand Up @@ -93,7 +122,7 @@ pub fn ffi_converter_callback_interface_impl(
::uniffi::metadata::codes::TYPE_CALLBACK_INTERFACE,
)
.concat_str(#mod_path)
.concat_str(#name);
.concat_str(#trait_name);
}

unsafe #lift_ref_impl_spec {
Expand Down

0 comments on commit 0924af3

Please sign in to comment.