utils_atomics/
trait.rs

1#[allow(unused_imports)]
2use core::sync::atomic::Ordering::{self, *};
3use docfg::docfg;
4
5#[allow(non_camel_case_types)]
6pub type Atomic_c_char = <core::ffi::c_char as HasAtomic>::Atomic;
7#[allow(non_camel_case_types)]
8pub type Atomic_c_schar = <core::ffi::c_schar as HasAtomic>::Atomic;
9#[allow(non_camel_case_types)]
10pub type Atomic_c_uchar = <core::ffi::c_uchar as HasAtomic>::Atomic;
11#[allow(non_camel_case_types)]
12pub type Atomic_c_short = <core::ffi::c_short as HasAtomic>::Atomic;
13#[allow(non_camel_case_types)]
14pub type Atomic_c_ushort = <core::ffi::c_ushort as HasAtomic>::Atomic;
15#[allow(non_camel_case_types)]
16pub type Atomic_c_int = <core::ffi::c_int as HasAtomic>::Atomic;
17#[allow(non_camel_case_types)]
18pub type Atomic_c_uint = <core::ffi::c_uint as HasAtomic>::Atomic;
19#[allow(non_camel_case_types)]
20pub type Atomic_c_long = <core::ffi::c_long as HasAtomic>::Atomic;
21#[allow(non_camel_case_types)]
22pub type Atomic_c_ulong = <core::ffi::c_ulong as HasAtomic>::Atomic;
23#[allow(non_camel_case_types)]
24pub type Atomic_c_longlong = <core::ffi::c_longlong as HasAtomic>::Atomic;
25#[allow(non_camel_case_types)]
26pub type Atomic_c_ulonglong = <core::ffi::c_ulonglong as HasAtomic>::Atomic;
27#[docfg(feature = "nightly")]
28#[allow(non_camel_case_types)]
29pub type Atomic_c_size_t = <core::ffi::c_size_t as HasAtomic>::Atomic;
30#[docfg(feature = "nightly")]
31#[allow(non_camel_case_types)]
32pub type Atomic_c_ssize_t = <core::ffi::c_ssize_t as HasAtomic>::Atomic;
33#[docfg(feature = "nightly")]
34#[allow(non_camel_case_types)]
35pub type Atomic_c_ptrdiff_t = <core::ffi::c_ptrdiff_t as HasAtomic>::Atomic;
36
37/// A trait representing types that have an associated atomic type.
38pub trait HasAtomic {
39    type Atomic: Atomic<Primitive = Self>;
40}
41
42#[allow(clippy::missing_errors_doc)]
43/// A trait representing atomic types.
44/// # Safety
45/// - `Self` must have the same size and alignment as [`Primitive`](`Atomic::Primitive`)
46pub unsafe trait Atomic: Send + Sync {
47    type Primitive: HasAtomic<Atomic = Self>;
48
49    /// Creates a new atomic integer.
50    fn new(v: Self::Primitive) -> Self;
51
52    /// Returns a mutable reference to the underlying integer.
53    ///
54    /// This is safe because the mutable reference guarantees that no other threads are
55    /// concurrently accessing the atomic data.
56    fn get_mut(&mut self) -> &mut Self::Primitive;
57    /// Consumes the atomic and returns the contained value.
58    ///
59    /// This is safe because passing `self` by value guarantees that no other threads are
60    /// concurrently accessing the atomic data.
61    fn into_inner(self) -> Self::Primitive;
62    /// Loads a value from the atomic integer.
63    ///
64    /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
65    /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
66    ///
67    /// # Panics
68    ///
69    /// Panics if `order` is [`Release`] or [`AcqRel`].
70    fn load(&self, order: Ordering) -> Self::Primitive;
71    /// Stores a value into the atomic integer.
72    ///
73    /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
74    ///  Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
75    ///
76    /// # Panics
77    ///
78    /// Panics if `order` is [`Acquire`] or [`AcqRel`].
79    fn store(&self, val: Self::Primitive, order: Ordering);
80    /// Stores a value into the atomic integer, returning the previous value.
81    ///
82    /// `swap` takes an [`Ordering`] argument which describes the memory ordering
83    /// of this operation. All ordering modes are possible. Note that using
84    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
85    /// using [`Release`] makes the load part [`Relaxed`].
86    fn swap(&self, val: Self::Primitive, order: Ordering) -> Self::Primitive;
87
88    /// Stores a value into the atomic integer if the current value is the same as
89    /// the `current` value.
90    ///
91    /// The return value is a result indicating whether the new value was written and
92    /// containing the previous value. On success this value is guaranteed to be equal to
93    /// `current`.
94    ///
95    /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
96    /// ordering of this operation. `success` describes the required ordering for the
97    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
98    /// `failure` describes the required ordering for the load operation that takes place when
99    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
100    /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
101    /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
102    fn compare_exchange(
103        &self,
104        current: Self::Primitive,
105        new: Self::Primitive,
106        success: Ordering,
107        failure: Ordering,
108    ) -> Result<Self::Primitive, Self::Primitive>;
109
110    /// Stores a value into the atomic integer if the current value is the same as
111    /// the `current` value.
112    ///
113    /// Unlike [`compare_exchange`](Atomic::compare_exchange), this function is allowed to spuriously fail even
114    /// when the comparison succeeds, which can result in more efficient code on some
115    /// platforms. The return value is a result indicating whether the new value was
116    /// written and containing the previous value.
117    ///
118    /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
119    /// ordering of this operation. `success` describes the required ordering for the
120    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
121    /// `failure` describes the required ordering for the load operation that takes place when
122    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
123    /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
124    /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
125    fn compare_exchange_weak(
126        &self,
127        current: Self::Primitive,
128        new: Self::Primitive,
129        success: Ordering,
130        failure: Ordering,
131    ) -> Result<Self::Primitive, Self::Primitive>;
132
133    /// Fetches the value, and applies a function to it that returns an optional
134    /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
135    /// `Err(previous_value)`.
136    ///
137    /// Note: This may call the function multiple times if the value has been changed from other threads in
138    /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
139    /// only once to the stored value.
140    ///
141    /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
142    /// The first describes the required ordering for when the operation finally succeeds while the second
143    /// describes the required ordering for loads. These correspond to the success and failure orderings of
144    /// [`compare_exchange`](Atomic::compare_exchange) respectively.
145    ///
146    /// Using [`Acquire`] as success ordering makes the store part
147    /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
148    /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
149    ///
150    /// # Considerations
151    ///
152    /// This method is not magic; it is not provided by the hardware.
153    /// It is implemented in terms of [`compare_exchange_weak`](Atomic::compare_exchange_weak),
154    /// and suffers from the same drawbacks.
155    /// In particular, this method will not circumvent the [ABA Problem].
156    ///
157    /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
158    fn fetch_update<F: FnMut(Self::Primitive) -> Option<Self::Primitive>>(
159        &self,
160        set_order: Ordering,
161        fetch_ordering: Ordering,
162        f: F,
163    ) -> Result<Self::Primitive, Self::Primitive>;
164}
165
166/// A trait representing atomic types that can be constructed in a "const" context.
167#[cfg_attr(docsrs, doc(cfg(feature = "const")))]
168#[cfg(feature = "const")]
169#[const_trait]
170pub trait AtomicConstNew: Atomic {
171    fn new(v: Self::Primitive) -> Self;
172}
173
174/// A trait representing atomic types that support addition operations.
175pub trait AtomicAdd<T = <Self as Atomic>::Primitive>: Atomic {
176    /// Adds to the current value, returning the previous value.
177    ///
178    /// This operation wraps around on overflow.
179    ///
180    /// `fetch_add` takes an [`Ordering`] argument which describes the memory ordering
181    /// of this operation. All ordering modes are possible. Note that using
182    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
183    /// using [`Release`] makes the load part [`Relaxed`].
184    fn fetch_add(&self, val: T, order: Ordering) -> Self::Primitive;
185}
186
187/// A trait representing atomic types that support subtraction operations.
188pub trait AtomicSub<T = <Self as Atomic>::Primitive>: Atomic {
189    /// Subtracts from the current value, returning the previous value.
190    ///
191    /// This operation wraps around on overflow.
192    ///
193    /// `fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
194    /// of this operation. All ordering modes are possible. Note that using
195    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
196    /// using [`Release`] makes the load part [`Relaxed`].
197    fn fetch_sub(&self, val: T, order: Ordering) -> Self::Primitive;
198}
199
200/// A trait representing atomic types that support subtraction operations.
201pub trait AtomicBitAnd<T = <Self as Atomic>::Primitive>: Atomic {
202    /// Bitwise "and" with the current value.
203    ///
204    /// Performs a bitwise "and" operation on the current value and the argument `val`, and
205    /// sets the new value to the result.
206    ///
207    /// Returns the previous value.
208    ///
209    /// `fetch_and` takes an [`Ordering`] argument which describes the memory ordering
210    /// of this operation. All ordering modes are possible. Note that using
211    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
212    /// using [`Release`] makes the load part [`Relaxed`].
213    fn fetch_and(&self, val: T, order: Ordering) -> Self::Primitive;
214    /// Bitwise "nand" with the current value.
215    ///
216    /// Performs a bitwise "nand" operation on the current value and the argument `val`, and
217    /// sets the new value to the result.
218    ///
219    /// Returns the previous value.
220    ///
221    /// `fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
222    /// of this operation. All ordering modes are possible. Note that using
223    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
224    /// using [`Release`] makes the load part [`Relaxed`].
225    fn fetch_nand(&self, val: T, order: Ordering) -> Self::Primitive;
226}
227
228/// A trait representing atomic types that support bitwise OR operations.
229pub trait AtomicBitOr<T = <Self as Atomic>::Primitive>: Atomic {
230    /// Bitwise "or" with the current value.
231    ///
232    /// Performs a bitwise "or" operation on the current value and the argument `val`, and
233    /// sets the new value to the result.
234    ///
235    /// Returns the previous value.
236    ///
237    /// `fetch_or` takes an [`Ordering`] argument which describes the memory ordering
238    /// of this operation. All ordering modes are possible. Note that using
239    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
240    /// using [`Release`] makes the load part [`Relaxed`].
241    fn fetch_or(&self, val: T, order: Ordering) -> Self::Primitive;
242}
243
244/// A trait representing atomic types that support bitwise XOR operations.
245pub trait AtomicBitXor<T = <Self as Atomic>::Primitive>: Atomic {
246    /// Bitwise "xor" with the current value.
247    ///
248    /// Performs a bitwise "xor" operation on the current value and the argument `val`, and
249    /// sets the new value to the result.
250    ///
251    /// Returns the previous value.
252    ///
253    /// `fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
254    /// of this operation. All ordering modes are possible. Note that using
255    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
256    /// using [`Release`] makes the load part [`Relaxed`].
257    fn fetch_xor(&self, val: T, order: Ordering) -> Self::Primitive;
258}
259
260/// A trait representing atomic types that support minimum operations.
261pub trait AtomicMin<T = <Self as Atomic>::Primitive>: Atomic {
262    /// Minimum with the current value.
263    ///
264    /// Finds the minimum of the current value and the argument `val`, and
265    /// sets the new value to the result.
266    ///
267    /// Returns the previous value.
268    ///
269    /// `fetch_min` takes an [`Ordering`] argument which describes the memory ordering
270    /// of this operation. All ordering modes are possible. Note that using
271    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
272    /// using [`Release`] makes the load part [`Relaxed`].
273    fn fetch_min(&self, val: T, order: Ordering) -> Self::Primitive;
274}
275
276/// A trait representing atomic types that support maximum operations.
277pub trait AtomicMax<T = <Self as Atomic>::Primitive>: Atomic {
278    /// Maximum with the current value.
279    ///
280    /// Finds the maximum of the current value and the argument `val`, and
281    /// sets the new value to the result.
282    ///
283    /// Returns the previous value.
284    ///
285    /// `fetch_max` takes an [`Ordering`] argument which describes the memory ordering
286    /// of this operation. All ordering modes are possible. Note that using
287    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
288    /// using [`Release`] makes the load part [`Relaxed`].
289    fn fetch_max(&self, val: T, order: Ordering) -> Self::Primitive;
290}
291
292/* MARKER TRAITS */
293
294/// A marker trait representing types that have an associated atomic integer type.
295pub trait HasAtomicInt: HasAtomic {
296    type AtomicInt: AtomicInt<Primitive = Self>;
297}
298/// A marker trait representing atomic types that support numerical operations.
299pub trait AtomicNumOps<T = <Self as Atomic>::Primitive>:
300    Atomic + AtomicAdd<T> + AtomicSub<T>
301{
302}
303/// A marker trait representing atomic types that support bitwise operations.
304pub trait AtomicBitOps<T = <Self as Atomic>::Primitive>:
305    Atomic + AtomicBitAnd<T> + AtomicBitOr<T> + AtomicBitXor<T>
306{
307}
308/// A marker trait representing atomic types that support ordering operations.
309pub trait AtomicOrd<T = <Self as Atomic>::Primitive>: Atomic + AtomicMin<T> + AtomicMax<T> {}
310/// A marker trait representing atomic types that support numerical and ordering operations.
311pub trait AtomicNum: AtomicNumOps + AtomicOrd {}
312/// A marker trait representing atomic types that support numerical and ordering operations.
313pub trait AtomicInt: AtomicNum + AtomicBitOps {}
314
315impl<T: HasAtomic> HasAtomicInt for T
316where
317    T::Atomic: AtomicInt<Primitive = T>,
318{
319    type AtomicInt = <T as HasAtomic>::Atomic;
320}
321impl<T, U> AtomicNumOps<T> for U where U: Atomic + AtomicAdd<T> + AtomicSub<T> {}
322impl<T, U> AtomicBitOps<T> for U where U: Atomic + AtomicBitAnd<T> + AtomicBitOr<T> + AtomicBitXor<T>
323{}
324impl<T, U> AtomicOrd<T> for U where U: Atomic + AtomicMin<T> + AtomicMax<T> {}
325impl<T> AtomicNum for T where T: AtomicNumOps + AtomicOrd {}
326impl<T> AtomicInt for T where T: AtomicNum + AtomicBitOps {}
327
328// IMPLEMENTATION
329
330macro_rules! impl_atomic {
331    ($($len:literal: $prim:ty => $atomic:ty),+) => {
332        $(
333            #[docfg(target_has_atomic = $len)]
334            impl HasAtomic for $prim {
335                type Atomic = $atomic;
336            }
337
338            #[docfg(target_has_atomic = $len)]
339            unsafe impl Atomic for $atomic {
340                type Primitive = $prim;
341
342                #[inline]
343                fn new (v: Self::Primitive) -> Self {
344                    <$atomic>::new(v)
345                }
346
347                #[inline]
348                fn get_mut (&mut self) -> &mut Self::Primitive {
349                    <$atomic>::get_mut(self)
350                }
351
352                #[inline]
353                fn into_inner (self) -> Self::Primitive {
354                    <$atomic>::into_inner(self)
355                }
356
357                #[inline]
358                fn load (&self, order: Ordering) -> Self::Primitive {
359                    <$atomic>::load(self, order)
360                }
361
362                #[inline]
363                fn store (&self, val: Self::Primitive, order: Ordering) {
364                    <$atomic>::store(self, val, order)
365                }
366
367                #[inline]
368                fn swap (&self, val: Self::Primitive, order: Ordering) -> Self::Primitive {
369                    <$atomic>::swap(self, val, order)
370                }
371
372                #[inline]
373                fn compare_exchange (&self, current: Self::Primitive, new: Self::Primitive, success: Ordering, failure: Ordering) -> Result<Self::Primitive, Self::Primitive> {
374                    <$atomic>::compare_exchange(self, current, new, success, failure)
375                }
376
377                #[inline]
378                fn compare_exchange_weak (&self, current: Self::Primitive, new: Self::Primitive, success: Ordering, failure: Ordering) -> Result<Self::Primitive, Self::Primitive> {
379                    <$atomic>::compare_exchange_weak(self, current, new, success, failure)
380                }
381
382                #[inline]
383                fn fetch_update<F: FnMut(Self::Primitive) -> Option<Self::Primitive>> (&self, set_order: Ordering, fetch_ordering: Ordering, f: F) -> Result<Self::Primitive, Self::Primitive> {
384                    <$atomic>::fetch_update(self, set_order, fetch_ordering, f)
385                }
386            }
387
388            cfg_if::cfg_if! {
389                if #[cfg(feature = "const")] {
390                    #[cfg_attr(docsrs, doc(cfg(feature = "const")))]
391                    impl const AtomicConstNew for $atomic {
392                        #[inline]
393                        fn new (v: Self::Primitive) -> Self {
394                            <$atomic>::new(v)
395                        }
396                    }
397                }
398            }
399        )+
400    };
401}
402
403macro_rules! impl_int {
404    ($($len:literal: ($int:ty, $uint:ty) => ($iatomic:ty, $uatomic:ty)),+) => {
405        $(
406            impl_int!($len: $int => $iatomic);
407            impl_int!($len: $uint => $uatomic);
408        )+
409    };
410
411    ($($len:literal: $prim:ty => $atomic:ty),+) => {
412        $(
413            impl_atomic!($len: $prim => $atomic);
414
415            #[docfg(target_has_atomic = $len)]
416            impl AtomicAdd for $atomic {
417                #[inline]
418                fn fetch_add(&self, val: $prim, order: Ordering) -> $prim {
419                    <$atomic>::fetch_add(self, val, order)
420                }
421            }
422
423            #[docfg(target_has_atomic = $len)]
424            impl AtomicSub for $atomic {
425                #[inline]
426                fn fetch_sub(&self, val: $prim, order: Ordering) -> $prim {
427                    <$atomic>::fetch_sub(self, val, order)
428                }
429            }
430
431            #[docfg(target_has_atomic = $len)]
432            impl AtomicBitAnd for $atomic {
433                #[inline]
434                fn fetch_and(&self, val: $prim, order: Ordering) -> $prim {
435                    <$atomic>::fetch_and(self, val, order)
436                }
437
438                #[inline]
439                fn fetch_nand(&self, val: $prim, order: Ordering) -> $prim {
440                    <$atomic>::fetch_nand(self, val, order)
441                }
442            }
443
444            #[docfg(target_has_atomic = $len)]
445            impl AtomicBitOr for $atomic {
446                #[inline]
447                fn fetch_or(&self, val: $prim, order: Ordering) -> $prim {
448                    <$atomic>::fetch_or(self, val, order)
449                }
450            }
451
452            #[docfg(target_has_atomic = $len)]
453            impl AtomicBitXor for $atomic {
454                #[inline]
455                fn fetch_xor(&self, val: $prim, order: Ordering) -> $prim {
456                    <$atomic>::fetch_xor(self, val, order)
457                }
458            }
459
460            #[docfg(target_has_atomic = $len)]
461            impl AtomicMin for $atomic {
462                #[inline]
463                fn fetch_min(&self, val: $prim, order: Ordering) -> $prim {
464                    <$atomic>::fetch_min(self, val, order)
465                }
466            }
467
468            #[docfg(target_has_atomic = $len)]
469            impl AtomicMax for $atomic {
470                #[inline]
471                fn fetch_max(&self, val: $prim, order: Ordering) -> $prim {
472                    <$atomic>::fetch_max(self, val, order)
473                }
474            }
475        )+
476    };
477}
478
479impl_int! {
480    "8": (u8, i8) => (core::sync::atomic::AtomicU8, core::sync::atomic::AtomicI8),
481    "16": (u16, i16) => (core::sync::atomic::AtomicU16, core::sync::atomic::AtomicI16),
482    "32": (u32, i32) => (core::sync::atomic::AtomicU32, core::sync::atomic::AtomicI32),
483    "64": (u64, i64) => (core::sync::atomic::AtomicU64, core::sync::atomic::AtomicI64),
484    "ptr": (usize, isize) => (core::sync::atomic::AtomicUsize, core::sync::atomic::AtomicIsize)
485    //"128": (u128, i128) => (core::sync::atomic::AtomicU128, core::sync::atomic::AtomicI128)
486}
487
488impl_atomic! {
489    "8": bool => core::sync::atomic::AtomicBool
490}
491
492#[docfg(target_has_atomic = "ptr")]
493impl<T> HasAtomic for *mut T {
494    type Atomic = core::sync::atomic::AtomicPtr<T>;
495}
496
497#[docfg(target_has_atomic = "ptr")]
498unsafe impl<T> Atomic for core::sync::atomic::AtomicPtr<T> {
499    type Primitive = *mut T;
500
501    #[inline]
502    fn new(v: Self::Primitive) -> Self {
503        core::sync::atomic::AtomicPtr::new(v)
504    }
505
506    #[inline]
507    fn get_mut(&mut self) -> &mut Self::Primitive {
508        core::sync::atomic::AtomicPtr::get_mut(self)
509    }
510
511    #[inline]
512    fn into_inner(self) -> Self::Primitive {
513        core::sync::atomic::AtomicPtr::into_inner(self)
514    }
515
516    #[inline]
517    fn load(&self, order: Ordering) -> Self::Primitive {
518        core::sync::atomic::AtomicPtr::load(self, order)
519    }
520
521    #[inline]
522    fn store(&self, val: Self::Primitive, order: Ordering) {
523        core::sync::atomic::AtomicPtr::store(self, val, order)
524    }
525
526    #[inline]
527    fn swap(&self, val: Self::Primitive, order: Ordering) -> Self::Primitive {
528        core::sync::atomic::AtomicPtr::swap(self, val, order)
529    }
530
531    #[inline]
532    fn compare_exchange(
533        &self,
534        current: Self::Primitive,
535        new: Self::Primitive,
536        success: Ordering,
537        failure: Ordering,
538    ) -> Result<Self::Primitive, Self::Primitive> {
539        core::sync::atomic::AtomicPtr::compare_exchange(self, current, new, success, failure)
540    }
541
542    #[inline]
543    fn compare_exchange_weak(
544        &self,
545        current: Self::Primitive,
546        new: Self::Primitive,
547        success: Ordering,
548        failure: Ordering,
549    ) -> Result<Self::Primitive, Self::Primitive> {
550        core::sync::atomic::AtomicPtr::compare_exchange_weak(self, current, new, success, failure)
551    }
552
553    #[inline]
554    fn fetch_update<F: FnMut(Self::Primitive) -> Option<Self::Primitive>>(
555        &self,
556        set_order: Ordering,
557        fetch_ordering: Ordering,
558        f: F,
559    ) -> Result<Self::Primitive, Self::Primitive> {
560        core::sync::atomic::AtomicPtr::fetch_update(self, set_order, fetch_ordering, f)
561    }
562}