use crate::{
atomic_float_wrapper::AtomicFloatWrapper, atomic_integer::AtomicInteger, AtomicFloat,
AtomicNumber, IntoAtomicFloat, IntoAtomicInteger,
};
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::{PrimitiveFloat, PrimitiveInteger, 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 {}
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_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_atomic_number!(f64, AtomicFloatWrapper<f64>);
impl_into_atomic_number!(f32, AtomicFloatWrapper<f32>);
#[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)
}
}
impl<A> AtomicNumber<A>
where
A: IntoAtomicFloat + PrimitiveFloat,
{
pub fn into_atomic_float(self) -> impl AtomicFloat<<Self as Atomic>::Type> {
self
}
}
impl<A> AtomicNumber<A>
where
A: IntoAtomicInteger + PrimitiveInteger,
{
pub fn into_atomic_integer(self) -> impl AtomicInteger<<Self as Atomic>::Type> {
self
}
}