Skip to main content

atomic_primitive/
atomic.rs

1use core::sync::atomic::Ordering;
2
3use crate::Sealed;
4
5/// Trait for all primitive [atomic types], including [`AtomicBool`] and all
6/// atomic integer types.
7///
8/// This encapsulates trait implementations and inherent methods that are common
9/// among all of the primitive atomic types: [`AtomicBool`], [`AtomicU8`],
10/// [`AtomicU16`], [`AtomicU32`], [`AtomicUsize`], [`AtomicI8`],
11/// [`AtomicI16`], [`AtomicI32`], [`AtomicIsize`], and, on targets with
12/// 64-bit atomics, [`AtomicU64`] and [`AtomicI64`].
13///
14/// See the corresponding items on the individual types for more documentation
15/// and examples.
16///
17/// This trait is sealed to prevent downstream implementations.
18///
19/// [`AtomicBool`]: core::sync::atomic::AtomicBool
20/// [`AtomicU8`]: core::sync::atomic::AtomicU8
21/// [`AtomicU16`]: core::sync::atomic::AtomicU16
22/// [`AtomicU32`]: core::sync::atomic::AtomicU32
23/// [`AtomicU64`]: core::sync::atomic::AtomicU64
24/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize
25/// [`AtomicI8`]: core::sync::atomic::AtomicI8
26/// [`AtomicI16`]: core::sync::atomic::AtomicI16
27/// [`AtomicI32`]: core::sync::atomic::AtomicI32
28/// [`AtomicI64`]: core::sync::atomic::AtomicI64
29/// [`AtomicIsize`]: core::sync::atomic::AtomicIsize
30/// [atomic types]: core::sync::atomic
31#[expect(private_bounds)]
32pub trait PrimitiveAtomic: Sealed + Sized + Send + Sync {
33    /// The non-atomic type corresponding to this atomic type.
34    ///
35    /// The [`AtomicPrimitive`](crate::AtomicPrimitive) bound is the only
36    /// addition beyond standard library functionality, enabling bidirectional
37    /// navigation between atomic and non-atomic types.
38    type Value: Copy + Send + Sync + crate::AtomicPrimitive<Atomic = Self>;
39
40    /// Creates a new atomic value.
41    fn new(value: Self::Value) -> Self;
42
43    /// Returns a mutable reference to the underlying value.
44    fn get_mut(&mut self) -> &mut Self::Value;
45
46    /// Consumes the atomic and returns the contained value.
47    fn into_inner(self) -> Self::Value;
48
49    /// Loads a value from the atomic.
50    fn load(&self, order: Ordering) -> Self::Value;
51
52    /// Stores a value into the atomic.
53    fn store(&self, value: Self::Value, order: Ordering);
54
55    /// Stores a value into the atomic, returning the previous value.
56    fn swap(&self, value: Self::Value, order: Ordering) -> Self::Value;
57
58    /// Stores a value into the atomic if the current value is the same as
59    /// `current`.
60    fn compare_exchange(
61        &self,
62        current: Self::Value,
63        new: Self::Value,
64        success: Ordering,
65        failure: Ordering,
66    ) -> Result<Self::Value, Self::Value>;
67
68    /// Stores a value into the atomic if the current value is the same as
69    /// `current`. Unlike [`compare_exchange`](PrimitiveAtomic::compare_exchange),
70    /// this function is allowed to spuriously fail.
71    fn compare_exchange_weak(
72        &self,
73        current: Self::Value,
74        new: Self::Value,
75        success: Ordering,
76        failure: Ordering,
77    ) -> Result<Self::Value, Self::Value>;
78
79    /// Fetches the value, and applies a function to it that returns an optional
80    /// new value. Returns a `Result` of `Ok(previous_value)` if the function
81    /// returned `Some(_)`, else `Err(previous_value)`.
82    fn fetch_update<F>(
83        &self,
84        set_order: Ordering,
85        fetch_order: Ordering,
86        f: F,
87    ) -> Result<Self::Value, Self::Value>
88    where
89        F: FnMut(Self::Value) -> Option<Self::Value>;
90
91    /// Bitwise "and" with the current value. Returns the previous value.
92    fn fetch_and(&self, val: Self::Value, order: Ordering) -> Self::Value;
93
94    /// Bitwise "nand" with the current value. Returns the previous value.
95    fn fetch_nand(&self, val: Self::Value, order: Ordering) -> Self::Value;
96
97    /// Bitwise "or" with the current value. Returns the previous value.
98    fn fetch_or(&self, val: Self::Value, order: Ordering) -> Self::Value;
99
100    /// Bitwise "xor" with the current value. Returns the previous value.
101    fn fetch_xor(&self, val: Self::Value, order: Ordering) -> Self::Value;
102
103    /// Returns a raw pointer to the underlying value.
104    fn as_ptr(&self) -> *mut Self::Value;
105}
106
107macro_rules! impl_primitive_atomic {
108    ($Atomic:ty, $Value:ty) => {
109        impl Sealed for $Atomic {}
110
111        impl PrimitiveAtomic for $Atomic {
112            type Value = $Value;
113
114            forward! {
115                fn new(value: $Value) -> Self;
116                fn get_mut(&mut self) -> &mut $Value;
117                fn into_inner(self) -> $Value;
118                fn load(&self, order: Ordering) -> $Value;
119            }
120
121            // store: cannot use forward! (no return type)
122            #[inline]
123            fn store(&self, value: $Value, order: Ordering) {
124                <$Atomic>::store(self, value, order)
125            }
126
127            forward! {
128                fn swap(&self, value: $Value, order: Ordering) -> $Value;
129                fn compare_exchange(&self, current: $Value, new: $Value, success: Ordering, failure: Ordering) -> Result<$Value, $Value>;
130                fn compare_exchange_weak(&self, current: $Value, new: $Value, success: Ordering, failure: Ordering) -> Result<$Value, $Value>;
131            }
132
133            // fetch_update: cannot use forward! (generic parameter)
134            #[inline]
135            fn fetch_update<F>(
136                &self,
137                set_order: Ordering,
138                fetch_order: Ordering,
139                f: F,
140            ) -> Result<$Value, $Value>
141            where
142                F: FnMut($Value) -> Option<$Value>,
143            {
144                <$Atomic>::fetch_update(self, set_order, fetch_order, f)
145            }
146
147            forward! {
148                fn fetch_and(&self, val: $Value, order: Ordering) -> $Value;
149                fn fetch_nand(&self, val: $Value, order: Ordering) -> $Value;
150                fn fetch_or(&self, val: $Value, order: Ordering) -> $Value;
151                fn fetch_xor(&self, val: $Value, order: Ordering) -> $Value;
152                fn as_ptr(&self) -> *mut $Value;
153            }
154        }
155    };
156}
157
158use core::sync::atomic::{
159    AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicIsize, AtomicU8, AtomicU16, AtomicU32,
160    AtomicUsize,
161};
162#[cfg(target_has_atomic = "64")]
163use core::sync::atomic::{AtomicI64, AtomicU64};
164
165impl_primitive_atomic!(AtomicBool, bool);
166impl_primitive_atomic!(AtomicU8, u8);
167impl_primitive_atomic!(AtomicU16, u16);
168impl_primitive_atomic!(AtomicU32, u32);
169impl_primitive_atomic!(AtomicUsize, usize);
170impl_primitive_atomic!(AtomicI8, i8);
171impl_primitive_atomic!(AtomicI16, i16);
172impl_primitive_atomic!(AtomicI32, i32);
173impl_primitive_atomic!(AtomicIsize, isize);
174#[cfg(target_has_atomic = "64")]
175impl_primitive_atomic!(AtomicU64, u64);
176#[cfg(target_has_atomic = "64")]
177impl_primitive_atomic!(AtomicI64, i64);