U30? in enum to save bits

pub enum Foo {

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:


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.