diff --git a/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs b/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs index ae4bffc973..c158f54d82 100644 --- a/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs +++ b/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs @@ -24,8 +24,4 @@ impl CodeType for CallbackInterfaceCodeType { fn canonical_name(&self) -> String { format!("Type{}", self.id) } - - fn initialization_fn(&self) -> Option { - Some(format!("uniffiCallbackInterface{}.register", self.id)) - } } diff --git a/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt b/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt index 0fd29c193b..f373decf0d 100644 --- a/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt +++ b/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt @@ -106,7 +106,6 @@ internal object {{ trait_impl }} { // Registers the foreign callback with the Rust side. // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { + internal fun register(lib: UniffiLib): Int = lib.{{ ffi_init_callback.name() }}(vtable) - } } diff --git a/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt b/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt index 7f30bc02fd..30ff7be5a9 100644 --- a/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt +++ b/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt @@ -9,24 +9,26 @@ internal const val UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2 /** * @suppress */ -public abstract class FfiConverterCallbackInterface: FfiConverter { +public abstract class FfiConverterCallbackInterface( + internal val langIndex: Int +): FfiConverterRustBuffer { internal val handleMap = UniffiHandleMap() internal fun drop(handle: Long) { handleMap.remove(handle) } - override fun lift(value: Long): CallbackInterface { - return handleMap.get(value) + override fun read(buf: ByteBuffer): CallbackInterface { + val handle = buf.getLong() + assert(buf.getInt() == this.langIndex) { "Callback interface has been called in the wrong language" } + return handleMap.get(handle) } - override fun read(buf: ByteBuffer) = lift(buf.getLong()) - - override fun lower(value: CallbackInterface) = handleMap.insert(value) - - override fun allocationSize(value: CallbackInterface) = 8UL + override fun allocationSize(value: CallbackInterface) = 12UL override fun write(value: CallbackInterface, buf: ByteBuffer) { - buf.putLong(lower(value)) + val handle = handleMap.insert(value) + buf.putLong(handle) + buf.putInt(langIndex) } } diff --git a/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt b/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt index 6f9b98aa7c..ef9bf24411 100644 --- a/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt +++ b/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt @@ -9,9 +9,12 @@ {% include "Interface.kt" %} {% include "CallbackInterfaceImpl.kt" %} +{%- let trait_impl=format!("uniffiCallbackInterface{}", name) %} /** * The ffiConverter which transforms the Callbacks in to handles to pass to Rust. * * @suppress */ -public object {{ ffi_converter_name }}: FfiConverterCallbackInterface<{{ interface_name }}>() +public object {{ ffi_converter_name }}: FfiConverterCallbackInterface<{{ interface_name }}>( + langIndex = {{ trait_impl }}.register(UniffiLib.INSTANCE) +) diff --git a/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt b/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt index e1c6696de1..19969906f1 100644 --- a/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt +++ b/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt @@ -35,20 +35,10 @@ public interface FfiConverter { // FfiType. It's used by the callback interface code. Callback interface // returns are always serialized into a `RustBuffer` regardless of their // normal FFI type. - fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { - val rbuf = RustBuffer.alloc(allocationSize(value)) - try { - val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity).also { - it.order(ByteOrder.BIG_ENDIAN) - } + fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue = + RustBuffer.write(allocationSize(value)) { bbuf -> write(value, bbuf) - rbuf.writeField("len", bbuf.position().toLong()) - return rbuf - } catch (e: Throwable) { - RustBuffer.free(rbuf) - throw e } - } // Lift a value from a `RustBuffer`. // diff --git a/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt b/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt index 3a56648190..844986bf5b 100644 --- a/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt +++ b/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt @@ -24,4 +24,6 @@ internal class UniffiHandleMap { fun remove(handle: Long): T { return map.remove(handle) ?: throw InternalException("UniffiHandleMap: Invalid handle") } + + fun has(handle: Long): Boolean = map.contains(handle) } diff --git a/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt b/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt index 6e640c03a3..8bba74bf69 100644 --- a/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt +++ b/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt @@ -126,6 +126,14 @@ open class {{ impl_class_name }}: Disposable, AutoCloseable, {{ interface_name } this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) } + constructor(rbuf: RustBuffer) : this( + rbuf.asByteBuffer()!!.let { buf -> + val pointer = buf.getLong() + buf.getInt() + Pointer(pointer) + } + ) + /** * This constructor can be used to instantiate a fake object. Only used for tests. Any * attempt to actually use an object constructed this way will fail as there is no @@ -171,7 +179,11 @@ open class {{ impl_class_name }}: Disposable, AutoCloseable, {{ interface_name } this.destroy() } + {% if obj.has_callback_interface() -%} + internal inline fun callWithPointer(block: (ptr: RustBuffer.ByValue) -> R): R { + {%- else %} internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + {%- endif %} // Check and increment the call counter, to keep the object alive. // This needs a compare-and-set retry loop in case of concurrent updates. do { @@ -185,7 +197,11 @@ open class {{ impl_class_name }}: Disposable, AutoCloseable, {{ interface_name } } while (! this.callCounter.compareAndSet(c, c + 1L)) // Now we can safely do the method call without the pointer being freed concurrently. try { + {% if obj.has_callback_interface() -%} + return block({{ ffi_converter_name }}.lowerPointer(this.uniffiClonePointer())) + {%- else %} return block(this.uniffiClonePointer()) + {%- endif %} } finally { // This decrement always matches the increment we performed above. if (this.callCounter.decrementAndGet() == 0L) { @@ -267,20 +283,52 @@ open class {{ impl_class_name }}: Disposable, AutoCloseable, {{ interface_name } {% include "CallbackInterfaceImpl.kt" %} {%- endif %} +{%- let trait_impl=format!("uniffiCallbackInterface{}", name) %} + +{%- if obj.has_callback_interface() %} /** * @suppress */ -public object {{ ffi_converter_name }}: FfiConverter<{{ type_name }}, Pointer> { - {%- if obj.has_callback_interface() %} +public object {{ ffi_converter_name }}: FfiConverterRustBuffer<{{ type_name }}> { internal val handleMap = UniffiHandleMap<{{ type_name }}>() - {%- endif %} + internal val langIndex: Int = {{ trait_impl }}.register(UniffiLib.INSTANCE) + + override fun read(buf: ByteBuffer): {{ type_name }} { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + val handle = buf.getLong() + val langIndex = buf.getInt() + if (handleMap.has(handle)) { + return handleMap.get(handle) + } else { + return {{ impl_class_name }}(Pointer(handle)) + } + } + + override fun allocationSize(value: {{ type_name }}) = 12UL + fun lowerPointer(pointer: Pointer): RustBuffer.ByValue = + RustBuffer.write(12UL) { bbuf -> + bbuf.putLong(Pointer.nativeValue(pointer)) + bbuf.putInt(langIndex) + } + + override fun write(value: {{ type_name }}, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + val handle = handleMap.insert(value) + buf.putLong(handle) + buf.putInt(this.langIndex) + } +} + +{%- else %} +/** + * @suppress + */ +public object {{ ffi_converter_name }}: FfiConverter<{{ type_name }}, Pointer> { override fun lower(value: {{ type_name }}): Pointer { - {%- if obj.has_callback_interface() %} - return Pointer(handleMap.insert(value)) - {%- else %} return value.uniffiClonePointer() - {%- endif %} } override fun lift(value: Pointer): {{ type_name }} { @@ -301,3 +349,5 @@ public object {{ ffi_converter_name }}: FfiConverter<{{ type_name }}, Pointer> { buf.putLong(Pointer.nativeValue(lower(value))) } } + +{%- endif %} diff --git a/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt b/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt index c12c386d7c..be54316d13 100644 --- a/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt +++ b/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt @@ -43,6 +43,21 @@ open class RustBuffer : Structure() { internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> UniffiLib.INSTANCE.{{ ci.ffi_rustbuffer_free().name() }}(buf, status) } + + fun write(size: ULong, writer: (ByteBuffer) -> Unit): RustBuffer.ByValue { + val rbuf = RustBuffer.alloc(size) + try { + val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity).also { + it.order(ByteOrder.BIG_ENDIAN) + } + writer(bbuf) + rbuf.writeField("len", bbuf.position().toLong()) + return rbuf + } catch (e: Throwable) { + RustBuffer.free(rbuf) + throw e + } + } } @Suppress("TooGenericExceptionThrown") diff --git a/uniffi_bindgen/src/interface/ffi.rs b/uniffi_bindgen/src/interface/ffi.rs index ab2e8eb6bd..be01c2ce78 100644 --- a/uniffi_bindgen/src/interface/ffi.rs +++ b/uniffi_bindgen/src/interface/ffi.rs @@ -119,10 +119,11 @@ impl From<&Type> for FfiType { // Byte strings are also always owned rust values. // We might add a separate type for borrowed byte strings in future as well. Type::Bytes => FfiType::RustBuffer(None), + Type::Object { imp, .. } if imp.has_callback_interface() => FfiType::RustBuffer(None), // Objects are pointers to an Arc<> Type::Object { name, .. } => FfiType::RustArcPtr(name.to_owned()), // Callback interfaces are passed as opaque integer handles. - Type::CallbackInterface { .. } => FfiType::UInt64, + Type::CallbackInterface { .. } => FfiType::RustBuffer(None), // Other types are serialized into a bytebuffer and deserialized on the other side. Type::Enum { .. } | Type::Record { .. } @@ -221,7 +222,7 @@ impl FfiFunction { name: "vtable".to_string(), type_: FfiType::Struct(vtable_name).reference(), }], - return_type: None, + return_type: Some(FfiType::Int32), has_rust_call_status_arg: false, ..Self::default() } diff --git a/uniffi_core/src/ffi/foreigncallbacks.rs b/uniffi_core/src/ffi/foreigncallbacks.rs index 326ff12747..18ec56f2dc 100644 --- a/uniffi_core/src/ffi/foreigncallbacks.rs +++ b/uniffi_core/src/ffi/foreigncallbacks.rs @@ -8,29 +8,38 @@ //! code loads the exported library. For each callback type, we also define a "cell" type for //! storing the callback. -use std::{ - ptr::{null_mut, NonNull}, - sync::atomic::{AtomicPtr, Ordering}, -}; +use std::{ptr::NonNull, sync::Mutex}; // Cell type that stores any NonNull #[doc(hidden)] -pub struct UniffiForeignPointerCell(AtomicPtr); +pub struct UniffiForeignPointerCell { + pointers: Mutex>, +} impl UniffiForeignPointerCell { pub const fn new() -> Self { - Self(AtomicPtr::new(null_mut())) + Self { + pointers: Mutex::new(Vec::new()), + } } - pub fn set(&self, callback: NonNull) { - self.0.store(callback.as_ptr(), Ordering::Relaxed); + pub fn set(&self, callback: NonNull) -> usize { + let mut pointers = self.pointers.lock().unwrap(); + let index = pointers.len(); + pointers.push(callback.as_ptr()); + index } - pub fn get(&self) -> &T { + pub fn get(&self, index: usize) -> &T { + let pointers = self.pointers.lock().unwrap(); + if index >= pointers.len() { + panic!("Foreign pointer used before being set. This is likely a uniffi bug.") + } unsafe { - NonNull::new(self.0.load(Ordering::Relaxed)) - .expect("Foreign pointer not set. This is likely a uniffi bug.") - .as_mut() + let ptr = pointers[index]; + NonNull::new(ptr) + .expect("Foreign pointer not set. This is likely a uniffi bug.") + .as_ref() } } } diff --git a/uniffi_macros/src/export/callback_interface.rs b/uniffi_macros/src/export/callback_interface.rs index 23009712e1..935a5a3aca 100644 --- a/uniffi_macros/src/export/callback_interface.rs +++ b/uniffi_macros/src/export/callback_interface.rs @@ -88,18 +88,19 @@ pub(super) fn trait_impl( static #vtable_cell: ::uniffi::UniffiForeignPointerCell::<#vtable_type> = ::uniffi::UniffiForeignPointerCell::<#vtable_type>::new(); #[no_mangle] - extern "C" fn #init_ident(vtable: ::std::ptr::NonNull<#vtable_type>) { - #vtable_cell.set(vtable); + extern "C" fn #init_ident(vtable: ::std::ptr::NonNull<#vtable_type>) -> i32 { + #vtable_cell.set(vtable) as i32 } #[derive(Debug)] struct #trait_impl_ident { handle: u64, + lang_index: usize, } impl #trait_impl_ident { - fn new(handle: u64) -> Self { - Self { handle } + fn new(handle: u64, lang_index: usize) -> Self { + Self { handle, lang_index } } } @@ -112,7 +113,7 @@ pub(super) fn trait_impl( impl ::std::ops::Drop for #trait_impl_ident { fn drop(&mut self) { - let vtable = #vtable_cell.get(); + let vtable = #vtable_cell.get(self.lang_index); (vtable.uniffi_free)(self.handle); } } @@ -141,22 +142,23 @@ 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 }); - + let try_lift = ffiops::try_lift_from_rust_buffer(quote! { Self }); quote! { #[doc(hidden)] #[automatically_derived] unsafe #lift_impl_spec { - type FfiType = u64; - - fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result { - ::std::result::Result::Ok(::std::boxed::Box::new(<#trait_impl_ident>::new(v))) - } + type FfiType = ::uniffi::rustbuffer::RustBuffer; fn try_read(buf: &mut &[u8]) -> ::uniffi::deps::anyhow::Result { use ::uniffi::deps::bytes::Buf; - ::uniffi::check_remaining(buf, 8)?; - #try_lift_self(buf.get_u64()) + ::uniffi::check_remaining(buf, 12)?; + let handle = buf.get_u64(); + let lang_index = ::std::convert::TryFrom::try_from(buf.get_i32())?; + ::std::result::Result::Ok(::std::boxed::Box::new(<#trait_impl_ident>::new(handle, lang_index))) + } + + fn try_lift(buf: Self::FfiType) -> ::uniffi::deps::anyhow::Result { + #try_lift(buf) } } @@ -221,7 +223,7 @@ fn gen_method_impl(sig: &FnSignature, vtable_cell: &Ident) -> syn::Result #return_ty { - let vtable = #vtable_cell.get(); + let vtable = #vtable_cell.get(self.lang_index); let mut uniffi_call_status: ::uniffi::RustCallStatus = ::std::default::Default::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); @@ -231,7 +233,7 @@ fn gen_method_impl(sig: &FnSignature, vtable_cell: &Ident) -> syn::Result #return_ty { - let vtable = #vtable_cell.get(); + let vtable = #vtable_cell.get(self.lang_index); ::uniffi::foreign_async_call::<_, #return_ty, crate::UniFfiTag>(move |uniffi_future_callback, uniffi_future_callback_data| { let mut uniffi_foreign_future: ::uniffi::ForeignFuture = ::uniffi::FfiDefault::ffi_default(); (vtable.#ident)(self.handle, #(#lower_exprs,)* uniffi_future_callback, uniffi_future_callback_data, &mut uniffi_foreign_future); diff --git a/uniffi_macros/src/export/scaffolding.rs b/uniffi_macros/src/export/scaffolding.rs index e352559bc5..22cbc12998 100644 --- a/uniffi_macros/src/export/scaffolding.rs +++ b/uniffi_macros/src/export/scaffolding.rs @@ -136,8 +136,11 @@ impl ScaffoldingBits { } else { quote! { ::std::sync::Arc<#self_ident> } }; - let lift_type = ffiops::lift_type(&self_type); - let try_lift = ffiops::try_lift(&self_type); + let lift_type = if is_trait { + quote! { *const ::std::os::raw::c_void } + } else { + ffiops::lift_type(&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 @@ -154,6 +157,7 @@ impl ScaffoldingBits { } } } else { + let try_lift = ffiops::try_lift(&self_type); quote! { #try_lift(uniffi_self_lowered) } }; diff --git a/uniffi_macros/src/export/trait_interface.rs b/uniffi_macros/src/export/trait_interface.rs index 18d01a5d38..eec571cefa 100644 --- a/uniffi_macros/src/export/trait_interface.rs +++ b/uniffi_macros/src/export/trait_interface.rs @@ -127,71 +127,105 @@ pub(crate) fn ffi_converter( let impl_spec = tagged_impl_header("FfiConverterArc", "e! { dyn #trait_ident }, udl_mode); let lift_ref_impl_spec = tagged_impl_header("LiftRef", "e! { dyn #trait_ident }, udl_mode); let trait_name = ident_to_string(trait_ident); - let try_lift = if with_foreign { + + if with_foreign { let trait_impl_ident = callback_interface::trait_impl_ident(&trait_name); + let try_lift = ffiops::try_lift_from_rust_buffer(quote! { ::std::sync::Arc }); + let lower = ffiops::lower_into_rust_buffer(quote! { ::std::sync::Arc }); quote! { - fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<::std::sync::Arc> { - ::std::result::Result::Ok(::std::sync::Arc::new(<#trait_impl_ident>::new(v as u64))) + // All traits must be `Sync + Send`. The generated scaffolding will fail to compile + // 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!( + dyn #trait_ident: ::core::marker::Sync, ::core::marker::Send + ); + + unsafe #impl_spec { + type FfiType = ::uniffi::rustbuffer::RustBuffer; + + fn lower(obj: ::std::sync::Arc) -> Self::FfiType { + #lower(obj) + } + + fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<::std::sync::Arc> { + #try_lift(v) + } + + fn write(obj: ::std::sync::Arc, buf: &mut ::std::vec::Vec) { + ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); + let handle = ::std::boxed::Box::into_raw(::std::boxed::Box::new(obj)) as *const ::std::os::raw::c_void; + let lang_index = -1; // no value + ::uniffi::deps::bytes::BufMut::put_u64(buf, handle as ::std::primitive::u64); + ::uniffi::deps::bytes::BufMut::put_i32(buf, lang_index); + } + + fn try_read(buf: &mut &[u8]) -> ::uniffi::Result<::std::sync::Arc> { + use ::uniffi::deps::bytes::Buf; + ::uniffi::check_remaining(buf, 12)?; + let handle = buf.get_u64(); + let lang_index = buf.get_i32() as ::std::primitive::usize; + ::std::result::Result::Ok(::std::sync::Arc::new(<#trait_impl_ident>::new(handle, lang_index))) + } + + const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_CALLBACK_TRAIT_INTERFACE) + .concat_str(#mod_path) + .concat_str(#trait_name); + } + + unsafe #lift_ref_impl_spec { + type LiftType = ::std::sync::Arc; } } } else { + let lower_self = ffiops::lower(quote! { ::std::sync::Arc }); + let try_lift_self = ffiops::try_lift(quote! { ::std::sync::Arc }); quote! { - fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<::std::sync::Arc> { - unsafe { - ::std::result::Result::Ok( - *::std::boxed::Box::from_raw(v as *mut ::std::sync::Arc), - ) + // All traits must be `Sync + Send`. The generated scaffolding will fail to compile + // 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!( + dyn #trait_ident: ::core::marker::Sync, ::core::marker::Send + ); + + unsafe #impl_spec { + type FfiType = *const ::std::os::raw::c_void; + + fn lower(obj: ::std::sync::Arc) -> Self::FfiType { + ::std::boxed::Box::into_raw(::std::boxed::Box::new(obj)) as *const ::std::os::raw::c_void } - } - } - }; - let metadata_code = if with_foreign { - quote! { ::uniffi::metadata::codes::TYPE_CALLBACK_TRAIT_INTERFACE } - } else { - quote! { ::uniffi::metadata::codes::TYPE_TRAIT_INTERFACE } - }; - let lower_self = ffiops::lower(quote! { ::std::sync::Arc }); - let try_lift_self = ffiops::try_lift(quote! { ::std::sync::Arc }); - - quote! { - // All traits must be `Sync + Send`. The generated scaffolding will fail to compile - // 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!( - dyn #trait_ident: ::core::marker::Sync, ::core::marker::Send - ); - - unsafe #impl_spec { - type FfiType = *const ::std::os::raw::c_void; - - fn lower(obj: ::std::sync::Arc) -> Self::FfiType { - ::std::boxed::Box::into_raw(::std::boxed::Box::new(obj)) as *const ::std::os::raw::c_void - } - #try_lift + fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<::std::sync::Arc> { + unsafe { + ::std::result::Result::Ok( + *::std::boxed::Box::from_raw(v as *mut ::std::sync::Arc), + ) + } + } - fn write(obj: ::std::sync::Arc, buf: &mut ::std::vec::Vec) { - ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); - ::uniffi::deps::bytes::BufMut::put_u64( - buf, - #lower_self(obj) as ::std::primitive::u64, - ); - } + fn write(obj: ::std::sync::Arc, buf: &mut ::std::vec::Vec) { + ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); + ::uniffi::deps::bytes::BufMut::put_u64( + buf, + #lower_self(obj) as ::std::primitive::u64, + ); + } - fn try_read(buf: &mut &[u8]) -> ::uniffi::Result<::std::sync::Arc> { - ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); - ::uniffi::check_remaining(buf, 8)?; - #try_lift_self(::uniffi::deps::bytes::Buf::get_u64(buf) as Self::FfiType) - } + fn try_read(buf: &mut &[u8]) -> ::uniffi::Result<::std::sync::Arc> { + ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); + ::uniffi::check_remaining(buf, 8)?; + #try_lift_self(::uniffi::deps::bytes::Buf::get_u64(buf) as Self::FfiType) + } - const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(#metadata_code) - .concat_str(#mod_path) - .concat_str(#trait_name); - } + const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_TRAIT_INTERFACE) + .concat_str(#mod_path) + .concat_str(#trait_name); + } - unsafe #lift_ref_impl_spec { - type LiftType = ::std::sync::Arc; + unsafe #lift_ref_impl_spec { + type LiftType = ::std::sync::Arc; + } } } }