diff options
Diffstat (limited to 'third_party/rust/uniffi_macros/src/object.rs')
-rw-r--r-- | third_party/rust/uniffi_macros/src/object.rs | 76 |
1 files changed, 54 insertions, 22 deletions
diff --git a/third_party/rust/uniffi_macros/src/object.rs b/third_party/rust/uniffi_macros/src/object.rs index 573a1eaadd..6bcc07a14e 100644 --- a/third_party/rust/uniffi_macros/src/object.rs +++ b/third_party/rust/uniffi_macros/src/object.rs @@ -1,17 +1,27 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; use syn::DeriveInput; -use uniffi_meta::free_fn_symbol_name; -use crate::util::{create_metadata_items, ident_to_string, mod_path, tagged_impl_header}; +use crate::util::{ + create_metadata_items, extract_docstring, ident_to_string, mod_path, tagged_impl_header, +}; +use uniffi_meta::ObjectImpl; pub fn expand_object(input: DeriveInput, udl_mode: bool) -> syn::Result<TokenStream> { let module_path = mod_path()?; let ident = &input.ident; + let docstring = extract_docstring(&input.attrs)?; let name = ident_to_string(ident); - let free_fn_ident = Ident::new(&free_fn_symbol_name(&module_path, &name), Span::call_site()); + let clone_fn_ident = Ident::new( + &uniffi_meta::clone_fn_symbol_name(&module_path, &name), + Span::call_site(), + ); + let free_fn_ident = Ident::new( + &uniffi_meta::free_fn_symbol_name(&module_path, &name), + Span::call_site(), + ); let meta_static_var = (!udl_mode).then(|| { - interface_meta_static_var(ident, false, &module_path) + interface_meta_static_var(ident, ObjectImpl::Struct, &module_path, docstring) .unwrap_or_else(syn::Error::into_compile_error) }); let interface_impl = interface_impl(ident, udl_mode); @@ -19,7 +29,19 @@ pub fn expand_object(input: DeriveInput, udl_mode: bool) -> syn::Result<TokenStr Ok(quote! { #[doc(hidden)] #[no_mangle] - pub extern "C" fn #free_fn_ident( + pub unsafe extern "C" fn #clone_fn_ident( + ptr: *const ::std::ffi::c_void, + call_status: &mut ::uniffi::RustCallStatus + ) -> *const ::std::ffi::c_void { + uniffi::rust_call(call_status, || { + unsafe { ::std::sync::Arc::increment_strong_count(ptr) }; + Ok(ptr) + }) + } + + #[doc(hidden)] + #[no_mangle] + pub unsafe extern "C" fn #free_fn_ident( ptr: *const ::std::ffi::c_void, call_status: &mut ::uniffi::RustCallStatus ) { @@ -41,6 +63,7 @@ pub fn expand_object(input: DeriveInput, udl_mode: bool) -> syn::Result<TokenStr pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { let name = ident_to_string(ident); let impl_spec = tagged_impl_header("FfiConverterArc", ident, udl_mode); + let lower_return_impl_spec = tagged_impl_header("LowerReturn", ident, udl_mode); let lift_ref_impl_spec = tagged_impl_header("LiftRef", ident, udl_mode); let mod_path = match mod_path() { Ok(p) => p, @@ -52,7 +75,7 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { // if they are not, but unfortunately it fails with an unactionably obscure error message. // By asserting the requirement explicitly, we help Rust produce a more scrutable error message // and thus help the user debug why the requirement isn't being met. - uniffi::deps::static_assertions::assert_impl_all!(#ident: Sync, Send); + uniffi::deps::static_assertions::assert_impl_all!(#ident: ::core::marker::Sync, ::core::marker::Send); #[doc(hidden)] #[automatically_derived] @@ -78,17 +101,10 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { ::std::sync::Arc::into_raw(obj) as Self::FfiType } - /// When lifting, we receive a "borrow" of the `Arc` that is owned by - /// the foreign-language code, and make a clone of it for our own use. - /// - /// Safety: the provided value must be a pointer previously obtained by calling - /// the `lower()` or `write()` method of this impl. + /// When lifting, we receive an owned `Arc` that the foreign language code cloned. fn try_lift(v: Self::FfiType) -> ::uniffi::Result<::std::sync::Arc<Self>> { let v = v as *const #ident; - // We musn't drop the `Arc` that is owned by the foreign-language code. - let foreign_arc = ::std::mem::ManuallyDrop::new(unsafe { ::std::sync::Arc::<Self>::from_raw(v) }); - // Take a clone for our own use. - Ok(::std::sync::Arc::clone(&*foreign_arc)) + Ok(unsafe { ::std::sync::Arc::<Self>::from_raw(v) }) } /// When writing as a field of a complex structure, make a clone and transfer ownership @@ -117,8 +133,17 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_INTERFACE) .concat_str(#mod_path) - .concat_str(#name) - .concat_bool(false); + .concat_str(#name); + } + + unsafe #lower_return_impl_spec { + type ReturnType = <Self as ::uniffi::FfiConverterArc<crate::UniFfiTag>>::FfiType; + + fn lower_return(obj: Self) -> ::std::result::Result<Self::ReturnType, ::uniffi::RustBuffer> { + Ok(<Self as ::uniffi::FfiConverterArc<crate::UniFfiTag>>::lower(::std::sync::Arc::new(obj))) + } + + const TYPE_ID_META: ::uniffi::MetadataBuffer = <Self as ::uniffi::FfiConverterArc<crate::UniFfiTag>>::TYPE_ID_META; } unsafe #lift_ref_impl_spec { @@ -129,18 +154,25 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { pub(crate) fn interface_meta_static_var( ident: &Ident, - is_trait: bool, + imp: ObjectImpl, module_path: &str, + docstring: String, ) -> syn::Result<TokenStream> { let name = ident_to_string(ident); + let code = match imp { + ObjectImpl::Struct => quote! { ::uniffi::metadata::codes::INTERFACE }, + ObjectImpl::Trait => quote! { ::uniffi::metadata::codes::TRAIT_INTERFACE }, + ObjectImpl::CallbackTrait => quote! { ::uniffi::metadata::codes::CALLBACK_TRAIT_INTERFACE }, + }; + Ok(create_metadata_items( "interface", &name, quote! { - ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::INTERFACE) - .concat_str(#module_path) - .concat_str(#name) - .concat_bool(#is_trait) + ::uniffi::MetadataBuffer::from_code(#code) + .concat_str(#module_path) + .concat_str(#name) + .concat_long_str(#docstring) }, None, )) |