Async/Future support
UniFFI supports exposing async Rust functions over the FFI. It can convert a Rust Future
/async fn
to and from foreign native futures (async
/await
in Python/Swift, suspend fun
in Kotlin etc.)
Check out the examples or the more terse and thorough fixtures.
Example
This is a short "async sleep()" example:
use std::time::Duration;
use async_std::future::{timeout, pending};
/// Async function that says something after a certain time.
#[uniffi::export]
pub async fn say_after(ms: u64, who: String) -> String {
let never = pending::<()>();
timeout(Duration::from_millis(ms), never).await.unwrap_err();
format!("Hello, {who}!")
}
This can be called by the following Python code:
import asyncio
from uniffi_example_futures import *
async def main():
print(await say_after(20, 'Alice'))
if __name__ == '__main__':
asyncio.run(main())
Async functions can also be defined in UDL:
namespace example {
[Async]
string say_after(u64 ms, string who);
}
This code uses asyncio
to drive the future to completion, while our exposed function is used with await
.
In Rust Future
terminology this means the foreign bindings supply the "executor" - think event-loop, or async runtime. In this example it's asyncio
. There's no requirement for a Rust event loop.
There are some great API docs on the implementation that are well worth a read.
See the foreign-executor fixture for more implementation details.