Crate async_ffi[−][src]
Expand description
FFI-compatible futures
In case of an async program with some async plugins, Future
s need to cross the FFI boundary.
But Rust currently doesn’t provide stable ABI nor stable layout of related structs like
dyn Future
and Waker
.
With this crate, we can easily wrap async blocks or async functions to make this happen.
FfiFuture<T>
provides the same function as Box<dyn Future<Output = T> + Send>
but FFI-compatible (repr(C)
).
Any future implementing Send
can be converted to FfiFuture<T>
by calling into_ffi
on it.
FfiFuture<T>
also implements Future<Output = T> + Send
. You can simply await
a FfiFuture<T>
like a normal Future
to get the output.
There is also a non-Send
version LocalFfiFuture<T>
working like
Box<dyn Future<Output = T>>
, which can be used for local future or single-threaded targets.
It is ABI-compatible to FfiFuture<T>
, but it’s your duty to guarantee that non-Send
types
never cross thread boundary.
Panics
Unwinding across an FFI boundary is Undefined Behaviour.
Panic in Future::poll
Since the body of async fn
is translated to Future::poll
by compiler, it is most likely to
panic. In this case, the wrapped FfiFuture
will catch unwinding with std::panic::catch_unwind
,
returning FfiPoll::Panicked
. And the other side (usually the plugin host) will get this value
and explicit panic, just like std::sync::Mutex
’s poisoning mechanism.
Panic in Future::drop
or any waker vtable functions Waker::*
Unfortunately, this is very difficult to handle since drop cleanup and Waker
functions are
expected to be infallible. If these functions panic, we would just call std::process::abort
.
Example
Provide some async functions in library: (plugin side)
// Compile with `crate-type = ["cdylib"]`.
use async_ffi::{FfiFuture, FutureExt};
#[no_mangle]
pub extern "C" fn work(arg: u32) -> FfiFuture<u32> {
async move {
let ret = do_some_io(arg).await;
do_some_sleep(42).await;
ret
}
.into_ffi()
}
Execute async functions from external library: (host or executor side)
use async_ffi::{FfiFuture, FutureExt};
// #[link(name = "myplugin...")]
extern "C" {
#[no_mangle]
fn work(arg: u32) -> FfiFuture<u32>;
}
async fn run_work(arg: u32) -> u32 {
unsafe { work(arg).await }
}
Structs
The FFI compatible future type with Send
bound.
The FFI compatible std::task::Context
The FFI compatible future type without Send
bound.
Represents that the poll function panicked.
Enums
The FFI compatible std::task::Poll
Constants
The ABI version of FfiFuture
and LocalFfiFuture
.
Every non-compatible ABI change will increase this number.
Traits
Helper trait to provide convenience methods for converting a std::task::Context
to FfiContext
Helper trait to provide conversion from Future
to FfiFuture
or LocalFfiFuture
.
Type Definitions
The FFI compatible future type with Send
bound and 'static
lifetime,
which is needed for most use cases.
The FFI compatible future type without Send
bound but with 'static
lifetime.