Attribute Macro async_ffi_macros::async_ffi
source · #[async_ffi]
Expand description
A helper macro attribute to converts an async fn
into a ordinary fn
returning FfiFuture
.
Note that this crate doesn’t automatically pulls in async_ffi
dependency. You must manually
add async_ffi
dependency to your Cargo.toml
. Or alternatively, using macros
feature of
async_ffi
which re-export the macro from this crate, instead of pulling in this crate
explicitly.
Usages
The typical usage is to apply this macro to an async fn
.
use async_ffi_macros::async_ffi;
// Or if you have `macros` feature of `async_ffi` enabled,
// use async_ffi::async_ffi;
#[async_ffi]
#[no_mangle]
async fn func(x: i32) -> i32 {
do_work(x).await;
x + 42
}
It would be converted into roughly:
#[no_mangle]
extern "C" fn func(x: i32) -> ::async_ffi::FfiFuture<i32> {
::async_ffi::FfiFuture::new(async move {
// NB. Arguments are always moved into the result Future, no matter if it's used.
// This is the same behavior as original `async fn`s.
let x = x;
do_work(x).await;
x + 42
})
}
You can also apply #[async_ffi]
to external functions.
extern "C" {
#[async_ffi]
async fn extern_fn(arg: i32) -> i32;
// => fn extern_fn(arg: i32) -> ::async_ffi::FfiFuture<i32>;
}
Non-Send
futures
Call the macro with arguments ?Send
to wrap the result into LocalFfiFuture
instead of
FfiFuture
.
#[async_ffi(?Send)]
async fn func() {}
// => fn func() -> ::async_ffi::LocalFfiFuture<()> { ... }
References in parameters
When parameters of your async fn
contain references, you need to capture their lifetimes in
the result FfiFuture
. Currently, we don’t expand lifetime elisions. You must explicitly give
the result lifetime a name in macro arguments and specify all bounds if necessary.
#[async_ffi('fut)]
async fn borrow(x: &'fut i32, y: &'fut i32) -> i32 { *x + *y }
// => fn borrow<'fut>(x: &'fut i32) -> ::async_ffi::BorrowingFfiFuture<'fut, i32> { ... }
// In complex cases, explicit bounds are necessary.
#[async_ffi('fut)]
async fn complex<'a: 'fut, 'b: 'fut>(x: &'a mut i32, y: &'b mut i32) -> i32 { *x + *y }
// => fn complex<'a: 'fut, 'b: 'fut, 'fut>(x: &'a mut i32, y: &'b mut i32) -> BorrowingFfiFuture<'fut, i32> { ... }
// Non Send async fn can also work together.
#[async_ffi('fut, ?Send)]
async fn non_send(x: &'fut i32, y: &'fut i32) -> i32 { *x }
// => fn non_send<'fut>(x: &'fut i32) -> ::async_ffi::LocalBorrowingFfiFuture<'fut, i32> { ... }