blob: 983cdbd48b7e9d295b6a745900be114cce71cd4b [file] [log] [blame] [view]
# Bindings for enumerations
Here we describe how Crubit maps
[enumerations](https://en.wikipedia.org/wiki/Enumerated_type): a Rust unit-only
`enum` or a C++ `enum`.
## Rust bindings for C++ `enum`s
<!-- the example below is based on rs_bindings_from_cc/test/golden/enums.h -->
For the following C++ header:
```cpp
enum Color {
kRed,
kBlue,
kGreen,
};
```
Crubit will generate the following bindings:
```rust
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, PartialOrd, Ord)]
pub struct Color(u32);
impl Color {
pub const kRed: Color = Color(0);
pub const kBlue: Color = Color(1);
pub const kGreen: Color = Color(2);
}
impl From<u32> for Color {
fn from(value: u32) -> Color {
Color(value)
}
}
impl From<Color> for u32 {
fn from(value: Color) -> u32 {
value.0
}
}
```
<!-- the explanation below is based on b/208944813#comment1 -->
A C++ `enum` is translated into a set of `const` items in Rust, because this
most accurately represents the fact that C++ enumerations are non-exhaustive
(i.e. in C++ any in-range value can be cast to the enumeration, even if it
wasn't listed in the `enum` declaration). In other words, C++ behavior doesn't
match Rust `enum`s where "a discriminant in an enum not included in the type
definition" is
[listed](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)
as a potential source of Undefined Behavior.
TODO: Consider allowing C++ `enum`s to be marked with an attribute (e.g.
`[[crubit::exhaustive]]`?) and translate them to a Rust `enum`.
## C++ bindings for Rust unit-only `enum`s
<!-- The example below is based on the
`test_format_item_enum_with_only_discriminant_items` test from
`cc_bindings_from_rs/bindings.rs` -->
For the following Rust type:
```rust
pub enum Color {
Red,
Green,
Blue,
}
```
Crubit will generate the following bindings:
```cpp
struct alignas(1) Color final {
public:
// The Rust type has no `Default` impl.
Color() = delete;
// The Rust type is not `Copy`.
Color(const Color&) = delete;
Color& operator=(const Color&) = delete;
// All non-`Drop` Rust types are trivially-movable.
Color(Color&&) = default;
Color& operator=(Color&&) = delete;
// The Rust type has no `Drop` impl,
// nor requires custom drop glue.
~Color() = default;
private:
...
};
```
Note that the generated C++ bindings are currently opaque (b/259984090 and
b/280861833 track adding more idiomatic bindings for enumerations). In
particular, the C++ side doesn't currently have any direct visibility into the
discriminant the Rust enum. Nevertheless, the bindings should cover methods and
trait of the Rust enum - for example:
* mapping static methods from Rust to non-member methods in C++
* mapping `Default` trait impl from Rust to the default constructor in C++
(this bullet item is WIP - see b/258249980)