I have two structs, which both only need 7 bits to represent themselves:
#[repr(transparent)]
struct TypeFlags(u8);
// TypeFlags has capabilities that are invalid for Control
impl std::ops::BitOr for TypeFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
#[repr(transparent)]
struct Control(u8);
Since both types only need 7 bits, an "Either" type could be created which only occupies one byte.
// problem: the compiler sets aside
// a "flag" byte for the enum variant.
// size = 2
enum Either {
Type(TypeFlags),
Ctrl(Control)
}
// problem: pattern matching is painful
struct PackedEither(u8);
Are there any sub-byte optimizations for enum that I can take advantage of, or will I have to manually implement the bit flag on a struct like PackedEither?
The compiler is not able to make that optimization, but for the sake of argument let's assume the compiler were to make it and lets say
TypeFlagsgets stored as0b0xxx_xxxxandControlas0b1xxx_xxx.Now here is the problem:
In Rust we can match on a reference to
Eitherand get references to the contained values:Now the compiler would have to produce code, that references a value of
Controlbut, it does not store that anywhere in memory it only stores a "Control | 0b1000_0000".Sadly even if we were to use standard library internal attributes to programatically change the range of
TypeFlagsto0..128andControlto128..256, it still does not use the nieche like we want and optimize to a single byte.