diff --git a/uniffi_bindgen/src/scaffolding/mod.rs b/uniffi_bindgen/src/scaffolding/mod.rs index c4dae22e8f..7fd81831aa 100644 --- a/uniffi_bindgen/src/scaffolding/mod.rs +++ b/uniffi_bindgen/src/scaffolding/mod.rs @@ -72,40 +72,6 @@ mod filters { }) } - // Map a type to Rust code that specifies the FfiConverter implementation. - // - // This outputs something like `>` - pub fn ffi_trait(type_: &Type, trait_name: &str) -> Result { - Ok(match type_ { - Type::External { - name, - kind: ExternalKind::Interface, - .. - } => { - format!("<::std::sync::Arc as ::uniffi::{trait_name}>") - } - _ => format!( - "<{} as ::uniffi::{trait_name}>", - type_rs(type_)? - ), - }) - } - - pub fn return_type(callable: &T) -> Result { - let return_type = match callable.return_type() { - Some(t) => type_rs(&t)?, - None => "()".to_string(), - }; - match callable.throws_type() { - Some(t) => type_rs(&t)?, - None => "()".to_string(), - }; - Ok(match callable.throws_type() { - Some(e) => format!("::std::result::Result<{return_type}, {}>", type_rs(&e)?), - None => return_type, - }) - } - // Turns a `crate-name` into the `crate_name` the .rs code needs to specify. pub fn crate_name_rs(nm: &str) -> Result { Ok(format!("r#{}", nm.to_string().to_snake_case())) diff --git a/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs b/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs index 7be11554a4..658f4c8de5 100644 --- a/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs +++ b/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs @@ -1,82 +1,17 @@ -{# -// For each Callback Interface definition, we assume that there is a corresponding trait defined in Rust client code. -// If the UDL callback interface and Rust trait's methods don't match, the Rust compiler will complain. -// We generate: -// * an init function to accept that `ForeignCallback` from the foreign language, and stores it. -// * a holder for a `ForeignCallback`, of type `uniffi::ForeignCallbackInternals`. -// * a proxy `struct` which implements the `trait` that the Callback Interface corresponds to. This -// is the object that client code interacts with. -// - for each method, arguments will be packed into a `RustBuffer` and sent over the `ForeignCallback` to be -// unpacked and called. The return value is packed into another `RustBuffer` and sent back to Rust. -// - a `Drop` `impl`, which tells the foreign language to forget about the real callback object. -#} -{% let trait_name = cbi.name() -%} -{% let trait_impl = format!("UniFFICallbackHandler{}", trait_name) %} -{% let foreign_callback_internals = format!("foreign_callback_{}_internals", trait_name)|upper -%} - -// Register a foreign callback for getting across the FFI. -#[doc(hidden)] -static {{ foreign_callback_internals }}: uniffi::ForeignCallbackInternals = uniffi::ForeignCallbackInternals::new(); - -#[doc(hidden)] -#[no_mangle] -pub extern "C" fn {{ cbi.ffi_init_callback().name() }}(callback: uniffi::ForeignCallback, _: &mut uniffi::RustCallStatus) { - {{ foreign_callback_internals }}.set_callback(callback); - // The call status should be initialized to CALL_SUCCESS, so no need to modify it. -} - -// Make an implementation which will shell out to the foreign language. -#[doc(hidden)] -#[derive(Debug)] -struct {{ trait_impl }} { - handle: u64 -} - -impl {{ trait_impl }} { - fn new(handle: u64) -> Self { - Self { handle } - } -} - -impl Drop for {{ trait_impl }} { - fn drop(&mut self) { - {{ foreign_callback_internals }}.invoke_callback::<(), crate::UniFfiTag>( - self.handle, uniffi::IDX_CALLBACK_FREE, Default::default() - ) - } -} - -uniffi::deps::static_assertions::assert_impl_all!({{ trait_impl }}: ::core::marker::Send); - -impl r#{{ trait_name }} for {{ trait_impl }} { +#[::uniffi::export_for_udl(callback_interface)] +pub trait r#{{ cbi.name() }} { {%- for meth in cbi.methods() %} - - {#- Method declaration #} - fn r#{{ meth.name() -}} - ({% call rs::arg_list_decl_with_prefix("&self", meth) %}) - {%- match (meth.return_type(), meth.throws_type()) %} - {%- when (Some(return_type), None) %} -> {{ return_type.borrow()|type_rs }} - {%- when (Some(return_type), Some(err)) %} -> ::std::result::Result<{{ return_type.borrow()|type_rs }}, {{ err|type_rs }}> - {%- when (None, Some(err)) %} -> ::std::result::Result<(), {{ err|type_rs }}> - {% else -%} - {%- endmatch -%} { - {#- Method body #} - - {#- Packing args into a RustBuffer #} - {% if meth.arguments().len() == 0 -%} - let args_buf = Vec::new(); - {% else -%} - let mut args_buf = Vec::new(); - {% endif -%} + fn r#{{ meth.name() }}( + {% if meth.takes_self_by_arc()%}self: Arc{% else %}&self{% endif %}, {%- for arg in meth.arguments() %} - {{ arg.as_type().borrow()|ffi_trait("Lower") }}::write(r#{{ arg.name() }}, &mut args_buf); - {%- endfor -%} - let args_rbuf = uniffi::RustBuffer::from_vec(args_buf); - - {#- Calling into foreign code. #} - {{ foreign_callback_internals }}.invoke_callback::<{{ meth|return_type }}, crate::UniFfiTag>(self.handle, {{ loop.index }}, args_rbuf) - } - {%- endfor %} + r#{{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, + {%- endfor %} + ) + {%- match (meth.return_type(), meth.throws_type()) %} + {%- when (Some(return_type), None) %} -> {{ return_type|type_rs }}; + {%- when (Some(return_type), Some(error_type)) %} -> ::std::result::Result::<{{ return_type|type_rs }}, {{ error_type|type_rs }}>; + {%- when (None, Some(error_type)) %} -> ::std::result::Result::<(), {{ error_type|type_rs }}>; + {%- when (None, None) %}; + {%- endmatch %} + {% endfor %} } - -::uniffi::scaffolding_ffi_converter_callback_interface!(r#{{ trait_name }}, {{ trait_impl }}); diff --git a/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs b/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs index 3a8703102c..c8e845b34d 100644 --- a/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs +++ b/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs @@ -15,10 +15,10 @@ #[::uniffi::export_for_udl] pub trait r#{{ obj.name() }} { {%- for meth in obj.methods() %} - fn {% if meth.is_async() %}async {% endif %}{{ meth.name() }}( + fn {% if meth.is_async() %}async {% endif %}r#{{ meth.name() }}( {% if meth.takes_self_by_arc()%}self: Arc{% else %}&self{% endif %}, {%- for arg in meth.arguments() %} - {{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, + r#{{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, {%- endfor %} ) {%- match (meth.return_type(), meth.throws_type()) %} diff --git a/uniffi_macros/src/export.rs b/uniffi_macros/src/export.rs index 23179c5976..c98d6e059d 100644 --- a/uniffi_macros/src/export.rs +++ b/uniffi_macros/src/export.rs @@ -82,9 +82,12 @@ pub(crate) fn expand_export( 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, docstring) - .unwrap_or_else(|e| vec![e.into_compile_error()]); + let metadata_items = (!udl_mode).then(|| { + let items = + callback_interface::metadata_items(&self_ident, &items, &mod_path, docstring) + .unwrap_or_else(|e| vec![e.into_compile_error()]); + quote! { #(#items)* } + }); let ffi_converter_tokens = ffi_converter_callback_interface_impl(&self_ident, &trait_impl_ident, udl_mode); @@ -93,7 +96,7 @@ pub(crate) fn expand_export( #ffi_converter_tokens - #(#metadata_items)* + #metadata_items }) } ExportItem::Struct { diff --git a/uniffi_macros/src/lib.rs b/uniffi_macros/src/lib.rs index b7ba86ddc1..bf91ba7c77 100644 --- a/uniffi_macros/src/lib.rs +++ b/uniffi_macros/src/lib.rs @@ -33,20 +33,6 @@ use self::{ record::expand_record, }; -struct IdentPair { - lhs: Ident, - rhs: Ident, -} - -impl Parse for IdentPair { - fn parse(input: ParseStream<'_>) -> syn::Result { - let lhs = input.parse()?; - input.parse::()?; - let rhs = input.parse()?; - Ok(Self { lhs, rhs }) - } -} - struct CustomTypeInfo { ident: Ident, builtin: Path, @@ -257,14 +243,6 @@ pub fn export_for_udl(attrs: TokenStream, input: TokenStream) -> TokenStream { do_export(attrs, input, true) } -/// Generate the FfiConverter implementation for an trait interface for the scaffolding code -#[doc(hidden)] -#[proc_macro] -pub fn scaffolding_ffi_converter_callback_interface(tokens: TokenStream) -> TokenStream { - let input: IdentPair = syn::parse_macro_input!(tokens); - export::ffi_converter_callback_interface_impl(&input.lhs, &input.rhs, true).into() -} - /// A helper macro to include generated component scaffolding. /// /// This is a simple convenience macro to include the UniFFI component