Module uniffi::ffi::callbackinterface
Expand description
Callback interfaces are traits specified in UDL which can be implemented by foreign languages.
Using callback interfaces
- Define a Rust trait.
This toy example defines a way of Rust accessing a key-value store exposed by the host operating system (e.g. the key chain).
trait Keychain: Send {
fn get(&self, key: String) -> Option<String>;
fn put(&self, key: String, value: String);
}
- Define a callback interface in the UDL
callback interface Keychain {
string? get(string key);
void put(string key, string data);
};
- And allow it to be passed into Rust.
Here, we define a constructor to pass the keychain to rust, and then another method which may use it.
In UDL:
object Authenticator {
constructor(Keychain keychain);
void login();
}
In Rust:
struct Authenticator {
keychain: Box<dyn Keychain>,
}
impl Authenticator {
pub fn new(keychain: Box<dyn Keychain>) -> Self {
Self { keychain }
}
pub fn login(&self) {
let username = self.keychain.get("username".into());
let password = self.keychain.get("password".into());
}
}
- Create an foreign language implementation of the callback interface.
In this example, here’s a Kotlin implementation.
class AndroidKeychain: Keychain {
override fun get(key: String): String? {
// … elide the implementation.
return value
}
override fun put(key: String) {
// … elide the implementation.
}
}
- Pass the implementation to Rust.
Again, in Kotlin
val authenticator = Authenticator(AndroidKeychain())
authenticator.login()
How it works.
High level
Uniffi generates a protocol or interface in client code in the foreign language must implement.
For each callback interface, UniFFI defines a VTable.
This is a repr(C)
struct where each field is a repr(C)
callback function pointer.
There is one field for each method, plus an extra field for the uniffi_free
method.
The foreign code registers one VTable per callback interface with Rust.
VTable methods have a similar signature to Rust scaffolding functions. The one difference is that values are returned via an out pointer to work around a Python bug (https://bugs.python.org/issue5710).
The foreign object that implements the interface is represented by an opaque handle.
UniFFI generates a struct that implements the trait by calling VTable methods, passing the handle as the first parameter.
When the struct is dropped, the uniffi_free
method is called.
Structs
- Used when internal/unexpected error happened when calling a foreign callback, for example when a unknown exception is raised