About `MaybeUninit::uninit().assume_init()`

55 points Spengleberb 32 comments

In the popular arrayvec crate, the definition of ArrayVec and the implementation for ArrayVec::new() (see here) are as follows:

#[repr(C)]
pub struct ArrayVec<T, const CAP: usize> {
    len: LenUint,
    // the `len` first elements of the array are initialized
    xs: [MaybeUninit<T>; CAP],
}

// ...

impl<T, const CAP: usize> ArrayVec<T, CAP> {

    pub fn new() -> ArrayVec<T, CAP> {
        assert_capacity_limit!(CAP);
        unsafe {
            ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
        }
    }


    // ...

But the docs for MaybeUninit::assume_init() (see here) say:

Calling this when the content is not yet fully initialized causes immediate undefined behavior.

So what am I missing here? There's no safety comment, and I can't see any relevant bounds or invariants (I think assert_capacity_limit!(CAP) just asserts that the capacity is less than the platform's pointer width, so that doesn't seem relevant either).

Why is this valid?