{{#title extern “Rust” — Rust ♡ C++}}
#[cxx::bridge] mod ffi { extern "Rust" { } }
The extern "Rust"
section of a CXX bridge declares Rust types and signatures to be made available to C++.
The CXX code generator uses your extern “Rust” section(s) to produce a C++ header file containing the corresponding C++ declarations. The generated header has the same path as the Rust source file containing the bridge, except with a .rs.h
file extension.
A bridge module may contain zero or more extern “Rust” blocks.
Types defined in Rust that are made available to C++, but only behind an indirection.
# #[cxx::bridge] # mod ffi { extern "Rust" { type MyType; type MyOtherType; type OneMoreType<'a>; } # }
For example in the Tutorial we saw MultiBuf
used in this way. Rust code created the MultiBuf
, passed a &mut MultiBuf
to C++, and C++ later passed a &mut MultiBuf
back across the bridge to Rust.
Another example is the one on the Box<T> page, which exposes the Rust standard library's std::fs::File
to C++ as an opaque type in a similar way but with Box as the indirection rather than &mut.
The types named as opaque types (MyType
etc) refer to types in the super
module, the parent module of the CXX bridge. You can think of an opaque type T
as being like a re-export use super::T
made available to C++ via the generated header.
Opaque types are currently required to be Sized
and Unpin
. In particular, a trait object dyn MyTrait
or slice [T]
may not be used for an opaque Rust type. These restrictions may be lifted in the future.
For now, types used as extern Rust types are required to be defined by the same crate that contains the bridge using them. This restriction may be lifted in the future.
The bridge's parent module will contain the appropriate imports or definitions for these types.
use path::to::MyType; pub struct MyOtherType { ... } # # #[cxx::bridge] # mod ffi { # extern "Rust" { # type MyType; # type MyOtherType; # } # }
Rust functions made callable to C++.
Just like for opaque types, these functions refer implicitly to something in scope in the super
module, whether defined there or imported by some use
statement.
#[cxx::bridge] mod ffi { extern "Rust" { struct MyType; fn f() -> Box<MyType>; } } struct MyType(i32); fn f() -> Box<MyType> { return Box::new(MyType(1)); }
Extern Rust function signature may consist of types defined in the bridge, primitives, and any of these additional bindings.
Any signature with a self
parameter is interpreted as a Rust method and exposed to C++ as a non-static member function.
# #[cxx::bridge] # mod ffi { extern "Rust" { type MyType; fn f(&self) -> usize; } # }
The self
parameter may be a shared reference &self
, an exclusive reference &mut self
, or a pinned reference self: Pin<&mut Self>
. A by-value self
is not currently supported.
If the surrounding extern "Rust"
block contains exactly one extern type, that type is implicitly the receiver for a &self
or &mut self
method. If the surrounding block contains more than one extern type, a receiver type must be provided explicitly for the self parameter, or you can consider splitting into multiple extern blocks.
# #[cxx::bridge] # mod ffi { extern "Rust" { type First; type Second; fn bar(self: &First); fn foo(self: &mut Second); } # }
An extern Rust function signature is allowed to contain explicit lifetimes but in this case the function must be declared unsafe-to-call. This is pretty meaningless given we're talking about calls from C++, but at least it draws some extra attention from the caller that they may be responsible for upholding some atypical lifetime relationship.
#[cxx::bridge] mod ffi { extern "Rust" { type MyType; unsafe fn f<'a>(&'a self, s: &str) -> &'a str; } }
Bounds on a lifetime (like <'a, 'b: 'a>
) are not currently supported. Nor are type parameters or where-clauses.