Usage of enum-types is inherent in Rust, usually causing additional overhead due to the enum-discriminator. But, there are a number of optimizations that may eliminate this memory overhead. The following is just a cheatsheet. For further reading see https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html
Data-Less and Uninhabited fields
Introduced by MR https://github.com/rust-lang/rust/pull/45225
Size optimizations implemented so far:
- ignoring uninhabited variants (i.e. containing uninhabited fields), e.g.:
Option<!>
is 0 bytesResult<T, !>
has the same size asT
- using arbitrary niches, not just
0
, to represent a data-less variant, e.g.:Option<bool>
,Option<Option<bool>>
,Option<Ordering>
are all 1 byteOption<char>
is 4 bytes
- using a range of niches to represent multiple data-less variants, e.g.:
enum E { A(bool), B, C, D }
is 1 byte
An integer that is known not to equal zero.
See https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html
This enables some memory layout optimization. For example, Option<NonZeroUsize>
is the same size as usize
:
use std::mem::size_of;
assert_eq!(size_of::<Option<core::num::NonZeroUsize>>(), size_of::<usize>());
And analogous to it all other NonZero types https://doc.rust-lang.org/std/num/index.html
Please note, using an optimized Option<NonZeroX>
, its enum-discriminator will be one of the ‘unused’ bit-combinations in the underlying integer representation, for example the bit combination all zero representing state Option::None
.