Strong updates status

Indeed, for types Foo<T> that have an indirection to the type T we want to update (otherwise no need for strong update), that are cheap to deconstruct and reconstruct (size_of::<Foo<T>>() is small), and store the type T in a way that only cares about layout, we can use strong update between Foo<MaybeUninit<T>> and Foo<T> to the cost of deconstructing and reconstructing (which may be optimized out).

However, I'm not convinced by the benefit. This permits to have init be a safe function. But to call it you need to provide the initializing closure, which needs to use unsafe because it will call assume_init_mut(). So it's not clear to me why prefer this compared to what we would do now:

/// Safety: f must initialize its argument
unsafe fn init(xs: Vec<MaybeUninit<T>>, f: impl FnMut(&mut MaybeUninit<T>)) -> Vec<T>

With strong updates the user may use an init function of the type (uninit here means the contents of the box are uninitialized):

let uninitial = Box::uninit();
let initalized = uninital.init(Foo::init);

But still such a general Foo::init api is rare (Huge structs/arrays, can't find any other use). Even for self-referential structs, constructed in-place behind a Pin, an unsafe api is ok, as self references currently require raw pointers. I think strong updates only truly shine together with other language features (at least partial types, where the prior could fully be safe ([T{} -> T]), but also some implementation of safe self references).

Alternatively rust could treat MaybeUninit specially and guarantee same layout of C<MaybeUninit<T>> and C<T>. That way an in place api is possible:

fn init(xs: &@a mut Vec<MaybeUninit<T>>, f: impl FnMut(&@b mut MaybeUninit<T>) -> &@b mut T) -> &@a mut Vec<T>

Similarly with repr(transparent) we could define the order, take any #[repr(transparent)] struct T, that contains S, as it is stored as an S, it has to be a valid S, [S..T] is possible. As a union MaybeUninit still is a special case, here the compiler needs to know that any T is a valid MaybeUninit<T> ([MaybeUninit<T>..T]). We cannot know that for any union, as it may arbitrarily constrain any variant. (Also it actually contains a ManuallyDrop<T>)

This is probably impossbile to implement. Option<NonZeroU32> relies on NonZeroU32 never having an all-zeroes bit pattern to work correctly. If Option<MaybeUninit<NonZeroU32>> were forced to have the same representation, then it would likewise rely on MaybeUninit<NonZeroU32> never having an all-zeroes bit pattern. But there are numerous safe APIs that would make it possible to put an all-zeroes bit pattern into a MaybeUninit<NonZeroU32> (because MaybeUninit is intended to be able to hold arbitrary bit patterns and the APIs are designed around that).

What you'd want instead is something that works like MaybeUninit but copies validity invariants from the wrapped type, i.e. it is capable of holding any sequence of bits that could be valid for a value of that type. This would probably require some sort of DefaultUninit trait that defined an arbtrary bit pattern for the type that was at least compatible with its validity invariants, even if it wasn't a valid alue of the type (e.g. the all-0s bit pattern is not a valid bit pattern for &'static u64, but 0x8 has a valid sort of bit pattern for the type even though it's unlikely to actually be a valid &'static u64 value).

Oh, forgot about niches, that makes things a lot more complicated. This applies to all cases: [Option<u8>..Option<NonZeroU8>] is also impossible because of it. So it would have to be way more specific, just have the types behind pointers (raw, NonNull, ref, etc.) not affect layout. That would make all Boxes, Vecs, etc. the same layout and enable remote init.

Thanks for the note, this is something I should consider for partial types (T{} needs to check for niches).