Shared types
Shared types enable both languages to have visibility into the internals of a type. This is in contrast to opaque Rust types and opaque C++ types, for which only one side gets to manipulate the internals.
Unlike opaque types, the FFI bridge is allowed to pass and return shared types by value.
The order in which shared types are written is not important. C++ is order sensitive but CXX will topologically sort and forward-declare your types as necessary.
Shared structs and enums
For enums, only C-like a.k.a. unit variants are currently supported.
The generated data structures
Shared structs compile to an aggregate-initialization compatible C++ struct.
Shared enums compile to a C++ enum class
with a sufficiently sized integral
base type decided by CXX.
Because it is not UB in C++ for an enum class
to hold a value different from
all of the listed variants, we use a Rust representation for shared enums that
is compatible with this. The API you'll get is something like:
Notice you're free to treat the enum as an integer in Rust code via the public
repr
field.
Pattern matching with match
still works but will require you to write wildcard
arms to handle the situation of an enum value that is not one of the listed
variants.
If a shared struct has generic lifetime parameters, the lifetimes are simply not represented on the C++ side. C++ code will need care when working with borrowed data (as usual in C++).
Enum discriminants
You may provide explicit discriminants for some or all of the enum variants, in
which case those numbers will be propagated into the generated C++ enum class
.
Variants without an explicit discriminant are assigned the previous discriminant plus 1. If the first variant has not been given an explicit discriminant, it is assigned discriminant 0.
By default CXX represents your enum using the smallest integer type capable of
fitting all the discriminants (whether explicit or implicit). If you need a
different representation for reasons, provide a repr
attribute.
Extern enums
If you need to interoperate with an already existing enum for which an existing C++ definition is the source of truth, make sure that definition is provided by some header in the bridge and then declare your enum additionally as an extern C++ type.
CXX will recognize this pattern and, instead of generating a C++ definition of the enum, will instead generate C++ static assertions asserting that the variants and discriminant values and integer representation written in Rust all correctly match the existing C++ enum definition.
Extern enums support all the same features as ordinary shared enums (explicit discriminants, repr). Again, CXX will static assert that all of those things you wrote are correct.
Derives
The following standard traits are supported in derive(...)
within the CXX
bridge module.
Clone
Copy
Debug
Default
Eq
Hash
Ord
PartialEq
PartialOrd
Note that shared enums automatically always come with impls of Copy
, Clone
,
Eq
, and PartialEq
, so you're free to omit those derives on an enum.
The derives naturally apply to both the Rust data type and the corresponding C++ data type:
Hash
gives you a specialization oftemplate <> struct std::hash<T>
in C++PartialEq
producesoperator==
andoperator!=
PartialOrd
producesoperator<
,operator<=
,operator>
,operator>=