I need an integral type that as a predefined limited range that includes 0, and want to implement like this:
#[repr(u8)]
pub enum X { A, B, C, D, E, F, G, H }
impl From<u8> for X {
fn from(x: u8) -> X {
unsafe { std::mem::transmute(x & 0b111) }
}
}
When I need the integer value, I would cast with as u8. Arithmetic ops would be implemented by casting to u8 then converting back into the enum using from. And because I limit the range with the bitand when converting from u8 to the enum, I'm always in range of the enum.
Some benefits I can see are that the range is known to the compiler so it can skip bounds checking, and enum optimizations such as representing Option<X> as 1 byte.
A drawback I can see via assembly is that I incur and al, 7 every time I convert to enum, but I can live with that.
Is this a sound transmutation of u8 into the enum? What are other drawbacks of representing a limited range integer this way, if any?
I don't think there is anything wrong with this transmutation, in that it is likely sound. However, I believe it is unnecessary.
If performance is critical for your application, you should test on your target arch, but I used the Rust playground to show the generated ASM (for whatever arch the playground runs on):
Your version:
Explicit match:
The resulting assembly (from the playground at least) is: