To enable async interoperability, follow these steps to configure the cxx bridge and the cxx-async macros.
1. Define the Bridge
In your #[cxx::bridge] module, declare type aliases for your future types and define the async methods. For Rust-to-C++ calls, the C++ method must return the declared future type. For C++-to-Rust calls, the Rust method must return a boxed version of that future type.
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
type RustFutureString = crate::RustFutureString;
fn hello_from_cpp() -> RustFutureString;
}
extern "Rust" {
fn hello_from_rust() -> Box<RustFutureString>;
}
}
2. Implement the Future Bridge in Rust
Use the #[cxx_async::bridge] attribute to implement Future for your custom type. The Output type should be the type the future yields.
#[cxx_async::bridge]
unsafe impl Future for RustFutureString {
type Output = String;
}
3. Configure the C++ side
Include the appropriate headers (rust/cxx_async.h and either rust/cxx_async_cppcoro.h or rust/cxx_async_folly.h). Use the CXXASYNC_DEFINE_FUTURE macro at the top level (not in a namespace) to define the future.
Macro Syntax:
CXXASYNC_DEFINE_FUTURE(cpp_type, namespace_parts...)
cpp_type: The C++ type that cxx maps your Rust type to (e.g., rust::String for String).namespace_parts: The fully-qualified name of the future, with :: replaced by commas.
#include "rust/cxx.h"
#include "rust/cxx_async.h"
#include "rust/cxx_async_cppcoro.h"
CXXASYNC_DEFINE_FUTURE(rust::String, RustFutureString);
RustFutureString hello_from_cpp() {
co_return std::string("Hello world!");
}
4. Calling Async functions
Rust calling C++:
async fn call_cpp() -> String {
// Returns a Result; unwrap to get the value or catch C++ exceptions
ffi::hello_from_cpp().await.unwrap()
}
C++ calling Rust:
In Rust, use CxxAsyncResult::infallible for standard async blocks, or fallible if your block returns a Result.
// Rust side
fn hello_from_rust() -> RustFutureString {
RustFutureString::infallible(async { "Hello world!".to_owned() })
}
// C++ side
cppcoro::task<rust::String> call_rust() {
co_return hello_from_rust();
}
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
type RustFutureString = crate::RustFutureString;
fn hello_from_cpp() -> RustFutureString;
}
extern "Rust" {
fn hello_from_rust() -> Box<RustFutureString>;
}
}
#[cxx_async::bridge]
unsafe impl Future for RustFutureString {
type Output = String;
}