1{{#title Async functions — Rust ♡ C++}} 2# Async functions 3 4Direct FFI of async functions is absolutely in scope for CXX (on C++20 and up) 5but is not implemented yet in the current release. We are aiming for an 6implementation that is as easy as: 7 8```rust,noplayground 9#[cxx::bridge] 10mod ffi { 11 unsafe extern "C++" { 12 async fn doThing(arg: Arg) -> Ret; 13 } 14} 15``` 16 17```cpp,hidelines 18rust::Future<Ret> doThing(Arg arg) { 19 auto v1 = co_await f(); 20 auto v2 = co_await g(arg); 21 co_return v1 + v2; 22} 23``` 24 25## Workaround 26 27For now the recommended approach is to handle the return codepath over a oneshot 28channel (such as [`futures::channel::oneshot`]) represented in an opaque Rust 29type on the FFI. 30 31[`futures::channel::oneshot`]: https://docs.rs/futures/0.3.8/futures/channel/oneshot/index.html 32 33```rust,noplayground 34// bridge.rs 35 36use futures::channel::oneshot; 37 38#[cxx::bridge] 39mod ffi { 40 extern "Rust" { 41 type DoThingContext; 42 } 43 44 unsafe extern "C++" { 45 include!("path/to/bridge_shim.h"); 46 47 fn shim_doThing( 48 arg: Arg, 49 done: fn(Box<DoThingContext>, ret: Ret), 50 ctx: Box<DoThingContext>, 51 ); 52 } 53} 54 55struct DoThingContext(oneshot::Sender<Ret>); 56 57pub async fn do_thing(arg: Arg) -> Ret { 58 let (tx, rx) = oneshot::channel(); 59 let context = Box::new(DoThingContext(tx)); 60 61 ffi::shim_doThing( 62 arg, 63 |context, ret| { let _ = context.0.send(ret); }, 64 context, 65 ); 66 67 rx.await.unwrap() 68} 69``` 70 71```cpp 72// bridge_shim.cc 73 74#include "path/to/bridge.rs.h" 75#include "rust/cxx.h" 76 77void shim_doThing( 78 Arg arg, 79 rust::Fn<void(rust::Box<DoThingContext> ctx, Ret ret)> done, 80 rust::Box<DoThingContext> ctx) noexcept { 81 doThing(arg) 82 .then([done, ctx(std::move(ctx))](auto &&res) mutable { 83 (*done)(std::move(ctx), std::move(res)); 84 }); 85} 86``` 87