summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_macros/src/export/scaffolding.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_macros/src/export/scaffolding.rs')
-rw-r--r--third_party/rust/uniffi_macros/src/export/scaffolding.rs123
1 files changed, 77 insertions, 46 deletions
diff --git a/third_party/rust/uniffi_macros/src/export/scaffolding.rs b/third_party/rust/uniffi_macros/src/export/scaffolding.rs
index f120ccc880..fa7b61deca 100644
--- a/third_party/rust/uniffi_macros/src/export/scaffolding.rs
+++ b/third_party/rust/uniffi_macros/src/export/scaffolding.rs
@@ -6,12 +6,12 @@ use proc_macro2::{Ident, TokenStream};
use quote::quote;
use std::iter;
-use super::attributes::{AsyncRuntime, ExportAttributeArguments};
-use crate::fnsig::{FnKind, FnSignature, NamedArg};
+use super::attributes::AsyncRuntime;
+use crate::fnsig::{FnKind, FnSignature};
pub(super) fn gen_fn_scaffolding(
sig: FnSignature,
- arguments: &ExportAttributeArguments,
+ ar: &Option<AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
if sig.receiver.is_some() {
@@ -21,7 +21,7 @@ pub(super) fn gen_fn_scaffolding(
));
}
if !sig.is_async {
- if let Some(async_runtime) = &arguments.async_runtime {
+ if let Some(async_runtime) = ar {
return Err(syn::Error::new_spanned(
async_runtime,
"this attribute is only allowed on async functions",
@@ -32,7 +32,7 @@ pub(super) fn gen_fn_scaffolding(
sig.metadata_items()
.unwrap_or_else(syn::Error::into_compile_error)
});
- let scaffolding_func = gen_ffi_function(&sig, arguments, udl_mode)?;
+ let scaffolding_func = gen_ffi_function(&sig, ar, udl_mode)?;
Ok(quote! {
#scaffolding_func
#metadata_items
@@ -41,7 +41,7 @@ pub(super) fn gen_fn_scaffolding(
pub(super) fn gen_constructor_scaffolding(
sig: FnSignature,
- arguments: &ExportAttributeArguments,
+ ar: &Option<AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
if sig.receiver.is_some() {
@@ -50,14 +50,11 @@ pub(super) fn gen_constructor_scaffolding(
"constructors must not have a self parameter",
));
}
- if sig.is_async {
- return Err(syn::Error::new(sig.span, "constructors can't be async"));
- }
let metadata_items = (!udl_mode).then(|| {
sig.metadata_items()
.unwrap_or_else(syn::Error::into_compile_error)
});
- let scaffolding_func = gen_ffi_function(&sig, arguments, udl_mode)?;
+ let scaffolding_func = gen_ffi_function(&sig, ar, udl_mode)?;
Ok(quote! {
#scaffolding_func
#metadata_items
@@ -66,7 +63,7 @@ pub(super) fn gen_constructor_scaffolding(
pub(super) fn gen_method_scaffolding(
sig: FnSignature,
- arguments: &ExportAttributeArguments,
+ ar: &Option<AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
let scaffolding_func = if sig.receiver.is_none() {
@@ -75,7 +72,7 @@ pub(super) fn gen_method_scaffolding(
"associated functions are not currently supported",
));
} else {
- gen_ffi_function(&sig, arguments, udl_mode)?
+ gen_ffi_function(&sig, ar, udl_mode)?
};
let metadata_items = (!udl_mode).then(|| {
@@ -90,31 +87,37 @@ pub(super) fn gen_method_scaffolding(
// Pieces of code for the scaffolding function
struct ScaffoldingBits {
- /// Parameters for the scaffolding function
- params: Vec<TokenStream>,
+ /// Parameter names for the scaffolding function
+ param_names: Vec<TokenStream>,
+ /// Parameter types for the scaffolding function
+ param_types: Vec<TokenStream>,
/// Lift closure. See `FnSignature::lift_closure` for an explanation of this.
lift_closure: TokenStream,
/// Expression to call the Rust function after a successful lift.
rust_fn_call: TokenStream,
+ /// Convert the result of `rust_fn_call`, stored in a variable named `uniffi_result` into its final value.
+ /// This is used to do things like error conversion / Arc wrapping
+ convert_result: TokenStream,
}
impl ScaffoldingBits {
fn new_for_function(sig: &FnSignature, udl_mode: bool) -> Self {
let ident = &sig.ident;
- let params: Vec<_> = sig.args.iter().map(NamedArg::scaffolding_param).collect();
let call_params = sig.rust_call_params(false);
let rust_fn_call = quote! { #ident(#call_params) };
// UDL mode adds an extra conversion (#1749)
- let rust_fn_call = if udl_mode && sig.looks_like_result {
- quote! { #rust_fn_call.map_err(::std::convert::Into::into) }
+ let convert_result = if udl_mode && sig.looks_like_result {
+ quote! { uniffi_result.map_err(::std::convert::Into::into) }
} else {
- rust_fn_call
+ quote! { uniffi_result }
};
Self {
- params,
+ param_names: sig.scaffolding_param_names().collect(),
+ param_types: sig.scaffolding_param_types().collect(),
lift_closure: sig.lift_closure(None),
rust_fn_call,
+ convert_result,
}
}
@@ -125,20 +128,32 @@ impl ScaffoldingBits {
udl_mode: bool,
) -> Self {
let ident = &sig.ident;
- let ffi_converter = if is_trait {
+ let lift_impl = if is_trait {
quote! {
- <::std::sync::Arc<dyn #self_ident> as ::uniffi::FfiConverter<crate::UniFfiTag>>
+ <::std::sync::Arc<dyn #self_ident> as ::uniffi::Lift<crate::UniFfiTag>>
}
} else {
quote! {
- <::std::sync::Arc<#self_ident> as ::uniffi::FfiConverter<crate::UniFfiTag>>
+ <::std::sync::Arc<#self_ident> as ::uniffi::Lift<crate::UniFfiTag>>
}
};
- let params: Vec<_> = iter::once(quote! { uniffi_self_lowered: #ffi_converter::FfiType })
- .chain(sig.scaffolding_params())
- .collect();
+ let try_lift_self = if is_trait {
+ // For trait interfaces we need to special case this. Trait interfaces normally lift
+ // foreign trait impl pointers. However, for a method call, we want to lift a Rust
+ // pointer.
+ quote! {
+ {
+ let boxed_foreign_arc = unsafe { Box::from_raw(uniffi_self_lowered as *mut ::std::sync::Arc<dyn #self_ident>) };
+ // Take a clone for our own use.
+ Ok(*boxed_foreign_arc)
+ }
+ }
+ } else {
+ quote! { #lift_impl::try_lift(uniffi_self_lowered) }
+ };
+
let lift_closure = sig.lift_closure(Some(quote! {
- match #ffi_converter::try_lift(uniffi_self_lowered) {
+ match #try_lift_self {
Ok(v) => v,
Err(e) => return Err(("self", e))
}
@@ -146,38 +161,45 @@ impl ScaffoldingBits {
let call_params = sig.rust_call_params(true);
let rust_fn_call = quote! { uniffi_args.0.#ident(#call_params) };
// UDL mode adds an extra conversion (#1749)
- let rust_fn_call = if udl_mode && sig.looks_like_result {
- quote! { #rust_fn_call.map_err(::std::convert::Into::into) }
+ let convert_result = if udl_mode && sig.looks_like_result {
+ quote! { uniffi_result .map_err(::std::convert::Into::into) }
} else {
- rust_fn_call
+ quote! { uniffi_result }
};
Self {
- params,
+ param_names: iter::once(quote! { uniffi_self_lowered })
+ .chain(sig.scaffolding_param_names())
+ .collect(),
+ param_types: iter::once(quote! { #lift_impl::FfiType })
+ .chain(sig.scaffolding_param_types())
+ .collect(),
lift_closure,
rust_fn_call,
+ convert_result,
}
}
fn new_for_constructor(sig: &FnSignature, self_ident: &Ident, udl_mode: bool) -> Self {
let ident = &sig.ident;
- let params: Vec<_> = sig.args.iter().map(NamedArg::scaffolding_param).collect();
let call_params = sig.rust_call_params(false);
let rust_fn_call = quote! { #self_ident::#ident(#call_params) };
// UDL mode adds extra conversions (#1749)
- let rust_fn_call = match (udl_mode, sig.looks_like_result) {
+ let convert_result = match (udl_mode, sig.looks_like_result) {
// For UDL
- (true, false) => quote! { ::std::sync::Arc::new(#rust_fn_call) },
+ (true, false) => quote! { ::std::sync::Arc::new(uniffi_result) },
(true, true) => {
- quote! { #rust_fn_call.map(::std::sync::Arc::new).map_err(::std::convert::Into::into) }
+ quote! { uniffi_result.map(::std::sync::Arc::new).map_err(::std::convert::Into::into) }
}
- (false, _) => rust_fn_call,
+ (false, _) => quote! { uniffi_result },
};
Self {
- params,
+ param_names: sig.scaffolding_param_names().collect(),
+ param_types: sig.scaffolding_param_types().collect(),
lift_closure: sig.lift_closure(None),
rust_fn_call,
+ convert_result,
}
}
}
@@ -188,13 +210,15 @@ impl ScaffoldingBits {
/// `rust_fn` is the Rust function to call.
pub(super) fn gen_ffi_function(
sig: &FnSignature,
- arguments: &ExportAttributeArguments,
+ ar: &Option<AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
let ScaffoldingBits {
- params,
+ param_names,
+ param_types,
lift_closure,
rust_fn_call,
+ convert_result,
} = match &sig.kind {
FnKind::Function => ScaffoldingBits::new_for_function(sig, udl_mode),
FnKind::Method { self_ident } => {
@@ -216,14 +240,15 @@ pub(super) fn gen_ffi_function(
let ffi_ident = sig.scaffolding_fn_ident()?;
let name = &sig.name;
- let return_impl = &sig.return_impl();
+ let return_ty = &sig.return_ty;
+ let return_impl = &sig.lower_return_impl();
Ok(if !sig.is_async {
quote! {
#[doc(hidden)]
#[no_mangle]
#vis extern "C" fn #ffi_ident(
- #(#params,)*
+ #(#param_names: #param_types,)*
call_status: &mut ::uniffi::RustCallStatus,
) -> #return_impl::ReturnType {
::uniffi::deps::log::debug!(#name);
@@ -231,7 +256,10 @@ pub(super) fn gen_ffi_function(
::uniffi::rust_call(call_status, || {
#return_impl::lower_return(
match uniffi_lift_args() {
- Ok(uniffi_args) => #rust_fn_call,
+ Ok(uniffi_args) => {
+ let uniffi_result = #rust_fn_call;
+ #convert_result
+ }
Err((arg_name, anyhow_error)) => {
#return_impl::handle_failed_lift(arg_name, anyhow_error)
},
@@ -242,25 +270,28 @@ pub(super) fn gen_ffi_function(
}
} else {
let mut future_expr = rust_fn_call;
- if matches!(arguments.async_runtime, Some(AsyncRuntime::Tokio(_))) {
+ if matches!(ar, Some(AsyncRuntime::Tokio(_))) {
future_expr = quote! { ::uniffi::deps::async_compat::Compat::new(#future_expr) }
}
quote! {
#[doc(hidden)]
#[no_mangle]
- pub extern "C" fn #ffi_ident(#(#params,)*) -> ::uniffi::RustFutureHandle {
+ pub extern "C" fn #ffi_ident(#(#param_names: #param_types,)*) -> ::uniffi::Handle {
::uniffi::deps::log::debug!(#name);
let uniffi_lift_args = #lift_closure;
match uniffi_lift_args() {
Ok(uniffi_args) => {
- ::uniffi::rust_future_new(
- async move { #future_expr.await },
+ ::uniffi::rust_future_new::<_, #return_ty, _>(
+ async move {
+ let uniffi_result = #future_expr.await;
+ #convert_result
+ },
crate::UniFfiTag
)
},
Err((arg_name, anyhow_error)) => {
- ::uniffi::rust_future_new(
+ ::uniffi::rust_future_new::<_, #return_ty, _>(
async move {
#return_impl::handle_failed_lift(arg_name, anyhow_error)
},