Trait uniffi::FfiConverter

pub unsafe trait FfiConverter<UT>: Sized {
    type FfiType: FfiDefault;

    const TYPE_ID_META: MetadataBuffer;

    // Required methods
    fn lower(obj: Self) -> Self::FfiType;
    fn try_lift(v: Self::FfiType) -> Result<Self, Error>;
    fn write(obj: Self, buf: &mut Vec<u8, Global>);
    fn try_read(buf: &mut &[u8]) -> Result<Self, Error>;
}
Expand description

Generalized FFI conversions

This trait is not used directly by the code generation, but implement this and calling [derive_ffi_traits] is a simple way to implement all the traits that are.

Safety

All 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. These traits should not be used directly, only in generated code, and the generated code should have fixture tests to test that everything works correctly together.

Required Associated Types§

type FfiType: FfiDefault

The low-level type used for passing values of this type over the FFI.

This must be a C-compatible type (e.g. a numeric primitive, a #[repr(C)] struct) into which values of the target rust type can be converted.

For complex data types, we currently recommend using RustBuffer and serializing the data for transfer. In theory it could be possible to build a matching #[repr(C)] struct for a complex data type and pass that instead, but explicit serialization is simpler and safer as a starting point.

If a type implements multiple FFI traits, FfiType must be the same for all of them.

Required Associated Constants§

const TYPE_ID_META: MetadataBuffer

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.

Required Methods§

fn lower(obj: Self) -> Self::FfiType

Lower a rust value of the target type, into an FFI value of type Self::FfiType.

This trait method is used for sending data from rust to the foreign language code, by (hopefully cheaply!) converting it into something that can be passed over the FFI and reconstructed on the other side.

Note that this method takes an owned value; this allows it to transfer ownership in turn to the foreign language code, e.g. by boxing the value and passing a pointer.

fn try_lift(v: Self::FfiType) -> Result<Self, Error>

Lift a rust value of the target type, from an FFI value of type Self::FfiType.

This trait method is used for receiving data from the foreign language code in rust, by (hopefully cheaply!) converting it from a low-level FFI value of type Self::FfiType into a high-level rust value of the target type.

Since we cannot statically guarantee that the foreign-language code will send valid values of type Self::FfiType, this method is fallible.

fn write(obj: Self, buf: &mut Vec<u8, Global>)

Write a rust value into a buffer, to send over the FFI in serialized form.

This trait method can be used for sending data from rust to the foreign language code, in cases where we’re not able to use a special-purpose FFI type and must fall back to sending serialized bytes.

Note that this method takes an owned value because it’s transferring ownership to the foreign language code via the RustBuffer.

fn try_read(buf: &mut &[u8]) -> Result<Self, Error>

Read a rust value from a buffer, received over the FFI in serialized form.

This trait method can be used for receiving data from the foreign language code in rust, in cases where we’re not able to use a special-purpose FFI type and must fall back to receiving serialized bytes.

Since we cannot statically guarantee that the foreign-language code will send valid serialized bytes for the target type, this method is fallible.

Note the slightly unusual type here - we want a mutable reference to a slice of bytes, because we want to be able to advance the start of the slice after reading an item from it (but will not mutate the actual contents of the slice).

Implementations on Foreign Types§

§

impl<UT> FfiConverter<UT> for i16

§

type FfiType = i16

§

fn lower(obj: i16) -> <i16 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <i16 as FfiConverter<UT>>::FfiType) -> Result<i16, Error>

§

fn write(obj: i16, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<i16, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_I16)

§

impl<UT> FfiConverter<UT> for SystemTime

Support for passing timestamp values via the FFI.

Timestamps values are currently always passed by serializing to a buffer.

Timestamps are represented on the buffer by an i64 that indicates the direction and the magnitude in seconds of the offset from epoch, and a u32 that indicates the nanosecond portion of the offset magnitude. The nanosecond portion is expected to be between 0 and 999,999,999.

To build an epoch offset the absolute value of the seconds portion of the offset should be combined with the nanosecond portion. This is because the sign of the seconds portion represents the direction of the offset overall. The sign of the seconds portion can then be used to determine if the total offset should be added to or subtracted from the unix epoch.

§

type FfiType = RustBuffer

§

fn lower(v: SystemTime) -> RustBuffer

§

fn try_lift(buf: RustBuffer) -> Result<SystemTime, Error>

§

fn write(obj: SystemTime, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<SystemTime, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_SYSTEM_TIME)

§

impl<UT> FfiConverter<UT> for u32

§

type FfiType = u32

§

fn lower(obj: u32) -> <u32 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <u32 as FfiConverter<UT>>::FfiType) -> Result<u32, Error>

