Niche optimization
- Rust course
- Expert
- Lesson 11/46
- 4 min
Shrink enum size with niche optimization.
Niche optimization
Some types have bit patterns that are never used: &T and Box<T> are never null, bool is only 0 or 1, NonZeroU32 can't be 0, and char lies outside certain ranges. The compiler uses these "niches" to store the enum discriminant, so Option needs no extra byte:
size_of::<Option<&u8>>() // 8: None = null pointer
size_of::<Option<NonZeroU32>>() // 4: None = 0
size_of::<Option<u32>>() // 8: u32 has no unused pattern
size_of::<Option<bool>>() // 1: None = 2A niche in your own type
Holding ids as NonZeroU32 lets you express the "invalid id" case with Option for free:
use std::num::NonZeroU32;
struct KullaniciId(NonZeroU32);
let id = NonZeroU32::new(42).map(KullaniciId); // Some
let bos = NonZeroU32::new(0); // None
println!("{}", size_of::<Option<KullaniciId>>()); // 4Niches work when nested too: Option<Option<bool>> is still 1 byte.
Practice Niche sizes
Print the size_of values of Option<&u8>, Option<NonZeroU32>, Option<u32> and Option<bool> on one line separated by spaces.
Starter code
use std::mem::size_of;
use std::num::NonZeroU32;
fn main() {
// buraya yaz
}Sample solution
use std::mem::size_of;
use std::num::NonZeroU32;
fn main() {
println!(
"{} {} {} {}",
size_of::<Option<&u8>>(),
size_of::<Option<NonZeroU32>>(),
size_of::<Option<u32>>(),
size_of::<Option<bool>>()
);
}Expected output
8 4 8 1
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Why can <code>Option<Box<T>></code> be used in FFI in place of C's nullable pointer?
- Box exists in C
- It can't be
- It's always 16 bytes
- None is guaranteed to be represented as a null pointer Correct answer
Explanation: This is one of a few documented niche guarantees: Option<&T>, Option<Box<T>>, Option<NonNull<T>>, Option<extern fn>.
2 Non-zero integer
use std::num::____;
let id = NonZeroU32::new(42); // Some(42)
use std::num::NonZeroU32;
let id = NonZeroU32::new(42); // Some(42)
Explanation: NonZeroU32 can't be 0, so Option<NonZeroU32> is 4 bytes.
3 Type and size (64-bit)
| Term | Meaning |
|---|---|
Option<&u8> |
8 |
Option<NonZeroU32> |
4 |
Option<u32> |
8 (extra tag) |
Option<bool> |
1 |