Skip to content

Commit

Permalink
Merge pull request #2083 from bendk/macro-ffi-ops
Browse files Browse the repository at this point in the history
Factor out FFI converter operations
  • Loading branch information
bendk committed May 1, 2024
2 parents 3d93e26 + 3e6338f commit a47508d
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 141 deletions.
25 changes: 18 additions & 7 deletions uniffi_macros/src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
* 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 crate::util::{derive_all_ffi_traits, ident_to_string, mod_path, tagged_impl_header};
use crate::{
ffiops,
util::{derive_all_ffi_traits, ident_to_string, mod_path, tagged_impl_header},
};
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::Path;
Expand All @@ -18,34 +21,42 @@ pub(crate) fn expand_ffi_converter_custom_type(
let derive_ffi_traits = derive_all_ffi_traits(ident, udl_mode);
let name = ident_to_string(ident);
let mod_path = mod_path()?;
let from_custom = quote! { <#ident as crate::UniffiCustomTypeConverter>::from_custom };
let into_custom = quote! { <#ident as crate::UniffiCustomTypeConverter>::into_custom };
let lower_type = ffiops::lower_type(builtin);
let lower = ffiops::lower(builtin);
let write = ffiops::write(builtin);
let try_lift = ffiops::try_lift(builtin);
let try_read = ffiops::try_read(builtin);
let type_id_meta = ffiops::type_id_meta(builtin);

Ok(quote! {
#[automatically_derived]
unsafe #impl_spec {
// Note: the builtin type needs to implement both `Lower` and `Lift'. We use the
// `Lower` trait to get the associated type `FfiType` and const `TYPE_ID_META`. These
// can't differ between `Lower` and `Lift`.
type FfiType = <#builtin as ::uniffi::Lower<crate::UniFfiTag>>::FfiType;
type FfiType = #lower_type;
fn lower(obj: #ident ) -> Self::FfiType {
<#builtin as ::uniffi::Lower<crate::UniFfiTag>>::lower(<#ident as crate::UniffiCustomTypeConverter>::from_custom(obj))
#lower(#from_custom(obj))
}

fn try_lift(v: Self::FfiType) -> uniffi::Result<#ident> {
<#ident as crate::UniffiCustomTypeConverter>::into_custom(<#builtin as ::uniffi::Lift<crate::UniFfiTag>>::try_lift(v)?)
#into_custom(#try_lift(v)?)
}

fn write(obj: #ident, buf: &mut Vec<u8>) {
<#builtin as ::uniffi::Lower<crate::UniFfiTag>>::write(<#ident as crate::UniffiCustomTypeConverter>::from_custom(obj), buf);
#write(#from_custom(obj), buf);
}

fn try_read(buf: &mut &[u8]) -> uniffi::Result<#ident> {
<#ident as crate::UniffiCustomTypeConverter>::into_custom(<#builtin as ::uniffi::Lift<crate::UniFfiTag>>::try_read(buf)?)
#into_custom(#try_read(buf)?)
}

const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_CUSTOM)
.concat_str(#mod_path)
.concat_str(#name)
.concat(<#builtin as ::uniffi::TypeId<crate::UniFfiTag>>::TYPE_ID_META);
.concat(#type_id_meta);
}

#derive_ffi_traits
Expand Down
26 changes: 15 additions & 11 deletions uniffi_macros/src/enum_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ use syn::{
Attribute, Data, DataEnum, DeriveInput, Expr, Index, Lit, Variant,
};

use crate::util::{
create_metadata_items, derive_all_ffi_traits, either_attribute_arg, extract_docstring,
ident_to_string, kw, mod_path, parse_comma_separated, tagged_impl_header,
try_metadata_value_from_usize, try_read_field, AttributeSliceExt, UniffiAttributeArgs,
use crate::{
ffiops,
util::{
create_metadata_items, derive_all_ffi_traits, either_attribute_arg, extract_docstring,
ident_to_string, kw, mod_path, parse_comma_separated, tagged_impl_header,
try_metadata_value_from_usize, try_read_field, AttributeSliceExt, UniffiAttributeArgs,
},
};

fn extract_repr(attrs: &[Attribute]) -> syn::Result<Option<Ident>> {
Expand Down Expand Up @@ -134,10 +137,8 @@ fn enum_or_error_ffi_converter_impl(
let idx = Index::from(i + 1);
let write_fields =
std::iter::zip(v.fields.iter(), field_idents.iter()).map(|(f, ident)| {
let ty = &f.ty;
quote! {
<#ty as ::uniffi::Lower<crate::UniFfiTag>>::write(#ident, buf);
}
let write = ffiops::write(&f.ty);
quote! { #write(#ident, buf); }
});
let is_tuple = v.fields.iter().any(|f| f.ident.is_none());
let fields = if is_tuple {
Expand Down Expand Up @@ -230,7 +231,10 @@ pub(crate) fn enum_meta_static_var(
};
metadata_expr.extend(match discr_type {
None => quote! { .concat_bool(false) },
Some(t) => quote! { .concat_bool(true).concat(<#t as ::uniffi::TypeId<crate::UniFfiTag>>::TYPE_ID_META) }
Some(t) => {
let type_id_meta = ffiops::type_id_meta(t);
quote! { .concat_bool(true).concat(#type_id_meta) }
}
});
metadata_expr.extend(variant_metadata(enum_)?);
metadata_expr.extend(quote! {
Expand Down Expand Up @@ -315,20 +319,20 @@ pub fn variant_metadata(enum_: &DataEnum) -> syn::Result<Vec<TokenStream>> {
let name = ident_to_string(&v.ident);
let value_tokens = variant_value(v)?;
let docstring = extract_docstring(&v.attrs)?;
let field_types = v.fields.iter().map(|f| &f.ty);
let field_docstrings = v
.fields
.iter()
.map(|f| extract_docstring(&f.attrs))
.collect::<syn::Result<Vec<_>>>()?;
let field_type_id_metas = v.fields.iter().map(|f| ffiops::type_id_meta(&f.ty));

Ok(quote! {
.concat_str(#name)
#value_tokens
.concat_value(#fields_len)
#(
.concat_str(#field_names)
.concat(<#field_types as ::uniffi::TypeId<crate::UniFfiTag>>::TYPE_ID_META)
.concat(#field_type_id_metas)
// field defaults not yet supported for enums
.concat_bool(false)
.concat_long_str(#field_docstrings)
Expand Down
32 changes: 21 additions & 11 deletions uniffi_macros/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use syn::{

use crate::{
enum_::{rich_error_ffi_converter_impl, variant_metadata, EnumAttr},
ffiops,
util::{
chain, create_metadata_items, derive_ffi_traits, either_attribute_arg, extract_docstring,
ident_to_string, kw, mod_path, parse_comma_separated, tagged_impl_header,
Expand Down Expand Up @@ -97,23 +98,31 @@ fn flat_error_ffi_converter_impl(
};

let lower_impl = {
let mut match_arms: Vec<_> = enum_.variants.iter().enumerate().map(|(i, v)| {
let v_ident = &v.ident;
let idx = Index::from(i + 1);
let mut match_arms: Vec<_> = enum_
.variants
.iter()
.enumerate()
.map(|(i, v)| {
let v_ident = &v.ident;
let idx = Index::from(i + 1);
let write_string = ffiops::write(quote! { ::std::string::String });

quote! {
Self::#v_ident { .. } => {
::uniffi::deps::bytes::BufMut::put_i32(buf, #idx);
<::std::string::String as ::uniffi::Lower<crate::UniFfiTag>>::write(error_msg, buf);
quote! {
Self::#v_ident { .. } => {
::uniffi::deps::bytes::BufMut::put_i32(buf, #idx);
#write_string(error_msg, buf);
}
}
}
}).collect();
})
.collect();
if attr.non_exhaustive.is_some() {
match_arms.push(quote! {
_ => panic!("Unexpected variant in non-exhaustive enum"),
})
}

let lower = ffiops::lower_into_rust_buffer(quote! { Self });

quote! {
#[automatically_derived]
unsafe #lower_impl_spec {
Expand All @@ -125,7 +134,7 @@ fn flat_error_ffi_converter_impl(
}

fn lower(obj: Self) -> ::uniffi::RustBuffer {
<Self as ::uniffi::Lower<crate::UniFfiTag>>::lower_into_rust_buffer(obj)
#lower(obj)
}
}
}
Expand All @@ -140,6 +149,7 @@ fn flat_error_ffi_converter_impl(
#idx => Self::#v_ident,
}
});
let try_lift = ffiops::try_lift_from_rust_buffer(quote! { Self });
quote! {
#[automatically_derived]
unsafe #lift_impl_spec {
Expand All @@ -153,7 +163,7 @@ fn flat_error_ffi_converter_impl(
}

fn try_lift(v: ::uniffi::RustBuffer) -> ::uniffi::deps::anyhow::Result<Self> {
<Self as ::uniffi::Lift<crate::UniFfiTag>>::try_lift_from_rust_buffer(v)
#try_lift(v)
}
}
}
Expand Down
66 changes: 34 additions & 32 deletions uniffi_macros/src/export/callback_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::{
export::ImplItem,
ffiops,
fnsig::{FnKind, FnSignature, ReceiverArg},
util::{
create_metadata_items, derive_ffi_traits, ident_to_string, mod_path, tagged_impl_header,
Expand Down Expand Up @@ -44,33 +45,32 @@ pub(super) fn trait_impl(
})
.collect::<syn::Result<Vec<_>>>()?;

let vtable_fields = methods.iter()
.map(|sig| {
let ident = &sig.ident;
let param_names = sig.scaffolding_param_names();
let param_types = sig.scaffolding_param_types();
let lift_return = sig.lift_return_impl();
if !sig.is_async {
quote! {
#ident: extern "C" fn(
uniffi_handle: u64,
#(#param_names: #param_types,)*
uniffi_out_return: &mut #lift_return::ReturnType,
uniffi_out_call_status: &mut ::uniffi::RustCallStatus,
),
}
} else {
quote! {
#ident: extern "C" fn(
uniffi_handle: u64,
#(#param_names: #param_types,)*
uniffi_future_callback: ::uniffi::ForeignFutureCallback<#lift_return::ReturnType>,
uniffi_callback_data: u64,
uniffi_out_return: &mut ::uniffi::ForeignFuture,
),
}
let vtable_fields = methods.iter().map(|sig| {
let ident = &sig.ident;
let param_names = sig.scaffolding_param_names();
let param_types = sig.scaffolding_param_types();
let lift_return_type = ffiops::lift_return_type(&sig.return_ty);
if !sig.is_async {
quote! {
#ident: extern "C" fn(
uniffi_handle: u64,
#(#param_names: #param_types,)*
uniffi_out_return: &mut #lift_return_type,
uniffi_out_call_status: &mut ::uniffi::RustCallStatus,
),
}
});
} else {
quote! {
#ident: extern "C" fn(
uniffi_handle: u64,
#(#param_names: #param_types,)*
uniffi_future_callback: ::uniffi::ForeignFutureCallback<#lift_return_type>,
uniffi_callback_data: u64,
uniffi_out_return: &mut ::uniffi::ForeignFuture,
),
}
}
});

let trait_impl_methods = methods
.iter()
Expand Down Expand Up @@ -141,6 +141,7 @@ pub fn ffi_converter_callback_interface_impl(
Ok(p) => p,
Err(e) => return e.into_compile_error(),
};
let try_lift_self = ffiops::try_lift(quote! { Self });

quote! {
#[doc(hidden)]
Expand All @@ -155,7 +156,7 @@ pub fn ffi_converter_callback_interface_impl(
fn try_read(buf: &mut &[u8]) -> ::uniffi::deps::anyhow::Result<Self> {
use uniffi::deps::bytes::Buf;
::uniffi::check_remaining(buf, 8)?;
<Self as ::uniffi::Lift<crate::UniFfiTag>>::try_lift(buf.get_u64())
#try_lift_self(buf.get_u64())
}
}

Expand Down Expand Up @@ -209,21 +210,22 @@ fn gen_method_impl(sig: &FnSignature, vtable_cell: &Ident) -> syn::Result<TokenS

let params = sig.params();
let lower_exprs = sig.args.iter().map(|a| {
let lower_impl = a.lower_impl();
let lower = ffiops::lower(&a.ty);
let ident = &a.ident;
quote! { #lower_impl::lower(#ident) }
quote! { #lower(#ident) }
});

let lift_return = sig.lift_return_impl();
let lift_return_type = ffiops::lift_return_type(&sig.return_ty);
let lift_foreign_return = ffiops::lift_foreign_return(&sig.return_ty);

if !is_async {
Ok(quote! {
fn #ident(#self_param, #(#params),*) -> #return_ty {
let vtable = #vtable_cell.get();
let mut uniffi_call_status = ::uniffi::RustCallStatus::new();
let mut uniffi_return_value: #lift_return::ReturnType = ::uniffi::FfiDefault::ffi_default();
let mut uniffi_return_value: #lift_return_type = ::uniffi::FfiDefault::ffi_default();
(vtable.#ident)(self.handle, #(#lower_exprs,)* &mut uniffi_return_value, &mut uniffi_call_status);
#lift_return::lift_foreign_return(uniffi_return_value, uniffi_call_status)
#lift_foreign_return(uniffi_return_value, uniffi_call_status)
}
})
} else {
Expand Down
Loading

0 comments on commit a47508d

Please sign in to comment.