Skip to content

The uniffi::Object derive

The Object derive registers a UniFFI interface.

#[derive(uniffi::Object)]
struct MyObject {
    // ...
}

The #[uniffi::export] attribute is used on an impl block to export methods of the interface.

#[uniffi::export]
impl MyObject {
    // Constructors need to be annotated as such.
    // The return value can be either `Self` or `Arc<Self>`
    // It is the primary constructor, so in most languages this is invoked with
    `MyObject()`.
    #[uniffi::constructor]
    fn new(argument: String) -> Arc<Self> {
        // ...
    }

    // Constructors with different names are also supported, usually invoked
    // as `MyObject.named()` (depending on the target language)
    #[uniffi::constructor]
    fn named() -> Arc<Self> {
        // ...
    }

    // All functions that are not constructors must have a `self` argument
    fn method_a(&self) {
        // ...
    }

    // Returning objects is also supported, either as `Self` or `Arc<Self>`
    fn method_b(self: Arc<Self>) {
        // ...
    }
}

Impl blocks without the #[uniffi::export] are ignored by UniFFI. You can use the #[uniffi::export] attribute on any number of impl blocks.

See more about constructors here

Traits

#[uniffi::export]
trait MyTrait {
    // ...
}

And a foreign trait:

#[uniffi::export(with_foreign)]
trait MyTrait {
    // ...
}

Arguments

#[uniffi::export]
impl Foo {
  // Methods can take a `&self`, which will be borrowed from `Arc<Self>`
  fn some_method(&self) {
    ...
  }
}

// Input foo as an Arc and bar as a reference
fn call_both(foo: Arc<Foo>, bar: &Foo) {
  foo.some_method();
  bar.some_method();
}

The one restriction is that the reference must be visible in the function signature. This wouldn't work:

type MyFooRef = &'static Foo;

// ERROR: UniFFI won't recognize that the `foo` argument is a reference.
#[uniffi::export]
fn do_something(foo: MyFooRef) {
}

Structs implementing traits.

You can declare that an object implements a trait. For example:

#[uniffi::export]
trait MyTrait { .. }

#[derive(uniffi::Object)]
struct MyObject {}

#[uniffi::export]
impl MyObject {
    // ... some methods
}

#[uniffi::export]
impl MyTrait for MyObject {
    // ... the trait methods.
}

This will mean the bindings are able to use both the methods declared directly on MyObject but also be able to be used when a MyTrait is required.

Not all bindings support this.