enum Foo {
A = 0,
B = 1,
C = 2,
Unknown(i32),
}
where Unknown field cannot contain values 0, 1, or 2, thus Rust compiler will be able to pack this enum into single i32, like in C. enum Foo {
A = 0,
B = 1,
C = 2,
Unknown(i32),
}
where Unknown field cannot contain values 0, 1, or 2, thus Rust compiler will be able to pack this enum into single i32, like in C.I'd represent it like this:
#[repr(transparent)]
struct Foo(i32);
impl Foo {
const A: Foo = Foo(0);
const B: Foo = Foo(1);
const C: Foo = Foo(2);
}2) This is required for forward compatibility. For example protobuf explicitly requires it.
3) Your code is not forward compatible. The proper way is to implement it is as i32 and then unwrap it, or:
enum Foo {
A = 0,
B = 1,
C = 2,
_UNKNOWN_3 = 3,
_UNKNOWN_4 = 4,
_UNKNOWN_5 = 5,
_UNKNOWN_6 = 6,
// ... repeat few dozen times, to be forward compatible
}
Example: https://github.com/apoelstra/rust-bitcoin/blob/c37ab1f9c2392...P.S.
IMHO, Rust should allow to define enums as:
enum Foo {
A = 0,
B = 1,
C = 2,
_ , // Unknown values which must be handled by default case
}
or enum Foo {
A = 0,
B = 1,
C = 2,
_OTHER , // Unknown values which must be handled
}
because current workaround is usable for i8, maybe even for i16, but not for i32.In general, it _is_ possible for any C data layout to be represented in Rust -- but it's not necessarily the case that the representation has the same name. And it's also not the case that we can safely pass memory from C to Rust without validating the content, even if the representation is equivalent for all valid values.
[1] https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html#non_e...
[2] https://rust-lang.github.io/unsafe-code-guidelines/layout/en...
#[non_exhaustive]
#[repr(C)]
#[derive(Debug)]
#[allow(dead_code)]
enum Foo {
A = 0,
B = 1,
C = 2,
}
pub fn main() {
let bar = unsafe { std::mem::transmute::<i32, Foo>(33) };
println!("{:?}", bar);
let s = match bar {
Foo::A => ("A", bar as i32),
Foo::B => ("B", bar as i32),
Foo::C => ("C", bar as i32),
_ => ("Unknown", bar as i32),
};
println!("{:?}", s);
}
Standard Output
C
("Unknown", 33)> Your code is not forward compatible. The proper way is to implement it is as i32 and then unwrap it
That’s what they’re doing. It’s a newtype for i32 with a few named values but it can represent any i32, and you can unwrap it with .0 to get the i32 value.
I guess the compiler can't help you keep known and unknown values separate with that structure though, so maybe it's not enough.