Wrapping a NonZeroUsize in a new type

Viewed 222

I have read that Option<NonZeroUsize> occupies exactly one word of memory, like usize.

I would like to combine this with the new type idiom. I would like to define struct Pos(NonZeroUsize), so that the compiler prevents me from confusing a Pos with any other NonZeroUsize, but without losing the compact representation.

Will Option<Pos> occupy exactly one word of memory?

1 Answers

By default, while the compiler is likely to be able to optimize the size of Option<Pos>, types without a #[repr] annotation have no guarantees about memory layout:

The Default Representation
Nominal types without a repr attribute have the default representation. Informally, this representation is also called the rust representation.

There are no guarantees of data layout made by this representation.

However, you can specify #[repr(transparent)] to force Pos to have the same layout as its singular field:

#[repr(transparent)]
struct Pos(NonZeroUsize);

The transparent Representation
The transparent representation can only be used on a struct or an enum with a single variant that has:

  • a single field with non-zero size, and
  • any number of fields with size 0 and alignment 1 (e.g. PhantomData).

Structs and enums with this representation have the same layout and ABI as the single non-zero sized field.

Then Option<Pos> will always have the same size as NonZeroUsize, per points 5 and 7 in this list:

Option Representation
Rust guarantees to optimize the following types T such that Option<T> has the same size as T:

  1. Box<U>
  2. &U
  3. &mut U
  4. fn, extern "C" fn
  5. num::NonZero*
  6. ptr::NonNull<U>
  7. #[repr(transparent)] struct around one of the types in this list.
Related