Size of the type Result<Vec<u64>, u64>

std::mem::size_of::<Result<Vec<u64>, u64>>() says that Result<Vec<u64>, u64> has a size of 24 bytes. However, Vec<u64> already has a size of 24 bytes. Result is an Enum type which uses a tag to distinguish the type. How does Rust compile manage to get rid of the tag in this case?

It's called a niche optimization. It's possible because the pointer in Vec is always non-null, and so a value of 0 there means that the result is an Err.

2 Likes

Vec<u64> contains (ptr, len, capacity) where ptr is non-null. So you can use nullptr as magic tag.

fn main() {
    dbg!(std::mem::size_of::<Vec<u64>>());  // 24
    dbg!(std::mem::size_of::<Option<Vec<u64>>>());  // 24
    dbg!(std::mem::size_of::<Option<Option<Vec<u64>>>>());  // 32
}

For detail, Vec<T> contains a NonNull<T> which is annotated with #[rustc_layout_scalar_valid_range_start(1)] which enable the niche optimization.

1 Like

See also std::ptr::NonNull and std::num::NonZeroUsize, for example.

1 Like