melinoe 0.10.0

Zero-sized, branded, multi-token phantom capabilities for compile-time data-access and thread-synchronization proofs (a generalized evolution of GhostCell) for the Mnemosyne memory ecosystem.
Documentation
use core::sync::atomic::{
    AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
    AtomicU64, AtomicU8, AtomicUsize, Ordering,
};

pub(crate) mod sealed {
    pub trait Sealed {}
}

/// An atomic primitive abstracted over its value type, so [`crate::BrandedAtomic`] is
/// one generic implementation rather than a type-numbered family.
///
/// Sealed: implemented only for the standard-library atomics. The methods are
/// the crate-internal mediation surface; users call [`crate::BrandedAtomic`].
pub trait Atomic: sealed::Sealed {
    /// The plain value carried by this atomic (e.g. `u64` for `AtomicU64`).
    type Value: Copy;

    #[doc(hidden)]
    fn new_atomic(value: Self::Value) -> Self;
    #[doc(hidden)]
    fn atomic_load(&self, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_store(&self, value: Self::Value, order: Ordering);
    #[doc(hidden)]
    fn atomic_swap(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_compare_exchange(
        &self,
        current: Self::Value,
        new: Self::Value,
        success: Ordering,
        failure: Ordering,
    ) -> Result<Self::Value, Self::Value>;
    #[doc(hidden)]
    fn atomic_get_mut(&mut self) -> &mut Self::Value;
    #[doc(hidden)]
    fn atomic_into_inner(self) -> Self::Value;
    /// Pointer to the underlying value for plain (non-atomic) access.
    ///
    /// Sound to dereference only under a proof of exclusivity. An atomic has the
    /// same size/bit-validity as its value and interior mutability, so the cast
    /// is layout-valid and the pointer carries interior-mutable provenance.
    #[doc(hidden)]
    fn value_ptr(&self) -> *mut Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_update<F>(
        &self,
        set_order: Ordering,
        fetch_order: Ordering,
        f: F,
    ) -> Result<Self::Value, Self::Value>
    where
        F: FnMut(Self::Value) -> Option<Self::Value>;
}

/// Integer atomics, which additionally support arithmetic/bitwise RMW.
pub trait AtomicInt: Atomic {
    #[doc(hidden)]
    fn atomic_fetch_add(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_sub(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_and(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_or(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_xor(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_nand(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_max(&self, value: Self::Value, order: Ordering) -> Self::Value;
    #[doc(hidden)]
    fn atomic_fetch_min(&self, value: Self::Value, order: Ordering) -> Self::Value;
}

macro_rules! impl_atomic_base {
    ($atomic:ty, $value:ty) => {
        impl sealed::Sealed for $atomic {}

        impl Atomic for $atomic {
            type Value = $value;

            #[inline]
            fn new_atomic(value: $value) -> Self {
                <$atomic>::new(value)
            }
            #[inline]
            fn atomic_load(&self, order: Ordering) -> $value {
                self.load(order)
            }
            #[inline]
            fn atomic_store(&self, value: $value, order: Ordering) {
                self.store(value, order);
            }
            #[inline]
            fn atomic_swap(&self, value: $value, order: Ordering) -> $value {
                self.swap(value, order)
            }
            #[inline]
            fn atomic_compare_exchange(
                &self,
                current: $value,
                new: $value,
                success: Ordering,
                failure: Ordering,
            ) -> Result<$value, $value> {
                self.compare_exchange(current, new, success, failure)
            }
            #[inline]
            fn atomic_get_mut(&mut self) -> &mut $value {
                self.get_mut()
            }
            #[inline]
            fn atomic_into_inner(self) -> $value {
                self.into_inner()
            }
            #[inline]
            fn value_ptr(&self) -> *mut $value {
                // SAFETY of later deref: same layout as `$value`, interior-mutable.
                core::ptr::from_ref(self).cast::<$value>().cast_mut()
            }
            #[inline]
            fn atomic_fetch_update<F>(
                &self,
                set_order: Ordering,
                fetch_order: Ordering,
                f: F,
            ) -> Result<$value, $value>
            where
                F: FnMut($value) -> Option<$value>,
            {
                self.fetch_update(set_order, fetch_order, f)
            }
        }
    };
}

macro_rules! impl_atomic_int {
    ($atomic:ty, $value:ty) => {
        impl_atomic_base!($atomic, $value);

        impl AtomicInt for $atomic {
            #[inline]
            fn atomic_fetch_add(&self, value: $value, order: Ordering) -> $value {
                self.fetch_add(value, order)
            }
            #[inline]
            fn atomic_fetch_sub(&self, value: $value, order: Ordering) -> $value {
                self.fetch_sub(value, order)
            }
            #[inline]
            fn atomic_fetch_and(&self, value: $value, order: Ordering) -> $value {
                self.fetch_and(value, order)
            }
            #[inline]
            fn atomic_fetch_or(&self, value: $value, order: Ordering) -> $value {
                self.fetch_or(value, order)
            }
            #[inline]
            fn atomic_fetch_xor(&self, value: $value, order: Ordering) -> $value {
                self.fetch_xor(value, order)
            }
            #[inline]
            fn atomic_fetch_nand(&self, value: $value, order: Ordering) -> $value {
                self.fetch_nand(value, order)
            }
            #[inline]
            fn atomic_fetch_max(&self, value: $value, order: Ordering) -> $value {
                self.fetch_max(value, order)
            }
            #[inline]
            fn atomic_fetch_min(&self, value: $value, order: Ordering) -> $value {
                self.fetch_min(value, order)
            }
        }
    };
}

impl_atomic_int!(AtomicUsize, usize);
impl_atomic_int!(AtomicIsize, isize);
impl_atomic_int!(AtomicU32, u32);
impl_atomic_int!(AtomicI32, i32);
#[cfg(target_has_atomic = "64")]
impl_atomic_int!(AtomicU64, u64);
#[cfg(target_has_atomic = "64")]
impl_atomic_int!(AtomicI64, i64);

impl_atomic_int!(AtomicU8, u8);
impl_atomic_int!(AtomicI8, i8);
impl_atomic_int!(AtomicU16, u16);
impl_atomic_int!(AtomicI16, i16);

impl_atomic_base!(AtomicBool, bool);