Skip to content

Instantly share code, notes, and snippets.

@WorldSEnder
Last active June 21, 2023 23:53
Show Gist options
  • Save WorldSEnder/e6d4bebe8cc5a03c84c791ec81712c7f to your computer and use it in GitHub Desktop.
Save WorldSEnder/e6d4bebe8cc5a03c84c791ec81712c7f to your computer and use it in GitHub Desktop.
use core::mem::ManuallyDrop;
use core::ops::DerefMut;
use core::ops::Deref;
use core::mem::MaybeUninit;
/// Represents an initialized MaybeUninit. The contained value is dropped with this
/// evidence.
///
/// Safety: The referenced MaybeUninit is initialized
struct SurelyInit<'u, T>(&'u mut MaybeUninit<T>);
impl<'u, T> SurelyInit<'u, T> {
/// Writes a value into the MaybeUninit and returns evidence of initialization.
/// Any previous value is overwritten without its drop impl being called.
fn init(this: &'u mut MaybeUninit<T>, value: T) -> Self {
this.write(value);
// Safety: the MaybeUninit has been initialized.
unsafe { Self::assume_init(this) }
}
/// Safety: must ensure that the MaybeUninit is initialized
unsafe fn assume_init(this: &'u mut MaybeUninit<T>) -> Self {
// Safety: by the caller contract
Self(this)
}
/// Reads the value from the underlying MaybeUninit and "deinitializes" it.
fn take(self) -> T {
// We will shortly replace the contents destructively. Make sure no drop happens
// on the uninitialized replacement
let mut this = ManuallyDrop::new(self);
// Allow the compiler to replace the old value with any garbage.
// Subtly, this also allows the compiler to omit the copy all together and overwrite
// and destructively consume whatever value exists here
let old = std::mem::replace(this.0, MaybeUninit::uninit());
// Safety: The old value is assumed to have been initialized
// The value read is not dropped twice.
unsafe { old.assume_init() }
}
}
impl<'u, T> Deref for SurelyInit<'u, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.0.assume_init_ref() }
}
}
impl<'u, T> DerefMut for SurelyInit<'u, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.0.assume_init_mut() }
}
}
impl<'u, T> Drop for SurelyInit<'u, T> {
fn drop(&mut self) {
unsafe { self.0.assume_init_drop() }
}
}
pub fn main() {
let mut place: MaybeUninit<u32> = MaybeUninit::uninit();
{
let mut init = SurelyInit::init(&mut place, 42);
assert_eq!(*init, 42);
*init += 10;
assert_eq!(init.take(), 52);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment