Skip to content

Commit

Permalink
Merge pull request #1952 from bendk/metadata-ffi-trait
Browse files Browse the repository at this point in the history
Adding the `TypeId` FFI trait
  • Loading branch information
bendk authored Apr 26, 2024
2 parents cd489d4 + 06df57c commit 0f95c82
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 168 deletions.
4 changes: 2 additions & 2 deletions fixtures/metadata/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ mod test_type_ids {
use super::*;
use std::collections::HashMap;
use std::sync::Arc;
use uniffi_core::Lower;
use uniffi_core::TypeId;

fn check_type_id<T: Lower<UniFfiTag>>(correct_type: Type) {
fn check_type_id<T: TypeId<UniFfiTag>>(correct_type: Type) {
let buf = &mut T::TYPE_ID_META.as_ref();
assert_eq!(
uniffi_meta::read_metadata_type(buf).unwrap(),
Expand Down
36 changes: 0 additions & 36 deletions fixtures/uitests/tests/ui/invalid_types_in_signatures.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,6 @@ error[E0277]: the trait bound `Result<(), ErrorType>: Lift<UniFfiTag>` is not sa
and $N others
= note: this error originates in the attribute macro `uniffi::export` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Result<(), ErrorType>: Lift<UniFfiTag>` is not satisfied
--> tests/ui/invalid_types_in_signatures.rs:18:25
|
18 | pub fn input_result(_r: Result<(), ErrorType>) { }
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Lift<UniFfiTag>` is not implemented for `Result<(), ErrorType>`
|
= help: the following other types implement trait `Lift<UT>`:
bool
i8
i16
i32
i64
u8
u16
u32
and $N others

error[E0277]: the trait bound `Result<(), ErrorType>: Lower<UniFfiTag>` is not satisfied
--> tests/ui/invalid_types_in_signatures.rs:20:1
|
Expand All @@ -52,22 +35,3 @@ error[E0277]: the trait bound `Result<(), ErrorType>: Lower<UniFfiTag>` is not s
= note: required for `Option<Result<(), ErrorType>>` to implement `Lower<UniFfiTag>`
= note: required for `Option<Result<(), ErrorType>>` to implement `LowerReturn<UniFfiTag>`
= note: this error originates in the attribute macro `uniffi::export` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Result<(), ErrorType>: Lower<UniFfiTag>` is not satisfied
--> tests/ui/invalid_types_in_signatures.rs:21:34
|
21 | pub fn return_option_result() -> Option<Result<(), ErrorType>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Lower<UniFfiTag>` is not implemented for `Result<(), ErrorType>`, which is required by `Option<Result<(), ErrorType>>: LowerReturn<UniFfiTag>`
|
= help: the following other types implement trait `Lower<UT>`:
bool
i8
i16
i32
i64
u8
u16
u32
and $N others
= note: required for `Option<Result<(), ErrorType>>` to implement `Lower<UniFfiTag>`
= note: required for `Option<Result<(), ErrorType>>` to implement `LowerReturn<UniFfiTag>`
13 changes: 6 additions & 7 deletions uniffi/tests/ui/proc_macro_arc.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ error[E0277]: the trait bound `Foo: FfiConverterArc<UniFfiTag>` is not satisfied
--> tests/ui/proc_macro_arc.rs:11:18
|
11 | fn make_foo() -> Arc<Foo> {
| ^^^^^^^^ the trait `FfiConverterArc<UniFfiTag>` is not implemented for `Foo`, which is required by `Arc<Foo>: LowerReturn<UniFfiTag>`
| ^^^^^^^^ the trait `FfiConverterArc<UniFfiTag>` is not implemented for `Foo`, which is required by `Arc<Foo>: uniffi::TypeId<UniFfiTag>`
|
= help: the trait `LowerReturn<UT>` is implemented for `Arc<T>`
= help: the trait `uniffi::TypeId<UT>` is implemented for `Arc<T>`
= note: required for `Arc<Foo>` to implement `FfiConverter<UniFfiTag>`
= note: required for `Arc<Foo>` to implement `Lower<UniFfiTag>`
= note: required for `Arc<Foo>` to implement `LowerReturn<UniFfiTag>`
= note: required for `Arc<Foo>` to implement `uniffi::TypeId<UniFfiTag>`

error[E0277]: the trait bound `child::Foo: FfiConverterArc<UniFfiTag>` is not satisfied
--> tests/ui/proc_macro_arc.rs:20:5
Expand All @@ -36,8 +35,8 @@ error[E0277]: the trait bound `child::Foo: FfiConverterArc<UniFfiTag>` is not sa
--> tests/ui/proc_macro_arc.rs:21:22
|
21 | fn take_foo(foo: Arc<Foo>) {
| ^^^^^^^^ the trait `FfiConverterArc<UniFfiTag>` is not implemented for `child::Foo`, which is required by `Arc<child::Foo>: Lift<UniFfiTag>`
| ^^^^^^^^ the trait `FfiConverterArc<UniFfiTag>` is not implemented for `child::Foo`, which is required by `Arc<child::Foo>: uniffi::TypeId<UniFfiTag>`
|
= help: the trait `Lift<UT>` is implemented for `Arc<T>`
= help: the trait `uniffi::TypeId<UT>` is implemented for `Arc<T>`
= note: required for `Arc<child::Foo>` to implement `FfiConverter<UniFfiTag>`
= note: required for `Arc<child::Foo>` to implement `Lift<UniFfiTag>`
= note: required for `Arc<child::Foo>` to implement `uniffi::TypeId<UniFfiTag>`
37 changes: 20 additions & 17 deletions uniffi_core/src/ffi_converter_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
use crate::{
check_remaining, derive_ffi_traits, ffi_converter_rust_buffer_lift_and_lower, metadata,
ConvertError, FfiConverter, Lift, LiftRef, LiftReturn, Lower, LowerReturn, MetadataBuffer,
Result, RustBuffer, UnexpectedUniFFICallbackError,
Result, RustBuffer, TypeId, UnexpectedUniFFICallbackError,
};
use anyhow::bail;
use bytes::buf::{Buf, BufMut};
Expand Down Expand Up @@ -270,9 +270,6 @@ unsafe impl<UT, T: Lower<UT>> Lower<UT> for Option<T> {
fn lower(obj: Option<T>) -> RustBuffer {
Self::lower_into_rust_buffer(obj)
}

const TYPE_ID_META: MetadataBuffer =
MetadataBuffer::from_code(metadata::codes::TYPE_OPTION).concat(T::TYPE_ID_META);
}

unsafe impl<UT, T: Lift<UT>> Lift<UT> for Option<T> {
Expand All @@ -290,7 +287,9 @@ unsafe impl<UT, T: Lift<UT>> Lift<UT> for Option<T> {
fn try_lift(buf: RustBuffer) -> Result<Option<T>> {
Self::try_lift_from_rust_buffer(buf)
}
}

impl<UT, T: TypeId<UT>> TypeId<UT> for Option<T> {
const TYPE_ID_META: MetadataBuffer =
MetadataBuffer::from_code(metadata::codes::TYPE_OPTION).concat(T::TYPE_ID_META);
}
Expand Down Expand Up @@ -320,9 +319,6 @@ unsafe impl<UT, T: Lower<UT>> Lower<UT> for Vec<T> {
fn lower(obj: Vec<T>) -> RustBuffer {
Self::lower_into_rust_buffer(obj)
}

const TYPE_ID_META: MetadataBuffer =
MetadataBuffer::from_code(metadata::codes::TYPE_VEC).concat(T::TYPE_ID_META);
}

/// Support for associative arrays via the FFI - `record<u32, u64>` in UDL.
Expand All @@ -346,7 +342,9 @@ unsafe impl<UT, T: Lift<UT>> Lift<UT> for Vec<T> {
fn try_lift(buf: RustBuffer) -> Result<Vec<T>> {
Self::try_lift_from_rust_buffer(buf)
}
}

impl<UT, T: TypeId<UT>> TypeId<UT> for Vec<T> {
const TYPE_ID_META: MetadataBuffer =
MetadataBuffer::from_code(metadata::codes::TYPE_VEC).concat(T::TYPE_ID_META);
}
Expand All @@ -371,10 +369,6 @@ where
fn lower(obj: HashMap<K, V>) -> RustBuffer {
Self::lower_into_rust_buffer(obj)
}

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_HASH_MAP)
.concat(K::TYPE_ID_META)
.concat(V::TYPE_ID_META);
}

unsafe impl<K, V, UT> Lift<UT> for HashMap<K, V>
Expand All @@ -399,7 +393,13 @@ where
fn try_lift(buf: RustBuffer) -> Result<HashMap<K, V>> {
Self::try_lift_from_rust_buffer(buf)
}
}

impl<K, V, UT> TypeId<UT> for HashMap<K, V>
where
K: TypeId<UT> + std::hash::Hash + Eq,
V: TypeId<UT>,
{
const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_HASH_MAP)
.concat(K::TYPE_ID_META)
.concat(V::TYPE_ID_META);
Expand Down Expand Up @@ -442,6 +442,7 @@ derive_ffi_traits!(impl<T, UT> Lift<UT> for Arc<T> where Arc<T>: FfiConverter<UT
derive_ffi_traits!(impl<T, UT> LowerReturn<UT> for Arc<T> where Arc<T>: Lower<UT>, T: ?Sized);
derive_ffi_traits!(impl<T, UT> LiftReturn<UT> for Arc<T> where Arc<T>: Lift<UT>, T: ?Sized);
derive_ffi_traits!(impl<T, UT> LiftRef<UT> for Arc<T> where Arc<T>: Lift<UT>, T: ?Sized);
derive_ffi_traits!(impl<T, UT> TypeId<UT> for Arc<T> where Arc<T>: FfiConverter<UT>, T: ?Sized);

// Implement LowerReturn/LiftReturn for the unit type (void returns)

Expand All @@ -451,8 +452,6 @@ unsafe impl<UT> LowerReturn<UT> for () {
fn lower_return(_: ()) -> Result<Self::ReturnType, RustBuffer> {
Ok(())
}

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_UNIT);
}

unsafe impl<UT> LiftReturn<UT> for () {
Expand All @@ -461,7 +460,9 @@ unsafe impl<UT> LiftReturn<UT> for () {
fn try_lift_successful_return(_: ()) -> Result<Self> {
Ok(())
}
}

impl<UT> TypeId<UT> for () {
const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_UNIT);
}

Expand All @@ -488,10 +489,6 @@ where
Err(ohno) => panic!("Failed to convert arg '{arg_name}': {ohno}"),
}
}

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_RESULT)
.concat(R::TYPE_ID_META)
.concat(E::TYPE_ID_META);
}

