pub enum Foo {
A(u30),
B(u30),
C(u30),
}
Is it possible to define this and have Foo take up only 8 bits? (I am trying to avoid using a u32 & manually doing big manipulations).
pub enum Foo {
A(u30),
B(u30),
C(u30),
}
Is it possible to define this and have Foo take up only 8 bits? (I am trying to avoid using a u32 & manually doing big manipulations).
Nope, AFAICT bit twiddling is your only option here.
Note that you can define a newtype to contain the bit twiddling:
(untested)
#[derive(Copy,Clone)]
pub struct PackedFoo(u32);
impl From<Foo> for PackedFoo {
fn from(foo:Foo) {
let (tag, arg): (u32, u32) = match foo {
Foo::A(x) => (0, x),
Foo::B(x) => (1, x),
Foo::C(x) => (2, x)
};
assert!(arg < (1 << 30));
PackedFoo((tag << 30) | arg)
}
)
impl From<PackedFoo> for Foo {
fn from(packed:PackedFoo) -> Self {
let tag = packed.0 >> 30;
let arg = packed.0 ^ (tag << 30);
match tag {
0 => Self::A(arg),
1 => Self::B(arg),
2 => Self::C(arg),
_ => panic!("Unknown tag!")
}
}
}
In fact that enum will take up 1 byte for the discriminant as well as the space for the variant fields. So for a u32 field a value of Foo would take 5 bytes.
Frankly it's very doubtful that the bit twiddling being suggested here has a real payoff unless you're on severely constrained hardware. If you're not on constrained hardware it's a lot easier and faster to just consume the extra 2 bits of space you'd otherwise be saving per enum value.
There will also be 3 bytes of pading to get the u32 alignment right, for a total of 8. That’s a factor of 2, which could be significant if there are a large number of these or memory space is at a premium on the target architecture. In the normal case, however, I agree that simply using the enum is probably the right choice.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.