dambi 0.1.2

Single-threaded (!Send + !Sync) primitives
Documentation
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;

pub struct LocalCell<T> {
    inner: UnsafeCell<T>,
}

impl<T> LocalCell<T> {
    #[must_use]
    pub const fn new(value: T) -> Self {
        Self {
            inner: UnsafeCell::new(value),
        }
    }

    pub fn get(&self) -> &T {
        unsafe { &*self.inner.get() }
    }

    #[allow(clippy::mut_from_ref)]
    pub fn get_mut(&self) -> &mut T {
        unsafe { &mut *self.inner.get() }
    }

    pub fn as_ptr(&self) -> *mut T {
        self.inner.get()
    }
}

#[repr(transparent)]
pub struct AlwaysInit<T>(MaybeUninit<T>);

impl<T> AlwaysInit<T> {
    #[inline(always)]
    pub const fn new(t: T) -> Self {
        Self(MaybeUninit::new(t))
    }

    #[inline(always)]
    pub fn write(&mut self, t: T) {
        self.0.write(t);
    }

    #[inline(always)]
    pub fn get(&self) -> &T {
        // SAFETY: caller's container must `new`/`write` before observing,
        // and never observe after `drop_in_place`.
        unsafe { self.0.assume_init_ref() }
    }

    #[inline(always)]
    pub fn get_mut(&mut self) -> &mut T {
        // SAFETY: see `get`.
        unsafe { self.0.assume_init_mut() }
    }

    /// # Safety
    ///
    /// Caller must ensure `self` is not read after this call.
    #[inline(always)]
    pub unsafe fn drop_in_place(&mut self) {
        unsafe { self.0.assume_init_drop() }
    }
}

impl<T: Default> Default for AlwaysInit<T> {
    #[inline(always)]
    fn default() -> Self {
        Self::new(T::default())
    }
}