unsafe impl<UT, R, E> LiftReturn<UT> for Result<R, E>
Expand Down Expand Up @@ -519,7 +516,13 @@ where
fn handle_callback_unexpected_error(e: UnexpectedUniFFICallbackError) -> Self {
Err(E::try_convert_unexpected_callback_error(e).unwrap_or_else(|e| panic!("{e}")))
}
}

impl<UT, R, E> TypeId<UT> for Result<R, E>
where
R: TypeId<UT>,
E: TypeId<UT>,
{
const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_RESULT)
.concat(R::TYPE_ID_META)
.concat(E::TYPE_ID_META);
Expand Down
43 changes: 23 additions & 20 deletions uniffi_core/src/ffi_converter_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! proc-macro generated code. The goal is to allow the proc-macros to go from a type name to the
//! correct function for a given FFI operation.
//!
//! The traits form a sort-of tree structure from general to specific:
//! The main traits form a sort-of tree structure from general to specific:
//! ```ignore
//!
//! [FfiConverter]
Expand All @@ -23,6 +23,10 @@
//! [LowerReturn] [LiftRef] [LiftReturn]
//! ```
//!
//! There's also:
//! - [TypeId], which is implemented for all types that implement any of the above traits.
//! - [ConvertError], which is implement for errors that can be used in callback interfaces.
//!
//! The `derive_ffi_traits` macro can be used to derive the specific traits from the general ones.
//! Here's the main ways we implement these traits:
//!
Expand All @@ -39,7 +43,7 @@
//!
//! ## Safety
//!
//! All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
//! Most traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
//! that it's safe to pass your type out to foreign-language code and back again. Buggy
//! implementations of this trait might violate some assumptions made by the generated code,
//! or might not match with the corresponding code in the generated foreign-language bindings.
Expand Down Expand Up @@ -128,8 +132,6 @@ pub unsafe trait FfiConverter<UT>: Sized {
fn try_read(buf: &mut &[u8]) -> Result<Self>;

/// Type ID metadata, serialized into a [MetadataBuffer].
///
/// If a type implements multiple FFI traits, `TYPE_ID_META` must be the same for all of them.
const TYPE_ID_META: MetadataBuffer;
}

