Skip to main content

generic_atomics/
atomic_number.rs

1use crate::{
2    atomic_float_wrapper::AtomicFloatWrapper, atomic_integer::AtomicInteger, AtomicFloat,
3    AtomicNumber, IntoAtomicFloat, IntoAtomicInteger,
4};
5use atomic_traits::{
6    fetch::{self, And, Nand, Or, Update, Xor},
7    AsPtr, Atomic, Bitwise, FromPtr,
8};
9use core::sync::atomic::{
10    AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64,
11    AtomicU8, AtomicUsize,
12    Ordering::{self},
13};
14use num_primitive::{PrimitiveFloat, PrimitiveInteger, PrimitiveNumber};
15use num_traits::FromPrimitive;
16
17pub trait AtomicNumberTraitBounds<N>:
18    Atomic<Type = N> + Bitwise + AsPtr + FromPtr + fetch::Update<Type = <Self as Atomic>::Type>
19{
20}
21impl<AN, N> AtomicNumberTraitBounds<N> for AN where
22    AN: Atomic<Type = N> + Bitwise + AsPtr + FromPtr + fetch::Update<Type = <Self as Atomic>::Type>
23{
24}
25
26pub(crate) trait PrimitiveAtomicNumber: PrimitiveNumber + IntoAtomicNumber {}
27impl<T> PrimitiveAtomicNumber for T where T: PrimitiveNumber + IntoAtomicNumber {}
28
29// this is basically the same as PrimitiveAtomic in unstable std
30// but because f also want to use atomic floats its
31pub trait IntoAtomicNumber: Sized + FromPrimitive {
32    type AN: AtomicNumberTraitBounds<Self> + Send;
33    fn into_atomic_number(self) -> impl AtomicNumberTraitBounds<Self> {
34        Self::AN::new(self)
35    }
36}
37
38macro_rules! impl_into_atomic_number {
39    ($type:ty, $atomic:ty) => {
40        impl IntoAtomicNumber for $type {
41            type AN = $atomic;
42        }
43    };
44}
45
46impl_into_atomic_number!(i8, AtomicI8);
47impl_into_atomic_number!(i16, AtomicI16);
48impl_into_atomic_number!(i32, AtomicI32);
49impl_into_atomic_number!(i64, AtomicI64);
50impl_into_atomic_number!(isize, AtomicIsize);
51// impl_into_atomics!(i128, AtomicI128);
52impl_into_atomic_number!(u8, AtomicU8);
53impl_into_atomic_number!(u16, AtomicU16);
54impl_into_atomic_number!(u32, AtomicU32);
55impl_into_atomic_number!(u64, AtomicU64);
56impl_into_atomic_number!(usize, AtomicUsize);
57// impl_into_atomics!(u128, AtomicU128);
58impl_into_atomic_number!(f64, AtomicFloatWrapper<f64>);
59impl_into_atomic_number!(f32, AtomicFloatWrapper<f32>);
60
61// SAFETY: We only ever access the underlying data by refcasting to AtomicU*,
62// which guarantees no data races.
63#[expect(unsafe_code)]
64unsafe impl<F: PrimitiveAtomicNumber> Send for AtomicNumber<F> {}
65#[expect(unsafe_code)]
66unsafe impl<F: PrimitiveAtomicNumber> Sync for AtomicNumber<F> {}
67
68impl<T> Atomic for AtomicNumber<T>
69where
70    T: PrimitiveAtomicNumber + FromPrimitive,
71{
72    type Type = T;
73
74    #[inline(always)]
75    fn new(number: T) -> Self {
76        Self {
77            atomic: T::AN::new(number),
78        }
79    }
80
81    #[inline(always)]
82    fn get_mut(&mut self) -> &mut T {
83        self.atomic.get_mut()
84    }
85
86    #[inline(always)]
87    fn into_inner(self) -> T {
88        self.atomic.into_inner()
89    }
90
91    #[inline(always)]
92    fn load(&self, ordering: Ordering) -> T {
93        self.atomic.load(ordering)
94    }
95
96    #[inline(always)]
97    fn store(&self, value: T, ordering: Ordering) {
98        self.atomic.store(value, ordering);
99    }
100
101    #[inline(always)]
102    fn swap(&self, new_value: T, ordering: Ordering) -> T {
103        self.atomic.swap(new_value, ordering)
104    }
105
106    #[inline(always)]
107    #[expect(deprecated)]
108    fn compare_and_swap(&self, current: T, new: T, order: Ordering) -> T {
109        self.atomic.compare_and_swap(current, new, order)
110    }
111
112    #[inline(always)]
113    fn compare_exchange(
114        &self,
115        current: T,
116        new: T,
117        success: Ordering,
118        failure: Ordering,
119    ) -> Result<T, T> {
120        let current1 = current;
121        let bits = new;
122        self.atomic
123            .compare_exchange(current1, bits, success, failure)
124    }
125
126    #[inline(always)]
127    fn compare_exchange_weak(
128        &self,
129        current: T,
130        new: T,
131        success: Ordering,
132        failure: Ordering,
133    ) -> Result<T, T> {
134        self.atomic
135            .compare_exchange_weak(current, new, success, failure)
136    }
137}
138
139impl<T> Update for AtomicNumber<T>
140where
141    T: PrimitiveAtomicNumber + FromPrimitive,
142{
143    type Type = T;
144
145    #[inline(always)]
146    fn fetch_update<F>(&self, set_order: Ordering, fetch_order: Ordering, update: F) -> Result<T, T>
147    where
148        F: FnMut(T) -> Option<T>,
149    {
150        self.atomic.fetch_update(set_order, fetch_order, update)
151    }
152}
153
154impl<T> Bitwise for AtomicNumber<T> where T: PrimitiveAtomicNumber + FromPrimitive {}
155
156impl<T> And for AtomicNumber<T>
157where
158    T: PrimitiveAtomicNumber + FromPrimitive,
159{
160    type Type = T;
161
162    #[inline(always)]
163    fn fetch_and(&self, val: T, order: Ordering) -> T {
164        self.atomic.fetch_and(val, order)
165    }
166}
167
168impl<T> Nand for AtomicNumber<T>
169where
170    T: PrimitiveAtomicNumber + FromPrimitive,
171{
172    type Type = T;
173
174    #[inline(always)]
175    fn fetch_nand(&self, val: T, order: Ordering) -> T {
176        self.atomic.fetch_nand(val, order)
177    }
178}
179
180impl<T> Or for AtomicNumber<T>
181where
182    T: PrimitiveAtomicNumber + FromPrimitive,
183{
184    type Type = T;
185
186    #[inline(always)]
187    fn fetch_or(&self, val: T, order: Ordering) -> T {
188        self.atomic.fetch_or(val, order)
189    }
190}
191
192impl<T> Xor for AtomicNumber<T>
193where
194    T: PrimitiveAtomicNumber + FromPrimitive,
195{
196    type Type = T;
197
198    #[inline(always)]
199    fn fetch_xor(&self, val: T, order: Ordering) -> T {
200        self.atomic.fetch_xor(val, order)
201    }
202}
203
204impl<T> FromPtr for AtomicNumber<T>
205where
206    T: PrimitiveAtomicNumber + FromPrimitive,
207{
208    #[inline(always)]
209    #[expect(unsafe_code)]
210    unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self {
211        unsafe {
212            let u: &<T as IntoAtomicNumber>::AN = T::AN::from_ptr(ptr);
213            let ptr = core::ptr::from_ref(u);
214            let atomic_ptr = ptr.cast::<Self>();
215            &*(atomic_ptr)
216        }
217    }
218}
219
220impl<T> AsPtr for AtomicNumber<T>
221where
222    T: PrimitiveAtomicNumber + FromPrimitive,
223{
224    #[inline(always)]
225    fn as_ptr(&self) -> *mut T {
226        self.atomic.as_ptr()
227    }
228}
229
230impl<T> Default for AtomicNumber<T>
231where
232    T: PrimitiveAtomicNumber + FromPrimitive,
233{
234    #[inline(always)]
235    fn default() -> Self {
236        Self {
237            atomic: T::AN::new(T::default()),
238        }
239    }
240}
241
242impl<T> core::fmt::Debug for AtomicNumber<T>
243where
244    T: PrimitiveAtomicNumber + FromPrimitive,
245{
246    #[inline(always)]
247    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
248        core::fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
249    }
250}
251
252impl<A> AtomicNumber<A>
253where
254    A: IntoAtomicFloat + PrimitiveFloat,
255{
256    pub fn into_atomic_float(self) -> impl AtomicFloat<<Self as Atomic>::Type> {
257        self
258    }
259}
260
261impl<A> AtomicNumber<A>
262where
263    A: IntoAtomicInteger + PrimitiveInteger,
264{
265    pub fn into_atomic_integer(self) -> impl AtomicInteger<<Self as Atomic>::Type> {
266        self
267    }
268}