How do I use `MaybeUninit` in a `union`?

For some reason I need a MaybeUninit<T> for storing some data (Not using Option because the data availability is stored somewhere else). And when I want to put it into a union (also, the discriminant is stored somewhere else), I was told to use ManuallyDrop. However, after encapsulating the MaybeUninit<T> with ManuallyDrop<MaybeUninit<T>>, I don't know how to apply MaybeUninit::as_ptr with that type. I googled for the web but got nothing valuable. Should I simply use ManuallyDrop::take or std::mem::read or so?

union WrapperData<T> {
    value: ManuallyDrop<MaybeUninit<T>>,
    ptr: *mut T
}

// before calling these functions, avaliability of `value` is checked ahead of time
impl<T> WrapperData<T> {
    pub unsafe fn borrow_value(&mut self) -> *mut T {
        // don't know how to implement here
        unimplemented!()
    }

    pub unsafe fn take_value(&mut self) -> T {
        ManuallyDrop::take(&mut self.value).assume_init()
    }
}

ManuallyDrop implements the Deref and DerefMut traits, so you can call methods on the wrapped type directly:

pub unsafe fn borrow_value(&mut self) -> *mut T {
    self.value.as_mut_ptr()
}

(Playground)

1 Like

You do not need both ManuallyDrop and MaybeUninit. A value wrapped in MaybeUninit is not automatically dropped, and because of this, calling drop on the ManuallyDrop<MaybeUninit<T>> wont do anything, as dropping a MaybeUninit<T> doesn't do anything.

2 Likes

However, you do need ManuallyDrop in order to put a non-Copy type into a union.

You can probably get by with just ManuallyDrop<T> (without the MaybeUninit), but MaybeUninit has a lot of convenient methods that may be useful here.

1 Like