oncelock 0.1.0-alpha.0

A fast and simple implementation of OnceLock
Documentation
#![cfg_attr(missing_sync_backend, allow(unused))]

#[cfg(not(has_maybe_uninit))]
pub use self::fallback_untagged_option::UntaggedOptionCell;
#[cfg(has_maybe_uninit)]
pub use self::modern_untagged_option::UntaggedOptionCell;

#[cfg(has_maybe_uninit)]
#[cfg_attr(has_maybe_uninit, clippy::msrv = "1.36")]
mod modern_untagged_option {
    use core::cell::UnsafeCell;
    use core::mem::MaybeUninit;

    /// An [`UnsafeCell<Option<T>>`] where the tag is not actually stored.
    ///
    /// On versions where [`MaybeUninit`] is supported,
    /// this is equivalent to a `Cell<MaybeUninit<T>>`.
    /// Using uninitialized memory directly, without a `MaybeUninit`,
    /// has massive potential to cause undefined behavior.
    /// For this reason, on versions where [`MaybeUninit`] is unsupported,
    /// this emulates [`MaybeUninit`] behavior using an `Option`.
    ///
    /// This is not guaranteed to be `#[repr(transparent)`] due to emulation on old versions.
    ///
    /// Cannot directly emulate [`MaybeUninit`],
    /// because [`Self::assume_present`] is immediately undefined behavior when uninitialized,
    /// where [`MaybeUninit::as_ptr`] is only UB if the pointer is actually dereferenced.
    pub struct UntaggedOptionCell<T>(UnsafeCell<MaybeUninit<T>>);
    impl<T> UntaggedOptionCell<T> {
        #[inline]
        pub const fn uninit() -> Self {
            UntaggedOptionCell(UnsafeCell::new(MaybeUninit::uninit()))
        }

        /// Initialize the value to the specified value,
        /// discarding any previous value.
        ///
        /// # Safety
        /// Undefined behavior if a data race occurs.
        #[inline]
        pub unsafe fn write(&self, value: T) {
            // SAFETY: Caller guarantees mutation is valid
            unsafe { self.0.get().write(MaybeUninit::new(value)) }
        }

        /// Assume the value is present, and get a pointer to it.
        ///
        /// # Safety
        /// Immediate undefined behavior if the option is not
        #[inline]
        pub const fn get_ptr_unchecked(&self) -> *mut T {
            self.0.get() as *mut T
        }
    }
}
#[allow(clippy::missing_safety_doc)] // same behavior as 'modern' type
#[cfg(not(has_maybe_uninit))]
mod fallback_untagged_option {
    use core::cell::UnsafeCell;
    use core::mem::ManuallyDrop;
    use crate::polyfill::UncheckedUnwrap;

    // NOTE: Need ManuallyDrop for consistency with MaybeUninit
    pub struct UntaggedOptionCell<T>(UnsafeCell<ManuallyDrop<Option<T>>>);
    impl<T> UntaggedOptionCell<T> {
        #[inline]
        #[rustversion::attr(since(1.32), const)] // UnsafeCell::new, ManuallyDrop::new
        pub fn uninit() -> Self {
            UntaggedOptionCell(UnsafeCell::new(ManuallyDrop::new(None)))
        }

        #[inline]
        pub unsafe fn write(&self, value: T) {
            // SAFETY: Caller guarantees mutation is valid
            unsafe { core::ptr::write(self.0.get(), ManuallyDrop::new(Some(value))) }
        }

        #[inline]
        pub unsafe fn get_ptr_unchecked(&self) -> *mut T {
            // SAFETY: Caller guarantees not being concurrently mutated
            let opt: &Option<T> = unsafe { &*self.0.get() };
            // SAFETY: Caller guarantees data is initialized
            unsafe { opt.as_ref().polyfill_unwrap_unchecked() as *const T as *mut T }
        }
    }
}

pub trait UncheckedUnwrap<T> {
    /// Assume that the specified value is `Some`,
    /// triggering undefined behavior if not.
    ///
    /// # Safety
    /// Undefined behavior if `None`.
    unsafe fn polyfill_unwrap_unchecked(self) -> T;
}
impl<T> UncheckedUnwrap<T> for Option<T> {
    //noinspection RsReplaceMatchExpr
    #[inline]
    unsafe fn polyfill_unwrap_unchecked(self) -> T {
        #[cfg(debug_assertions)]
        assert!(self.is_some());
        match self {
            Some(x) => x,
            None => {
                // SAFETY: Responsibility of caller
                unsafe { core::hint::unreachable_unchecked() }
            }
        }
    }
}

pub trait FinishNonExhaustive {
    fn polyfill_finish_non_exhaustive(&mut self) -> core::fmt::Result;
}
macro_rules! do_impl_non_exhaustive {
    ($($target:ident),*) => {
        $(impl FinishNonExhaustive for core::fmt::$target<'_, '_> {
            #[rustversion::since(1.53)]
            fn polyfill_finish_non_exhaustive(&mut self) -> core::fmt::Result {
                self.finish_non_exhaustive()
            }
            #[rustversion::before(1.53)]
            fn polyfill_finish_non_exhaustive(&mut self) -> core::fmt::Result {
                self.finish()
            }
        })*
    };
}
do_impl_non_exhaustive!(DebugStruct);