§

fn write(obj: u32, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<u32, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_U32)

§

impl<UT> FfiConverter<UT> for String

Support for passing Strings via the FFI.

Unlike many other implementations of FfiConverter, this passes a struct containing a raw pointer rather than copying the data from one side to the other. This is a safety hazard, but turns out to be pretty nice for useability. This struct must be a valid RustBuffer and it must contain valid utf-8 data (in other words, it must be a Vec<u8> suitable for use as an actual rust String).

When serialized in a buffer, strings are represented as a i32 byte length followed by utf8-encoded bytes. (It’s a signed integer because unsigned types are currently experimental in Kotlin).

§

type FfiType = RustBuffer

§

fn lower(obj: String) -> <String as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <String as FfiConverter<UT>>::FfiType) -> Result<String, Error>

§

fn write(obj: String, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<String, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_STRING)

§

impl<UT> FfiConverter<UT> for f64

§

type FfiType = f64

§

fn lower(obj: f64) -> <f64 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <f64 as FfiConverter<UT>>::FfiType) -> Result<f64, Error>

§

fn write(obj: f64, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<f64, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_F64)

§

impl<UT> FfiConverter<UT> for u16

§

type FfiType = u16

§

fn lower(obj: u16) -> <u16 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <u16 as FfiConverter<UT>>::FfiType) -> Result<u16, Error>

§

fn write(obj: u16, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<u16, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_U16)

§

impl<UT> FfiConverter<UT> for bool

Support for passing boolean values via the FFI.

Booleans are passed as an i8 in order to avoid problems with handling C-compatible boolean values on JVM-based languages.

§

type FfiType = i8

§

fn lower(obj: bool) -> <bool as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <bool as FfiConverter<UT>>::FfiType) -> Result<bool, Error>

§

fn write(obj: bool, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<bool, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_BOOL)

§

impl<UT> FfiConverter<UT> for i64

§

type FfiType = i64

§

fn lower(obj: i64) -> <i64 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <i64 as FfiConverter<UT>>::FfiType) -> Result<i64, Error>

§

fn write(obj: i64, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<i64, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_I64)

§

impl<T, UT> FfiConverter<UT> for Arc<T>where T: FfiConverterArc<UT> + ?Sized,

§

type FfiType = <T as FfiConverterArc<UT>>::FfiType

§

fn lower(obj: Arc<T>) -> <Arc<T> as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <Arc<T> as FfiConverter<UT>>::FfiType) -> Result<Arc<T>, Error>

§

fn write(obj: Arc<T>, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<Arc<T>, Error>

§

const TYPE_ID_META: MetadataBuffer = T::TYPE_ID_META

§

impl<UT> FfiConverter<UT> for i32

§

type FfiType = i32

§

fn lower(obj: i32) -> <i32 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <i32 as FfiConverter<UT>>::FfiType) -> Result<i32, Error>

§

fn write(obj: i32, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<i32, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_I32)

§

impl<UT> FfiConverter<UT> for i8

§

type FfiType = i8

§

fn lower(obj: i8) -> <i8 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <i8 as FfiConverter<UT>>::FfiType) -> Result<i8, Error>

§

fn write(obj: i8, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<i8, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_I8)

§

impl<UT> FfiConverter<UT> for f32

§

type FfiType = f32

§

fn lower(obj: f32) -> <f32 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <f32 as FfiConverter<UT>>::FfiType) -> Result<f32, Error>

§

fn write(obj: f32, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<f32, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_F32)

§

impl<UT> FfiConverter<UT> for u8

§

type FfiType = u8

§

fn lower(obj: u8) -> <u8 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <u8 as FfiConverter<UT>>::FfiType) -> Result<u8, Error>

§

fn write(obj: u8, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<u8, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_U8)

§

impl<UT> FfiConverter<UT> for u64

§

type FfiType = u64

§

fn lower(obj: u64) -> <u64 as FfiConverter<UT>>::FfiType

§

fn try_lift(v: <u64 as FfiConverter<UT>>::FfiType) -> Result<u64, Error>

§

fn write(obj: u64, buf: &mut Vec<u8, Global>)

§

fn try_read(buf: &mut &[u8]) -> Result<u64, Error>

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_U64)

Implementors§

§

impl<UT> FfiConverter<UT> for Duration

Support for passing duration values via the FFI.

Duration values are currently always passed by serializing to a buffer.

Durations are represented on the buffer by a u64 that indicates the magnitude in seconds, and a u32 that indicates the nanosecond portion of the magnitude. The nanosecond portion is expected to be between 0 and 999,999,999.

§

type FfiType = RustBuffer

§

const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_DURATION)