in uniffi_macros/src/export/scaffolding.rs [127:188]
fn new_for_method(
sig: &FnSignature,
self_ident: &Ident,
is_trait: bool,
udl_mode: bool,
) -> Self {
let ident = &sig.ident;
let self_type = if is_trait {
quote! { ::std::sync::Arc<dyn #self_ident> }
} else {
quote! { ::std::sync::Arc<#self_ident> }
};
let lift_type = ffiops::lift_type(&self_type);
let try_lift = ffiops::try_lift(&self_type);
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 {
::std::boxed::Box::from_raw(
uniffi_self_lowered as *mut ::std::sync::Arc<dyn #self_ident>,
)
};
// Take a clone for our own use.
::std::result::Result::Ok(*boxed_foreign_arc)
}
}
} else {
quote! { #try_lift(uniffi_self_lowered) }
};
let lift_closure = sig.lift_closure(Some(quote! {
match #try_lift_self {
::std::result::Result::Ok(v) => v,
::std::result::Result::Err(e) => {
return ::std::result::Result::Err(("self", e));
}
}
}));
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 convert_result = if udl_mode && sig.looks_like_result {
quote! { uniffi_result .map_err(::std::convert::Into::into) }
} else {
quote! { uniffi_result }
};
Self {
param_names: iter::once(quote! { uniffi_self_lowered })
.chain(sig.scaffolding_param_names())
.collect(),
param_types: iter::once(quote! { #lift_type })
.chain(sig.scaffolding_param_types())
.collect(),
lift_closure,
rust_fn_call,
convert_result,
}
}