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 fetch_update<F>(
67                &self,
68                set_order: Ordering,
69                fetch_order: Ordering,
70                f: F,
71            ) -> Result<$int_type, $int_type>
72            where
73                F: FnMut($int_type) -> Option<$int_type>,
74            {
75                self.inner.fetch_update(set_order, fetch_order, f)
76            }
77
78            /// Stores a value into the atomic integer if the current value is the same as the
79            /// `current` value.
80            #[deprecated(
81                since = "0.0.6",
82                note = "Use `compare_exchange` or `compare_exchange_weak` instead"
83            )]
84            pub fn compare_and_swap(&self, current: $int_type, new: $int_type, order: Ordering) -> $int_type {
85                match self.compare_exchange(current, new, order, order) {
86                    Ok(v) => v,
87                    Err(v) => v,
88                }
89            }
90
91            /// Stores a value into the atomic integer if the current value is the same as the
92            /// `current` value.
93            ///
94            /// The return value is a result indicating whether the new value was written and
95            /// containing the previous value. On success this value is guaranteed to be equal to
96            /// `current`.
97            pub fn compare_exchange(
98                &self,
99                current: $int_type,
100                new: $int_type,
101                success: Ordering,
102                failure: Ordering,
103            ) -> Result<$int_type, $int_type> {
104                self.fetch_update(success, failure, |val| (val == current).then(|| new))
105            }
106
107            /// Stores a value into the atomic integer if the current value is the same as the
108            /// `current` value.
109            ///
110            /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when
111            /// the comparison succeeds, which can result in more efficient code on some platforms.
112            /// The return value is a result indicating whether the new value was written and
113            /// containing the previous value.
114            // TODO actually produce spurious failures
115            pub fn compare_exchange_weak(
116                &self,
117                current: $int_type,
118                new: $int_type,
119                success: Ordering,
120                failure: Ordering,
121            ) -> Result<$int_type, $int_type> {
122                self.compare_exchange(current, new, success, failure)
123            }
124
125            /// Adds to the current value, returning the previous value.
126            ///
127            /// This operation wraps around on overflow.
128            pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
129                self.fetch_update(order, order, |old| Some(old.wrapping_add(val)))
130                    .unwrap()
131            }
132
133            /// Subtracts from the current value, returning the previous value.
134            ///
135            /// This operation wraps around on overflow.
136            pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
137                self.fetch_update(order, order, |old| Some(old.wrapping_sub(val)))
138                    .unwrap()
139            }
140
141            /// Bitwise "and" with the current value. Returns the previous value.
142            pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
143                self.fetch_update(order, order, |old| Some(old & val)).unwrap()
144            }
145
146            /// Bitwise "nand" with the current value. Returns the previous value.
147            pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
148                self.fetch_update(order, order, |old| Some(!(old & val))).unwrap()
149            }
150
151            /// Bitwise "or" with the current value. Returns the previous value.
152            pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
153                self.fetch_update(order, order, |old| Some(old | val)).unwrap()
154            }
155
156            /// Bitwise "xor" with the current value. Returns the previous value.
157            pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
158                self.fetch_update(order, order, |old| Some(old ^ val)).unwrap()
159            }
160
161            /// Maximum with the current value. Returns the previous value.
162            pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
163                self.fetch_update(order, order, |old| Some(old.max(val))).unwrap()
164            }
165
166            /// Minimum with the current value. Returns the previous value.
167            pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
168                self.fetch_update(order, order, |old| Some(old.min(val))).unwrap()
169            }
170
171            /// Load the atomic value directly without triggering any Shuttle context switches.
172            ///
173            /// # Safety
174            ///
175            /// Shuttle does not consider potential concurrent interleavings of this function call,
176            /// and so it should be used when those interleavings aren't important (primarily in
177            /// debugging scenarios where we might want to just print this atomic's value).
178            pub unsafe fn raw_load(&self) -> $int_type {
179                self.inner.raw_load()
180            }
181
182            #[cfg(test)]
183            pub(crate) fn signature(&self) -> crate::sync::ResourceSignature {
184                self.inner.signature()
185            }
186        }
187    };
188}
189
190atomic_int!(AtomicI8, i8);
191atomic_int!(AtomicI16, i16);
192atomic_int!(AtomicI32, i32);
193atomic_int!(AtomicI64, i64);
194atomic_int!(AtomicI128, i128);
195atomic_int!(AtomicIsize, isize);
196atomic_int!(AtomicU8, u8);
197atomic_int!(AtomicU16, u16);
198atomic_int!(AtomicU32, u32);
199atomic_int!(AtomicU64, u64);
200atomic_int!(AtomicU128, u128);
201atomic_int!(AtomicUsize, usize);