generic-atomics 0.1.0

Generic Atomic types for types that implement num-primitive traits
Documentation
use crate::{atomic_float_wrapper::AtomicFloatWrapper, AtomicNumber};
use atomic_traits::{
    fetch::{self, And, Nand, Or, Update, Xor},
    AsPtr, Atomic, Bitwise, FromPtr,
};
use core::sync::atomic::{
    AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64,
    AtomicU8, AtomicUsize,
    Ordering::{self},
};
use num_primitive::PrimitiveNumber;
use num_traits::FromPrimitive;

pub trait AtomicNumberTraitBounds<N>:
    Atomic<Type = N> + Bitwise + AsPtr + FromPtr + fetch::Update<Type = <Self as Atomic>::Type>
{
}
impl<AN, N> AtomicNumberTraitBounds<N> for AN where
    AN: Atomic<Type = N> + Bitwise + AsPtr + FromPtr + fetch::Update<Type = <Self as Atomic>::Type>
{
}

pub(crate) trait PrimitiveAtomicNumber: PrimitiveNumber + IntoAtomicNumber {}
impl<T> PrimitiveAtomicNumber for T where T: PrimitiveNumber + IntoAtomicNumber {}

// this is basically the same as PrimitiveAtomic in unstable std
// but because f also want to use atomic floats its
pub trait IntoAtomicNumber: Sized + FromPrimitive {
    type AN: AtomicNumberTraitBounds<Self> + Send;
    fn into_atomic_number(self) -> impl AtomicNumberTraitBounds<Self> {
        Self::AN::new(self)
    }
}

macro_rules! impl_into_atomic_number {
    ($type:ty, $atomic:ty) => {
        impl IntoAtomicNumber for $type {
            type AN = $atomic;
        }
    };
}

impl_into_atomic_number!(i8, AtomicI8);
impl_into_atomic_number!(i16, AtomicI16);
impl_into_atomic_number!(i32, AtomicI32);
impl_into_atomic_number!(i64, AtomicI64);
impl_into_atomic_number!(isize, AtomicIsize);
// impl_into_atomics!(i128, AtomicI128);
impl_into_atomic_number!(u8, AtomicU8);
impl_into_atomic_number!(u16, AtomicU16);
impl_into_atomic_number!(u32, AtomicU32);
impl_into_atomic_number!(u64, AtomicU64);
impl_into_atomic_number!(usize, AtomicUsize);
// impl_into_atomics!(u128, AtomicU128);
impl_into_atomic_number!(f64, AtomicFloatWrapper<f64>);
impl_into_atomic_number!(f32, AtomicFloatWrapper<f32>);

// SAFETY: We only ever access the underlying data by refcasting to AtomicU*,
// which guarantees no data races.
#[expect(unsafe_code)]
unsafe impl<F: PrimitiveAtomicNumber> Send for AtomicNumber<F> {}
#[expect(unsafe_code)]
unsafe impl<F: PrimitiveAtomicNumber> Sync for AtomicNumber<F> {}

impl<T> Atomic for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    type Type = T;

    #[inline(always)]
    fn new(number: T) -> Self {
        Self {
            atomic: T::AN::new(number),
        }
    }

    #[inline(always)]
    fn get_mut(&mut self) -> &mut T {
        self.atomic.get_mut()
    }

    #[inline(always)]
    fn into_inner(self) -> T {
        self.atomic.into_inner()
    }

    #[inline(always)]
    fn load(&self, ordering: Ordering) -> T {
        self.atomic.load(ordering)
    }

    #[inline(always)]
    fn store(&self, value: T, ordering: Ordering) {
        self.atomic.store(value, ordering);
    }

    #[inline(always)]
    fn swap(&self, new_value: T, ordering: Ordering) -> T {
        self.atomic.swap(new_value, ordering)
    }

    #[inline(always)]
    #[expect(deprecated)]
    fn compare_and_swap(&self, current: T, new: T, order: Ordering) -> T {
        self.atomic.compare_and_swap(current, new, order)
    }

    #[inline(always)]
    fn compare_exchange(
        &self,
        current: T,
        new: T,
        success: Ordering,
        failure: Ordering,
    ) -> Result<T, T> {
        let current1 = current;
        let bits = new;
        self.atomic
            .compare_exchange(current1, bits, success, failure)
    }

    #[inline(always)]
    fn compare_exchange_weak(
        &self,
        current: T,
        new: T,
        success: Ordering,
        failure: Ordering,
    ) -> Result<T, T> {
        self.atomic
            .compare_exchange_weak(current, new, success, failure)
    }
}

impl<T> Update for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    type Type = T;

    #[inline(always)]
    fn fetch_update<F>(&self, set_order: Ordering, fetch_order: Ordering, update: F) -> Result<T, T>
    where
        F: FnMut(T) -> Option<T>,
    {
        self.atomic.fetch_update(set_order, fetch_order, update)
    }
}

impl<T> Bitwise for AtomicNumber<T> where T: PrimitiveAtomicNumber + FromPrimitive {}

impl<T> And for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    type Type = T;

    #[inline(always)]
    fn fetch_and(&self, val: T, order: Ordering) -> T {
        self.atomic.fetch_and(val, order)
    }
}

impl<T> Nand for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    type Type = T;

    #[inline(always)]
    fn fetch_nand(&self, val: T, order: Ordering) -> T {
        self.atomic.fetch_nand(val, order)
    }
}

impl<T> Or for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    type Type = T;

    #[inline(always)]
    fn fetch_or(&self, val: T, order: Ordering) -> T {
        self.atomic.fetch_or(val, order)
    }
}

impl<T> Xor for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    type Type = T;

    #[inline(always)]
    fn fetch_xor(&self, val: T, order: Ordering) -> T {
        self.atomic.fetch_xor(val, order)
    }
}

impl<T> FromPtr for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    #[inline(always)]
    #[expect(unsafe_code)]
    unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self {
        unsafe {
            let u: &<T as IntoAtomicNumber>::AN = T::AN::from_ptr(ptr);
            let ptr = core::ptr::from_ref(u);
            let atomic_ptr = ptr.cast::<Self>();
            &*(atomic_ptr)
        }
    }
}

impl<T> AsPtr for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    #[inline(always)]
    fn as_ptr(&self) -> *mut T {
        self.atomic.as_ptr()
    }
}

impl<T> Default for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    #[inline(always)]
    fn default() -> Self {
        Self {
            atomic: T::AN::new(T::default()),
        }
    }
}

impl<T> core::fmt::Debug for AtomicNumber<T>
where
    T: PrimitiveAtomicNumber + FromPrimitive,
{
    #[inline(always)]
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        core::fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
    }
}