Module uniffi::ffi::foreigncallbacks [−][src]
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, a CallbackInternals
(on the Foreign Language side) and ForeignCallbackInternals
(on Rust side) manages the process through a ForeignCallback
. There is one ForeignCallback
per callback interface.
Passing a callback interface implementation from foreign language (e.g. AndroidKeychain
) into Rust causes the
KeychainCallbackInternals
to store the instance in a handlemap.
The object handle is passed over to Rust, and used to instantiate a struct KeychainProxy
which implements
the trait. This proxy implementation is generate by Uniffi. The KeychainProxy
object is then passed to
client code as Box<dyn Keychain>
.
Methods on KeychainProxy
objects (e.g. self.keychain.get("username".into())
) encode the arguments into a RustBuffer
.
Using the ForeignCallback
, it calls the CallbackInternals
object on the foreign language side using the
object handle, and the method selector.
The CallbackInternals
object unpacks the arguments from the passed buffer, gets the object out from the handlemap,
and calls the actual implementation of the method.
If there’s a return value, it is packed up in to another RustBuffer
and used as the return value for
ForeignCallback
. The caller of ForeignCallback
, the KeychainProxy
unpacks the returned buffer into the correct
type and then returns to client code.
Structs
ForeignCallbackInternals | Struct to hold a foreign callback. |
Constants
IDX_CALLBACK_FREE | The method index used by the Drop trait to communicate to the foreign language side that Rust has finished with it, and it can be deleted from the handle map. |
Type Definitions
ForeignCallback | ForeignCallback is the Rust representation of a foreign language function.
It is the basis for all callbacks interfaces. It is registered exactly once per callback interface,
at library start up time.
Calling this method is only done by generated objects which mirror callback interfaces objects in the foreign language.
The |