Skip to main content

shuttle_std/sync/atomic/
int.rs

1use crate::sync::atomic::Atomic;
2use std::sync::atomic::Ordering;
3
4macro_rules! atomic_int {
5    ($name:ident, $int_type:ty) => {
6        /// An integer type which can be safely shared between threads.
7        pub struct $name {
8            inner: Atomic<$int_type>,
9        }
10
11        impl Default for $name {
12            fn default() -> Self {
13                Self::new(Default::default())
14            }
15        }
16
17        impl From<$int_type> for $name {
18            fn from(v: $int_type) -> Self {
19                Self::new(v)
20            }
21        }
22
23        impl std::fmt::Debug for $name {
24            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25                std::fmt::Debug::fmt(unsafe { &self.raw_load() }, f)
26            }
27        }
28
29        impl $name {
30            /// Creates a new atomic integer.
31            #[track_caller]
32            pub const fn new(v: $int_type) -> Self {
33                Self {
34                    inner: Atomic::new(v),
35                }
36            }
37
38            /// Returns a mutable reference to the underlying integer.
39            pub fn get_mut(&mut self) -> &mut $int_type {
40                self.inner.get_mut()
41            }
42
43            /// Consumes the atomic and returns the contained value.
44            pub fn into_inner(self) -> $int_type {
45                self.inner.into_inner()
46            }
47
48            /// Loads a value from the atomic integer.
49            pub fn load(&self, order: Ordering) -> $int_type {
50                self.inner.load(order)
51            }
52
53            /// Stores a value into the atomic integer.
54            pub fn store(&self, val: $int_type, order: Ordering) {
55                self.inner.store(val, order)
56            }
57
58            /// Stores a value into the atomic integer, returning the previous value.
59            pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
60                self.inner.swap(val, order)
61            }
62
63            /// Fetches the value, and applies a function to it that returns an optional new value.
64            /// Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
65            /// `Err(previous_value)`.
66            pub fn try_update(
67                &self,
68                set_order: Ordering,
69                fetch_order: Ordering,
70                mut f: impl FnMut($int_type) -> Option<$int_type>,
71            ) -> Result<$int_type, $int_type> {
72                let mut prev = self.load(fetch_order);
73                while let Some(next) = f(prev) {
74                    match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
75                        x @ Ok(_) => return x,
76                        Err(next_prev) => prev = next_prev,
77                    }
78                }
79                Err(prev)
80            }
81
82            /// Fetches the value, and applies a function to it that returns an optional new value.
83            ///
84            /// Since Rust 1.95 this is an alias for [`try_update`](Self::try_update). Deprecated
85            /// since Rust 1.99.
86            pub fn fetch_update<F>(
87                &self,
88                set_order: Ordering,
89                fetch_order: Ordering,
90                f: F,
91            ) -> Result<$int_type, $int_type>
92            where
93                F: FnMut($int_type) -> Option<$int_type>,
94            {
95                self.try_update(set_order, fetch_order, f)
96            }
97
98            /// Fetches the value, applies a function to it that returns a new value, and stores the
99            /// new value. Returns the previous value.
100            pub fn update(
101                &self,
102                set_order: Ordering,
103                fetch_order: Ordering,
104                mut f: impl FnMut($int_type) -> $int_type,
105            ) -> $int_type {
106                let mut prev = self.load(fetch_order);
107                loop {
108                    match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
109                        Ok(x) => break x,
110                        Err(next_prev) => prev = next_prev,
111                    }
112                }
113            }
114
115            /// Stores a value into the atomic integer if the current value is the same as the
116            /// `current` value.
117            #[deprecated(
118                since = "0.0.6",
119                note = "Use `compare_exchange` or `compare_exchange_weak` instead"
120            )]
121            pub fn compare_and_swap(&self, current: $int_type, new: $int_type, order: Ordering) -> $int_type {
122                match self.compare_exchange(current, new, order, order) {
123                    Ok(v) => v,
124                    Err(v) => v,
125                }
126            }
127
128            /// Stores a value into the atomic integer if the current value is the same as the
129            /// `current` value.
130            ///
131            /// The return value is a result indicating whether the new value was written and
132            /// containing the previous value. On success this value is guaranteed to be equal to
133            /// `current`.
134            pub fn compare_exchange(
135                &self,
136                current: $int_type,
137                new: $int_type,
138                success: Ordering,
139                failure: Ordering,
140            ) -> Result<$int_type, $int_type> {
141                self.inner
142                    .try_update(success, failure, |val| (val == current).then(|| new))
143            }
144
145            /// Stores a value into the atomic integer if the current value is the same as the
146            /// `current` value.
147            ///
148            /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when
149            /// the comparison succeeds, which can result in more efficient code on some platforms.
150            /// The return value is a result indicating whether the new value was written and
151            /// containing the previous value.
152            // TODO actually produce spurious failures
153            pub fn compare_exchange_weak(
154                &self,
155                current: $int_type,
156                new: $int_type,
157                success: Ordering,
158                failure: Ordering,
159            ) -> Result<$int_type, $int_type> {
160                self.compare_exchange(current, new, success, failure)
161            }
162
163            /// Adds to the current value, returning the previous value.
164            ///
165            /// This operation wraps around on overflow.
166            pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
167                self.inner
168                    .try_update(order, order, |old| Some(old.wrapping_add(val)))
169                    .unwrap()
170            }
171
172            /// Subtracts from the current value, returning the previous value.
173            ///
174            /// This operation wraps around on overflow.
175            pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
176                self.inner
177                    .try_update(order, order, |old| Some(old.wrapping_sub(val)))
178                    .unwrap()
179            }
180
181            /// Bitwise "and" with the current value. Returns the previous value.
182            pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
183                self.inner
184                    .try_update(order, order, |old| Some(old & val))
185                    .unwrap()
186            }
187
188            /// Bitwise "nand" with the current value. Returns the previous value.
189            pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
190                self.inner
191                    .try_update(order, order, |old| Some(!(old & val)))
192                    .unwrap()
193            }
194
195            /// Bitwise "or" with the current value. Returns the previous value.
196            pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
197                self.inner
198                    .try_update(order, order, |old| Some(old | val))
199                    .unwrap()
200            }
201
202            /// Bitwise "xor" with the current value. Returns the previous value.
203            pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
204                self.inner
205                    .try_update(order, order, |old| Some(old ^ val))
206                    .unwrap()
207            }
208
209            /// Maximum with the current value. Returns the previous value.
210            pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
211                self.inner
212                    .try_update(order, order, |old| Some(old.max(val)))
213                    .unwrap()
214            }
215
216            /// Minimum with the current value. Returns the previous value.
217            pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
218                self.inner
219                    .try_update(order, order, |old| Some(old.min(val)))
220                    .unwrap()
221            }
222
223            /// Load the atomic value directly without triggering any Shuttle context switches.
224            ///
225            /// # Safety
226            ///
227            /// Shuttle does not consider potential concurrent interleavings of this function call,
228            /// and so it should be used when those interleavings aren't important (primarily in
229            /// debugging scenarios where we might want to just print this atomic's value).
230            pub unsafe fn raw_load(&self) -> $int_type {
231                self.inner.raw_load()
232            }
233
234            #[cfg(test)]
235            pub(crate) fn signature(&self) -> crate::sync::ResourceSignature {
236                self.inner.signature()
237            }
238        }
239    };
240}
241
242atomic_int!(AtomicI8, i8);
243atomic_int!(AtomicI16, i16);
244atomic_int!(AtomicI32, i32);
245atomic_int!(AtomicI64, i64);
246atomic_int!(AtomicI128, i128);
247atomic_int!(AtomicIsize, isize);
248atomic_int!(AtomicU8, u8);
249atomic_int!(AtomicU16, u16);
250atomic_int!(AtomicU32, u32);
251atomic_int!(AtomicU64, u64);
252atomic_int!(AtomicU128, u128);
253atomic_int!(AtomicUsize, usize);