callbackinterface.rs |
Callback interfaces are traits specified in UDL which can be implemented by foreign languages.
# Using callback interfaces
1. 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);
}
```
2. Define a callback interface in the UDL
```idl
callback interface Keychain {
string? get(string key);
void put(string key, string data);
};
```
3. 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:
```idl
object Authenticator {
constructor(Keychain keychain);
void login();
}
```
In Rust:
```
# trait Keychain: Send {
# fn get(&self, key: String) -> Option<String>;
# fn put(&self, key: String, value: String);
# }
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());
}
}
```
4. Create an foreign language implementation of the callback interface.
In this example, here's a Kotlin implementation.
```kotlin
class AndroidKeychain: Keychain {
override fun get(key: String): String? {
// … elide the implementation.
return value
}
override fun put(key: String) {
// … elide the implementation.
}
}
```
5. Pass the implementation to Rust.
Again, in Kotlin
```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. |
6812 |
ffidefault.rs |
FfiDefault trait
When we make a FFI call into Rust we always need to return a value, even if that value will be
ignored because we're flagging an exception. This trait defines what that value is for our
supported FFI types. |
1798 |
ffiserialize.rs |
|
13077 |
foreignbytes.rs |
|
3988 |
foreigncallbacks.rs |
This module contains code to handle foreign callbacks - C-ABI functions that are defined by a
foreign language, then registered with UniFFI. These callbacks are used to implement callback
interfaces, async scheduling etc. Foreign callbacks are registered at startup, when the foreign
code loads the exported library. For each callback type, we also define a "cell" type for
storing the callback. |
1393 |
foreignfuture.rs |
This module defines a Rust Future that wraps an async foreign function call.
The general idea is to create a oneshot channel, hand the sender to the foreign side, and
await the receiver side on the Rust side.
The foreign side should:
* Input a [ForeignFutureCallback] and a `u64` handle in their scaffolding function.
This is the sender, converted to a raw pointer, and an extern "C" function that sends the result.
* Return a [ForeignFuture], which represents the foreign task object corresponding to the async function.
* Call the [ForeignFutureCallback] when the async function completes with:
* The `u64` handle initially passed in
* The `ForeignFutureResult` for the call
* Wait for the [ForeignFutureHandle::free] function to be called to free the task object.
If this is called before the task completes, then the task will be cancelled. |
8325 |
handle.rs |
|
1569 |
mod.rs |
Types that can cross the FFI boundary. |
825 |
rustbuffer.rs |
|
13685 |
rustcalls.rs |
# Low-level support for calling rust functions
This module helps the scaffolding code make calls to rust functions and pass back the result to the FFI bindings code.
It handles:
- Catching panics
- Adapting the result of `Return::lower_return()` into either a return value or an
exception |
11307 |
rustfuture |
|
|