potential-well 3.0.0

Atomic boxes.
Documentation
//! Atomic primitive implementations.
use core::{
    ptr,
    ptr::NonNull,
    sync::atomic::{AtomicPtr, Ordering, fence},
};

/// Converts `Option<NonNull<T>>` to `*mut T`.
pub(crate) fn from_nullable<T>(ptr: Nullable<T>) -> *mut T {
    ptr.map_or(ptr::null_mut(), NonNull::as_ptr)
}
/// Converts `*mut T` to `Option<NonNull<T>>`.
pub(crate) fn into_nullable<T>(ptr: *mut T) -> Nullable<T> {
    NonNull::new(ptr)
}

/// Sometimes not null.
pub(crate) type Nullable<T> = Option<NonNull<T>>;

/// Type-generic, nullable atomic primitive.
#[repr(transparent)]
pub(crate) struct AtomicOption<T>(AtomicPtr<T>);
impl<T> AtomicOption<T> {
    /// Create with pointer.
    #[inline]
    pub(crate) fn new(ptr: Nullable<T>) -> AtomicOption<T> {
        AtomicOption(AtomicPtr::new(from_nullable(ptr)))
    }

    /// Gives access to the underlying [`AtomicPtr`].
    #[inline]
    #[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
    pub(crate) fn as_raw(&self) -> &AtomicPtr<T> {
        &self.0
    }

    /// Raw atomic [`load`].
    ///
    /// [`load`]: AtomicPtr::load
    #[inline]
    pub(crate) fn load(&self, ordering: Ordering) -> Nullable<T> {
        into_nullable(self.0.load(ordering))
    }

    /// Raw mutable borrow.
    #[inline]
    pub(crate) fn get_mut(&mut self) -> Nullable<T> {
        into_nullable(*self.0.get_mut())
    }

    /// Raw atomic [`swap`]
    ///
    /// [`swap`]: AtomicPtr::swap
    #[inline]
    pub(crate) fn swap(&self, ptr: Nullable<T>, ordering: Ordering) -> Nullable<T> {
        into_nullable(self.0.swap(from_nullable(ptr), ordering))
    }

    /// Raw atomic [`compare_exchange`].
    ///
    /// [`compare_exchange`]: AtomicPtr::compare_exchange
    #[inline]
    pub(crate) fn compare_exchange(
        &self,
        current: Nullable<T>,
        new: Nullable<T>,
        success: Ordering,
        failure: Ordering,
    ) -> Result<Nullable<T>, Nullable<T>> {
        self.0
            .compare_exchange(from_nullable(current), from_nullable(new), success, failure)
            .map(into_nullable)
            .map_err(into_nullable)
    }

    /// Raw atomic [`compare_exchange_weak`].
    ///
    /// [`compare_exchange_weak`]: AtomicPtr::compare_exchange_weak
    #[inline]
    pub(crate) fn compare_exchange_weak(
        &self,
        current: Nullable<T>,
        new: Nullable<T>,
        success: Ordering,
        failure: Ordering,
    ) -> Result<Nullable<T>, Nullable<T>> {
        self.0
            .compare_exchange(from_nullable(current), from_nullable(new), success, failure)
            .map(into_nullable)
            .map_err(into_nullable)
    }

    /// Relaxed load for debugging.
    #[inline]
    pub(crate) fn load_debug(&self) -> Nullable<T> {
        self.load(Ordering::Relaxed)
    }

    /// Fenced load for dropping.
    #[inline]
    pub(crate) fn load_drop(&mut self) -> Nullable<T> {
        fence(Ordering::SeqCst);
        self.load(Ordering::SeqCst)
    }
}

/// Type-generic, non-nullable atomic primitive.
#[repr(transparent)]
pub(crate) struct Atomic<T>(AtomicOption<T>);
impl<T> Atomic<T> {
    /// Create with pointer.
    #[inline]
    pub(crate) fn new(ptr: NonNull<T>) -> Atomic<T> {
        Atomic(AtomicOption::new(Some(ptr)))
    }

    /// Gives access to the underlying [`AtomicPtr`].
    #[inline]
    #[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
    pub(crate) fn as_raw(&self) -> &AtomicPtr<T> {
        self.0.as_raw()
    }

    /// Raw atomic [`load`].
    ///
    /// [`load`]: AtomicPtr::load
    #[inline]
    pub(crate) fn load(&self, ordering: Ordering) -> NonNull<T> {
        // SAFETY: We never store null pointers.
        unsafe { self.0.load(ordering).unwrap_unchecked() }
    }

    /// Raw mutable borrow.
    #[inline]
    pub(crate) fn get_mut(&mut self) -> NonNull<T> {
        // SAFETY: We never store null pointers.
        unsafe { self.0.get_mut().unwrap_unchecked() }
    }

    /// Raw atomic [`swap`]
    ///
    /// [`swap`]: AtomicPtr::swap
    #[inline]
    pub(crate) fn swap(&self, ptr: NonNull<T>, ordering: Ordering) -> NonNull<T> {
        // SAFETY: We never store null pointers.
        unsafe { self.0.swap(Some(ptr), ordering).unwrap_unchecked() }
    }

    /// Raw atomic [`compare_exchange`].
    ///
    /// [`compare_exchange`]: AtomicPtr::compare_exchange
    #[inline]
    #[expect(dead_code)]
    pub(crate) fn compare_exchange(
        &self,
        current: NonNull<T>,
        new: NonNull<T>,
        success: Ordering,
        failure: Ordering,
    ) -> Result<NonNull<T>, NonNull<T>> {
        // SAFETY: We never store null pointers.
        unsafe {
            match self
                .0
                .compare_exchange(Some(current), Some(new), success, failure)
            {
                Ok(ptr) => Ok(ptr.unwrap_unchecked()),
                Err(ptr) => Err(ptr.unwrap_unchecked()),
            }
        }
    }

    /// Raw atomic [`compare_exchange_weak`].
    ///
    /// [`compare_exchange_weak`]: AtomicPtr::compare_exchange_weak
    #[inline]
    #[expect(dead_code)]
    pub(crate) fn compare_exchange_weak(
        &self,
        current: NonNull<T>,
        new: NonNull<T>,
        success: Ordering,
        failure: Ordering,
    ) -> Result<NonNull<T>, NonNull<T>> {
        // SAFETY: We never store null pointers.
        unsafe {
            match self
                .0
                .compare_exchange_weak(Some(current), Some(new), success, failure)
            {
                Ok(ptr) => Ok(ptr.unwrap_unchecked()),
                Err(ptr) => Err(ptr.unwrap_unchecked()),
            }
        }
    }

    /// Relaxed load for debugging.
    #[inline]
    pub(crate) fn load_debug(&self) -> NonNull<T> {
        // SAFETY: We never store null pointers.
        unsafe { self.0.load_debug().unwrap_unchecked() }
    }

    /// Fenced load for dropping.
    #[inline]
    pub(crate) fn load_drop(&mut self) -> NonNull<T> {
        // SAFETY: We never store null pointers.
        unsafe { self.0.load_drop().unwrap_unchecked() }
    }
}