Reputation: 21
Let's say I have the following enums - mixing c-style assigned values and variant enums:
enum Command {
Control(ControlSubcommand) = 0x00,
Temperature = 0x02,
Voltage = 0x04,
...
}
enum ControlSubcommand {
Status = 0x00,
DeviceType = 0x01,
....
}
I then pass it to a function when I try to deconstruct the given command to individual values. For a c-style command with a value directly assigned (Temperature, Voltage and so on) I want to get it's corresponding value - so 0x02, 0x04 and so on.
For the "variant" command (Control) I want to get the it's value and subcommand - so 0x00 with 0x00, 0x01 and so on.
I'm trying to write the following match construct to do so:
match command {
Command::Control(subcommand) => {
println!("control command with subcommand {}", subcommand as u32);
}
simple => {
println!("simple command {}", simple as u32);
}
}
But the problem is that technically simple
is still a Command
which is a non-primitive type, so as
cast does not work with it. Even though the variant case was already handled before and will not appear in simple
, Rust still disallows me from performing a cast.
Is it possible to somehow fix this code without changing the enum layout?
as
cast doesn't workUpvotes: 0
Views: 125
Reputation: 71310
There is no safe way to do that. If the enum is #[repr(integer)]
(which it must be to be able to define the discriminants).
But you can read the discriminant using unsafe code, as explained in the documentation:
#[repr(u32)]
enum Command {
Control(ControlSubcommand) = 0x00,
Temperature = 0x02,
Voltage = 0x04,
// ...
}
enum ControlSubcommand {
Status = 0x00,
DeviceType = 0x01,
// ....
}
fn get_discriminant(v: Command) -> u32 {
match v {
Command::Control(v) => v as u32,
// SAFETY: Because of `#[repr(u32)]`, the first field is the `u32` discriminant.
_ => unsafe { *(&v as *const Command as *const u32) },
}
}
Upvotes: 2