Enum Size Optimization

I have an enum that I would like to be as small as possible.
I was under the impression that Rust was smart enough to make the following enum take up only two bytes.
Since both Fish and Shark have the same large number of unused values in LastMoved rustc could use them as a niche to store the discriminant for Cell. Sadly size_of informs me that Cell needs 3 bytes. Am I missing something or is rustc missing a opportunity to make the enum smaller?

enum Cell {
    Empty,
    Fish(Fish),
    Shark(Shark),
}
struct Fish {
  moved: LastMoved,
  age: u8,
}
struct Shark {
  moved: LastMoved,
  energy: u8,
}
enum LastMoved {
  Even,
  Odd,
  Never,
}

The problem why Rust cannot optimize this further implicitly is that Rust allows you to get a &LastMoved reference from a &Cell. This can only work if the byte representing the LastMoved value already exists as-is in the cell, for each of the Fish and Shark variant, (and uses the same byte values for the LastMoved data in both cases) leaving no room for any flags to distinguish the two.

I can imagine there's maybe some potential for opting into further optimizations whilst disabling the ability to take a reference to the field (similar to how packed structs prevent references to some fields), but that's a language feature we don't currently have, so you'd need to implement the encoding and decoding of the relevant variants into a single byte yourself.

4 Likes

Thanks that is exactly what I was missing.