pub unsafe trait ExternType {
type Id;
type Kind: Kind;
}
Expand description
A type for which the layout is determined by its C++ definition.
This trait serves the following two related purposes.
§Safely unifying occurrences of the same extern type
ExternType
makes it possible for CXX to safely share a consistent Rust
type across multiple #[cxx::bridge] invocations that refer to a common
extern C++ type.
In the following snippet, two #[cxx::bridge] invocations in different
files (possibly different crates) both contain function signatures involving
the same C++ type example::Demo
. If both were written just containing
type Demo;
, then both macro expansions would produce their own separate
Rust type called Demo
and thus the compiler wouldn’t allow us to take the
Demo
returned by file1::ffi::create_demo
and pass it as the Demo
argument accepted by file2::ffi::take_ref_demo
. Instead, one of the two
Demo
s has been defined as an extern type alias of the other, making them
the same type in Rust. The CXX code generator will use an automatically
generated ExternType
impl emitted in file1 to statically verify that in
file2 crate::file1::ffi::Demo
really does refer to the C++ type
example::Demo
as expected in file2.
// file1.rs
#[cxx::bridge(namespace = "example")]
pub mod ffi {
unsafe extern "C++" {
type Demo;
fn create_demo() -> UniquePtr<Demo>;
}
}
// file2.rs
#[cxx::bridge(namespace = "example")]
pub mod ffi {
unsafe extern "C++" {
type Demo = crate::file1::ffi::Demo;
fn take_ref_demo(demo: &Demo);
}
}
§Integrating with bindgen-generated types
Handwritten ExternType
impls make it possible to plug in a data structure
emitted by bindgen as the definition of a C++ type emitted by CXX.
By writing the unsafe ExternType
impl, the programmer asserts that the C++
namespace and type name given in the type id refers to a C++ type that is
equivalent to Rust type that is the Self
type of the impl.
mod folly_sys; // the bindgen-generated bindings
use cxx::{type_id, ExternType};
unsafe impl ExternType for folly_sys::StringPiece {
type Id = type_id!("folly::StringPiece");
type Kind = cxx::kind::Opaque;
}
#[cxx::bridge(namespace = "folly")]
pub mod ffi {
unsafe extern "C++" {
include!("rust_cxx_bindings.h");
type StringPiece = crate::folly_sys::StringPiece;
fn print_string_piece(s: &StringPiece);
}
}
// Now if we construct a StringPiece or obtain one through one
// of the bindgen-generated signatures, we are able to pass it
// along to ffi::print_string_piece.
Required Associated Types§
Sourcetype Id
type Id
A type-level representation of the type’s C++ namespace and type name.
This will always be defined using type_id!
in the following form:
type Id = cxx::type_id!("name::space::of::TypeName");
Sourcetype Kind: Kind
type Kind: Kind
Either cxx::kind::Opaque
or cxx::kind::Trivial
.
A C++ type is only okay to hold and pass around by value in Rust if its move constructor is trivial and it has no destructor. In CXX, these are called Trivial extern C++ types, while types with nontrivial move behavior or a destructor must be considered Opaque and handled by Rust only behind an indirection, such as a reference or UniquePtr.
If you believe your C++ type reflected by this ExternType impl is indeed fine to hold by value and move in Rust, you can specify:
type Kind = cxx::kind::Trivial;
which will enable you to pass it into C++ functions by value, return it
by value, and include it in struct
s that you have declared to
cxx::bridge
. Your claim about the triviality of the C++ type will be
checked by a static_assert
in the generated C++ side of the binding.