Expand Down Expand Up @@ -217,8 +219,6 @@ pub unsafe trait Lift<UT>: Sized {
n => bail!("junk data left in buffer after lifting (count: {n})",),
}
}

const TYPE_ID_META: MetadataBuffer;
}

/// Lower Rust values to pass them to the foreign code
Expand Down Expand Up @@ -249,8 +249,6 @@ pub unsafe trait Lower<UT>: Sized {
Self::write(obj, &mut buf);
RustBuffer::from_vec(buf)
}

const TYPE_ID_META: MetadataBuffer;
}

/// Return Rust values to the foreign code
Expand Down Expand Up @@ -288,8 +286,6 @@ pub unsafe trait LowerReturn<UT>: Sized {
fn handle_failed_lift(arg_name: &str, e: anyhow::Error) -> Self {
panic!("Failed to convert arg '{arg_name}': {e}")
}

const TYPE_ID_META: MetadataBuffer;
}

/// Return foreign values to Rust
Expand Down Expand Up @@ -355,8 +351,6 @@ pub unsafe trait LiftReturn<UT>: Sized {
fn handle_callback_unexpected_error(e: UnexpectedUniFFICallbackError) -> Self {
panic!("Callback interface failure: {e}")
}

const TYPE_ID_META: MetadataBuffer;
}

