Niche optimization allows Rust to store data in the invalid bit patterns of a type. The only valid values of a bool are 0 and 1 (one bit). And Result only has two variants (one bit). So why does Result<bool, bool> take two bytes instead of 1? I would expect the first bit to be the bool value and the second to be the Result variant, as is the case with Option<bool>, which does does indeed have size 1. It seems that giving the second variant a payload, even when it's the same size as the first variant’s payload, affects niche optimization, but I don't see why that would be the case.
Because the payload of an enum variant has to be individually addressable, at addressing unit (i.e. byte) granularity.
Take this example:
fn change(b: &mut bool); // opaque
fn get_changed(mut r: Result<bool, bool>) -> Result<bool, bool> {
match r {
Ok(ref mut b) => change(b),
Err(ref mut b) => change(b),
};
r
}
change must be able to manipulate the borrowed bool without knowing it is actually embedded within a Result<_, _> and has to have some of its bits preserved. For example, change may perform a bytewise memory copy into the place borrowed by b.
For a more drastic example:
fn swap_payloads(r: &mut Result<bool, bool>, s: &mut Result<bool, bool>) {
let a: &mut bool = match r { Ok(x) => x, Err(x) => x, };
let b: &mut bool = match s { Ok(x) => x, Err(x) => x, };
std::mem::swap(a, b);
}
std::mem::swap performs a bytewise swap. If Result<bool, bool> were packed into a single byte, std::mem::swap would have swapped not just payloads, but discriminants as well.
For this reason, the payload of a Result<bool, bool> must be stored at a distinct address from the discriminant.
There have been discussions about adding a feature that can prohibit referencing sub-fields within a data type, so that this optimization can happen (e.g. https://internals.rust-lang.org/t/towards-even-smaller-structs/14686/), but it seems none have come to fruition as of 2025.
Because you can take a reference to the bool, and give it to code that knows nothing about the original type. Therefore the value of the whole byte of bool must be 1 or 0, it cannot be anything else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With