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