/// Lift references
Expand All @@ -377,6 +371,14 @@ pub unsafe trait LiftRef<UT> {
type LiftType: Lift<UT> + Borrow<Self>;
}

/// Type ID metadata
///
/// This is used to build up more complex metadata. For example, the `MetadataBuffer` for function
/// signatures includes a copy of this metadata for each argument and return type.
pub trait TypeId<UT> {
const TYPE_ID_META: MetadataBuffer;
}

pub trait ConvertError<UT>: Sized {
fn try_convert_unexpected_callback_error(e: UnexpectedUniFFICallbackError) -> Result<Self>;
}
Expand Down Expand Up @@ -468,6 +470,7 @@ macro_rules! derive_ffi_traits {
$crate::derive_ffi_traits!(impl<UT> LiftReturn<UT> for $ty);
$crate::derive_ffi_traits!(impl<UT> LiftRef<UT> for $ty);
$crate::derive_ffi_traits!(impl<UT> ConvertError<UT> for $ty);
$crate::derive_ffi_traits!(impl<UT> TypeId<UT> for $ty);
};

(local $ty:ty) => {
Expand All @@ -477,6 +480,7 @@ macro_rules! derive_ffi_traits {
$crate::derive_ffi_traits!(impl LiftReturn<crate::UniFfiTag> for $ty);
$crate::derive_ffi_traits!(impl LiftRef<crate::UniFfiTag> for $ty);
$crate::derive_ffi_traits!(impl ConvertError<crate::UniFfiTag> for $ty);
$crate::derive_ffi_traits!(impl TypeId<crate::UniFfiTag> for $ty);
};

(impl $(<$($generic:ident),*>)? $(::uniffi::)? Lower<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
Expand All @@ -491,8 +495,6 @@ macro_rules! derive_ffi_traits {
fn write(obj: Self, buf: &mut ::std::vec::Vec<u8>) {
<Self as $crate::FfiConverter<$ut>>::write(obj, buf)
}

const TYPE_ID_META: $crate::MetadataBuffer = <Self as $crate::FfiConverter<$ut>>::TYPE_ID_META;
}
};

Expand All @@ -508,8 +510,6 @@ macro_rules! derive_ffi_traits {
fn try_read(buf: &mut &[u8]) -> $crate::deps::anyhow::Result<Self> {
<Self as $crate::FfiConverter<$ut>>::try_read(buf)
}

const TYPE_ID_META: $crate::MetadataBuffer = <Self as $crate::FfiConverter<$ut>>::TYPE_ID_META;
}
};

Expand All @@ -521,8 +521,6 @@ macro_rules! derive_ffi_traits {
fn lower_return(obj: Self) -> $crate::deps::anyhow::Result<Self::ReturnType, $crate::RustBuffer> {
Ok(<Self as $crate::Lower<$ut>>::lower(obj))
}

const TYPE_ID_META: $crate::MetadataBuffer =<Self as $crate::Lower<$ut>>::TYPE_ID_META;
}
};

Expand All @@ -534,8 +532,6 @@ macro_rules! derive_ffi_traits {
fn try_lift_successful_return(v: Self::ReturnType) -> $crate::Result<Self> {
<Self as $crate::Lift<$ut>>::try_lift(v)
}

const TYPE_ID_META: $crate::MetadataBuffer = <Self as $crate::Lift<$ut>>::TYPE_ID_META;
}
};

Expand Down Expand Up @@ -585,6 +581,13 @@ macro_rules! derive_ffi_traits {
}
}
};

(impl $(<$($generic:ident),*>)? $(::uniffi::)? TypeId<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
impl $(<$($generic),*>)* $crate::TypeId<$ut> for $ty $(where $($where)*)*
{
const TYPE_ID_META: $crate::MetadataBuffer = <Self as $crate::FfiConverter<$ut>>::TYPE_ID_META;
}
};
}

unsafe impl<T: Send + Sync, UT> HandleAlloc<UT> for T {
Expand Down
2 changes: 1 addition & 1 deletion uniffi_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub mod metadata;
pub use ffi::*;
pub use ffi_converter_traits::{
ConvertError, FfiConverter, FfiConverterArc, HandleAlloc, Lift, LiftRef, LiftReturn, Lower,
LowerReturn,
LowerReturn, TypeId,
};
pub use metadata::*;

Expand Down
2 changes: 1 addition & 1 deletion uniffi_macros/src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub(crate) fn expand_ffi_converter_custom_type(
const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_CUSTOM)
.concat_str(#mod_path)
.concat_str(#name)
.concat(<#builtin as ::uniffi::Lower<crate::UniFfiTag>>::TYPE_ID_META);
.concat(<#builtin as ::uniffi::TypeId<crate::UniFfiTag>>::TYPE_ID_META);
}

#derive_ffi_traits
Expand Down
Loading

0 comments on commit 0f95c82

Please sign in to comment.