Custom types

A custom type is a Rust type that crosses the FFI as one of the builtin types. You tell UniFFI how to convert between the two. By default, Kotlin only sees the builtin type. You can also configure your own Kotlin type for it.

Rust side

For a newtype, custom_newtype! is enough:

pub struct UserId(pub i64);
uniffi::custom_newtype!(UserId, i64);

For anything else, use custom_type! with conversion functions. If the type comes from another crate, add remote:

use url::Url;

uniffi::custom_type!(Url, String, {
    remote,                                // Url is defined in the `url` crate
    lower: |url| url.into(),
    try_lift: |s| Ok(Url::parse(&s)?),
});

In UDL, declare custom types with [Custom] typedef string Url;.

Kotlin side: default

Without configuration, the custom type is a typealias to the builtin type:

typealias UserId = Long
typealias Url = String

Kotlin side: your own type

To use a real Kotlin type, configure it in uniffi.toml:

[custom_types.Url]
type_name = "io.ktor.http.Url"          # the Kotlin type
imports = ["io.ktor.http.Url"]          # imports the conversions need
lift = "Url({})"                        # builtin → Kotlin
lower = "{}.toString()"                 # Kotlin → builtin

{} is replaced with the value being converted. into_custom and from_custom are accepted as older names for lift and lower.

val demo = getCustomTypesDemo(null)
demo.url == Url("http://example.com/")   // a real io.ktor.http.Url

The Kotlin type has to be available in commonMain. Add its library as a dependency. Default values of fields with a custom type are converted with the lift expression too.

Fixtures