• Stars
    star
    232
  • Rank 172,847 (Top 4 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created about 3 years ago
  • Updated 25 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Simple interoperability between C++ coroutines and asynchronous Rust

cxx-async

Overview

cxx-async is a Rust crate that extends the cxx library to provide interoperability between asynchronous Rust code using async/await and C++20 coroutines using co_await. If your C++ code is asynchronous, cxx-async can provide a more convenient, and potentially more efficient, alternative to callbacks. You can freely convert between C++ coroutines and Rust futures and/or streams and await one from the other.

It's important to emphasize what cxx-async isn't: it isn't a C++ binding to Tokio or any other Rust I/O library. Nor is it a Rust binding to boost::asio or similar. Such bindings could in principle be layered on top of cxx-async if desired, but this crate doesn't provide them out of the box. (Note that this is a tricky problem even in theory, since Rust async I/O code is generally tightly coupled to a single library such as Tokio, in much the same way C++ async I/O code tends to be tightly coupled to libraries like boost::asio.) If you're writing server code, you can still use cxx-async, but you will need to ensure that both the Rust and C++ sides run separate I/O executors.

cxx-async aims for compatibility with popular C++ coroutine support libraries. Right now, both the lightweight cppcoro and the more comprehensive Folly are supported. Pull requests are welcome to support others.

Quick tutorial

To use cxx-async, first start by adding cxx to your project. Then add the following to your Cargo.toml:

[dependencies]
cxx-async = "0.1"

Now, inside your #[cxx::bridge] module, declare a future type and some methods like so:

#[cxx::bridge]
mod ffi {
    // Declare type aliases for each of the future types you wish to use here. Then declare
    // async C++ methods that you wish Rust to call. Make sure they return one of the future
    // types you declared.
    unsafe extern "C++" {
        type RustFutureString = crate::RustFutureString;

        fn hello_from_cpp() -> RustFutureString;
    }

    // Async Rust methods that you wish C++ to call go here. Again, make sure they return one of the
    // boxed future types you declared above.
    extern "Rust" {
        fn hello_from_rust() -> Box<RustFutureString>;
    }
}

After the #[cxx::bridge] block, define the future types using the #[cxx_async::bridge] attribute:

// The inner type is the Rust type that this future yields.
#[cxx_async::bridge]
unsafe impl Future for RustFutureString {
    type Output = String;
}

Now, in your C++ file, make sure to #include the right headers:

#include "rust/cxx.h"
#include "rust/cxx_async.h"
#include "rust/cxx_async_cppcoro.h"  // Or cxx_async_folly.h, as appropriate.

And add a call to the CXXASYNC_DEFINE_FUTURE macro to define the C++ side of the future:

// The first argument is the C++ type that the future yields, and the second argument is the
// fully-qualified name of the future, with `::` namespace separators replaced with commas. (For
// instance, if your future is named `mycompany::myproject::RustFutureString`, you might write
// `CXXASYNC_DEFINE_FUTURE(rust::String, mycompany, myproject, RustFutureString);`. The first
// argument is the C++ type that `cxx` maps your Rust type to: in this case, `String` maps to
// `rust::String`, so we supply `rust::String` here.
//
// This macro must be invoked at the top level, not in a namespace.
CXXASYNC_DEFINE_FUTURE(rust::String, RustFutureString);

You're all set! Now you can define asynchronous C++ code that Rust can call:

RustFutureString hello_from_cpp() {
    co_return std::string("Hello world!");
}

On the Rust side:

async fn call_cpp() -> String {
    // This returns a Result (with the error variant populated if C++ threw an exception), so you
    // need to unwrap it:
    ffi::hello_from_cpp().await.unwrap()
}

And likewise, define some asynchronous Rust code that C++ can call:

use cxx_async::CxxAsyncResult;
fn hello_from_rust() -> RustFutureString {
    // You can instead use `fallible` if your async block returns a Result.
    RustFutureString::infallible(async { "Hello world!".to_owned() })
}

Over on the C++ side:

cppcoro::task<rust::String> call_rust() {
    co_return hello_from_rust();
}

That's it! You should now be able to freely await futures on either side. An analogous procedure can be followed to wrap C++ coroutines that yield values with co_yield in Rust streams.

Installation notes

You will need a C++ compiler that implements the coroutines TS, which generally coincides with support for C++20. Some C++ compilers (e.g. Apple clang 13.0.0) that implement the coroutines TS crash when compiling Folly. It's also recommended to use libc++ instead of libstdc++, as the former has more complete support for coroutines.

Folly installation

Usage of cxx-async with Folly requires that Folly have been built with coroutine support. Many distributions of Folly (e.g. the one in Homebrew) don't have coroutine support enabled; a common symptom of this is a linker error mentioning a missing symbol folly::resumeCoroutineWithNewAsyncStackRoot.

To build Folly with coroutine support on macOS, try:

$ git clone https://github.com/facebook/folly.git
$ cd folly
$ ./build.sh --install-dir=/usr/local --extra-cmake-defines \
    '{"CXX_STD": "c++20", "CMAKE_CXX_FLAGS": "-fcoroutines-ts"}'

Note that, depending on how your permissions are set up, you might get an error like Permission denied: '/usr/local/.built-by-getdeps'; this is harmless.

Code of conduct

cxx-async follows the same Code of Conduct as Rust itself. Reports can be made to the crate authors.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

More Repositories

1

rust-media

A free, comprehensive, and portable video/audio streaming library for Rust
Rust
808
star
2

sprocketnes

NES emulator written in Rust
Rust
739
star
3

offset-allocator

A port of Sebastian Aaltonen's `OffsetAllocator` to Rust
Rust
389
star
4

zero.rs

A module for freestanding Rust programs
Rust
247
star
5

libui-rs

Rust bindings to the minimalist, native, cross-platform UI toolkit `libui`
Rust
212
star
6

vscode-powerline

Powerline theme for the Visual Studio Code status bar
CSS
65
star
7

mp4v2

MP4v2 Library: This library provides functions to read, create, and modify mp4 files
C++
56
star
8

rustfmt

An incomplete Rust pretty printer
Rust
48
star
9

planeshift

Early experimental WIP. Do not use yet!
Rust
38
star
10

compute-shader

A simple, cross-platform interface to GPU compute functionality in Rust
Rust
37
star
11

gltf-ibl-sampler-egui

An artist-friendly skybox generator wrapping the glTF IBL Sampler
C++
33
star
12

parng

A parallel, SIMD-optimized PNG decoder written in Rust
Rust
23
star
13

multilist

Safe, intrusive doubly-linked lists for Rust
Rust
17
star
14

fempeg

MP2 decoder written in Rust
Rust
17
star
15

doctorjsmm

DoctorJS--, simple type inference for JavaScript
JavaScript
16
star
16

bevy-baked-gi

A workflow for baked global illumination in the Bevy game engine
C#
15
star
17

firefox-framerate-monitor

Simple Jetpack-based framerate monitor for Firefox
JavaScript
14
star
18

deminifier

JavaScript deminifier addon for Firefox 4
JavaScript
13
star
19

pilcrow

Work-in-progress Unicode paragraph layout library written in Rust
Rust
13
star
20

webrender-demos

Demos for WebRender
HTML
13
star
21

rust-sandbox

Sandboxing support for Rust, using the native OS facilities
Rust
13
star
22

miniservo-mac

Tiny browser chrome for Servo using CEF for testing
C++
12
star
23

webrast

Experimental, high-performance GPU-accelerated rasterizer for common Web content
Rust
11
star
24

linux-drm-sharing-test

A demo of cross-process texture sharing on Linux using DRI/DRM directly
C
11
star
25

rtree

Safe, zero-overhead doubly-linked trees in Rust
Rust
10
star
26

signpost

Rust interface to the OS native signpost debug facilities
Rust
10
star
27

cxx-async-prototype

Asynchronous C++ interoperability for Rust
C++
10
star
28

piranha

A simple profiler for Android
OCaml
9
star
29

cxx-async-example

A minimal example server to demonstrate use of `cxx-async`
C++
8
star
30

rust-irc-client

An IRC client library written in Rust
Rust
8
star
31

fast-itoa

Experimental SIMD integer-to-string conversion
Rust
7
star
32

test-async-texture-upload

Async texture upload demo for Android
Java
7
star
33

rust-spidermonkey

SpiderMonkey bindings for the Rust programming language
JavaScript
7
star
34

rust-nss

Rust bindings to the Network Security Services library used in Firefox and Chrome
Rust
5
star
35

virtex

Sparse virtual texturing experiment
Rust
4
star
36

fennec-faststart-prototype

Tests the Fennec Native UI graphics code
Java
4
star
37

pngl

GPU-accelerated PNG decoder written in Rust
Rust
4
star
38

rust-ao

Rust bindings to the libao audio output library
Rust
4
star
39

memory-meter

Minimalist memory meter addon for Firefox 4
JavaScript
4
star
40

iowaittop

Tiny I/O measurement tool for Android
C
4
star
41

two-engines

Gecko/Servo comparison
HTML
4
star
42

selectron

Experiments with hardware-accelerated CSS rendering
Cuda
4
star
43

rustium

Rust language bindings for the Chromium Embedded Framework
Rust
3
star
44

gfx.js

2D scene graph library for JavaScript
JavaScript
3
star
45

modmod

Simple music module player written in OCaml
OCaml
3
star
46

ocaml-oembed

OCaml library implementing the oEmbed standard
OCaml
3
star
47

android-flexible-glsurfaceview

A more flexible replacement for Android's GLSurfaceView
Java
3
star
48

giflib

Rust bindings to the venerable giflib library
Shell
2
star
49

rbot

A Rust IRC bot
Rust
2
star
50

netsurf-buildsystem

The build system from the NetSurf project
Perl
2
star
51

sharkctl

Library to allow programmatic control of Shark on Mac OS X 10.6 Snow Leopard
C
2
star
52

gperftools

Fork of Google's performance tools for better profiling on ARM
C++
2
star
53

rust-oauth

A Rust client-side implementation of the OAuth standard
Rust
2
star
54

fast-gaussian

Fast Gaussian blur demo
TypeScript
2
star
55

pcwalton.github.com

Blog
JavaScript
2
star
56

WRTextView

EXPERIMENTAL, DO NOT USE YET
Objective-C
2
star
57

buoyancy

A fast CSS float placement algorithm for Servo
Rust
2
star
58

imdialog

Partial dialog(1) replacement backed by ImGui, written in Rust
Rust
2
star
59

sample-tree

A macOS script to run sample(1) on a process and all its children
Rust
2
star
60

bevy-gltf-pbr-extras

Advanced glTF PBR features for the Bevy game engine (iridescence, etc.)
WGSL
2
star
61

lord-drawquaad

A minimalist Rust library for drawing full-screen textured quads in OpenGL 3.3+
Rust
1
star
62

NetSurf

C
1
star
63

ogg

The Xiph.org Ogg library
C
1
star
64

vorbis

The Xiph.org Vorbis library
C
1
star
65

glyphy-rs

Rust bindings to the glyphy library
Rust
1
star
66

test-universal-surface-texture

A workaround for the lack of SurfaceTexture on Android Honeycomb and below
Java
1
star
67

attic

Miscellaneous hackery.
1
star