Skip to main content

shuttle_std/sync/atomic/
bool.rs

1use crate::sync::atomic::Atomic;
2#[cfg(test)]
3use crate::sync::ResourceSignature;
4use std::sync::atomic::Ordering;
5
6/// A boolean type which can be safely shared between threads.
7pub struct AtomicBool {
8    inner: Atomic<bool>,
9}
10
11impl Default for AtomicBool {
12    fn default() -> Self {
13        Self::new(Default::default())
14    }
15}
16
17impl From<bool> for AtomicBool {
18    fn from(b: bool) -> Self {
19        Self::new(b)
20    }
21}
22
23impl std::fmt::Debug for AtomicBool {
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
29impl AtomicBool {
30    /// Creates a new atomic boolean.
31    #[track_caller]
32    pub const fn new(v: bool) -> Self {
33        Self { inner: Atomic::new(v) }
34    }
35
36    /// Returns a mutable reference to the underlying boolean.
37    pub fn get_mut(&mut self) -> &mut bool {
38        self.inner.get_mut()
39    }
40
41    /// Consumes the atomic and returns the contained value.
42    pub fn into_inner(self) -> bool {
43        self.inner.into_inner()
44    }
45
46    /// Loads a value from the atomic boolean.
47    pub fn load(&self, order: Ordering) -> bool {
48        self.inner.load(order)
49    }
50
51    /// Stores a value into the atomic boolean.
52    pub fn store(&self, val: bool, order: Ordering) {
53        self.inner.store(val, order)
54    }
55
56    /// Stores a value into the atomic boolean, returning the previous value.
57    pub fn swap(&self, val: bool, order: Ordering) -> bool {
58        self.inner.swap(val, order)
59    }
60
61    /// Fetches the value, and applies a function to it that returns an optional new value.
62    /// Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
63    /// `Err(previous_value)`.
64    pub fn try_update(
65        &self,
66        set_order: Ordering,
67        fetch_order: Ordering,
68        mut f: impl FnMut(bool) -> Option<bool>,
69    ) -> Result<bool, bool> {
70        let mut prev = self.load(fetch_order);
71        while let Some(next) = f(prev) {
72            match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
73                x @ Ok(_) => return x,
74                Err(next_prev) => prev = next_prev,
75            }
76        }
77        Err(prev)
78    }
79
80    /// Fetches the value, and applies a function to it that returns an optional new value.
81    ///
82    /// Since Rust 1.95 this is an alias for [`try_update`](Self::try_update). Deprecated since
83    /// Rust 1.99.
84    pub fn fetch_update<F>(&self, set_order: Ordering, fetch_order: Ordering, f: F) -> Result<bool, bool>
85    where
86        F: FnMut(bool) -> Option<bool>,
87    {
88        self.try_update(set_order, fetch_order, f)
89    }
90
91    /// Fetches the value, applies a function to it that returns a new value, and stores the new
92    /// value. Returns the previous value.
93    pub fn update(&self, set_order: Ordering, fetch_order: Ordering, mut f: impl FnMut(bool) -> bool) -> bool {
94        let mut prev = self.load(fetch_order);
95        loop {
96            match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
97                Ok(x) => break x,
98                Err(next_prev) => prev = next_prev,
99            }
100        }
101    }
102
103    /// Stores a value into the atomic boolean if the current value is the same as the
104    /// `current` value.
105    #[deprecated(since = "0.0.6", note = "Use `compare_exchange` or `compare_exchange_weak` instead")]
106    pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
107        match self.compare_exchange(current, new, order, order) {
108            Ok(v) => v,
109            Err(v) => v,
110        }
111    }
112
113    /// Stores a value into the atomic boolean if the current value is the same as the
114    /// `current` value.
115    ///
116    /// The return value is a result indicating whether the new value was written and
117    /// containing the previous value. On success this value is guaranteed to be equal to
118    /// `current`.
119    pub fn compare_exchange(
120        &self,
121        current: bool,
122        new: bool,
123        success: Ordering,
124        failure: Ordering,
125    ) -> Result<bool, bool> {
126        self.inner
127            .try_update(success, failure, |val| (val == current).then_some(new))
128    }
129
130    /// Stores a value into the atomic boolean if the current value is the same as the
131    /// `current` value.
132    ///
133    /// Unlike [`AtomicBool::compare_exchange`], this function is allowed to spuriously fail
134    /// even when the comparison succeeds, which can result in more efficient code on some
135    /// platforms. The return value is a result indicating whether the new value was written
136    /// and containing the previous value.
137    // TODO actually produce spurious failures
138    pub fn compare_exchange_weak(
139        &self,
140        current: bool,
141        new: bool,
142        success: Ordering,
143        failure: Ordering,
144    ) -> Result<bool, bool> {
145        self.compare_exchange(current, new, success, failure)
146    }
147
148    /// Logical "and" with the current value. Returns the previous value.
149    pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
150        self.inner.try_update(order, order, |old| Some(old & val)).unwrap()
151    }
152
153    /// Logical "nand" with the current value. Returns the previous value.
154    pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
155        self.inner.try_update(order, order, |old| Some(!(old & val))).unwrap()
156    }
157
158    /// Logical "or" with the current value. Returns the previous value.
159    pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
160        self.inner.try_update(order, order, |old| Some(old | val)).unwrap()
161    }
162
163    /// Logical "xor" with the current value. Returns the previous value.
164    pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
165        self.inner.try_update(order, order, |old| Some(old ^ val)).unwrap()
166    }
167
168    /// Logical "not" with the current value. Returns the previous value.
169    pub fn fetch_not(&self, order: Ordering) -> bool {
170        self.fetch_xor(true, order)
171    }
172
173    /// Load the atomic value directly without triggering any Shuttle context switches.
174    ///
175    /// # Safety
176    ///
177    /// Shuttle does not consider potential concurrent interleavings of this function call,
178    /// and so it should be used when those interleavings aren't important (primarily in
179    /// debugging scenarios where we might want to just print this atomic's value).
180    pub unsafe fn raw_load(&self) -> bool {
181        self.inner.raw_load()
182    }
183
184    #[cfg(test)]
185    pub(crate) fn signature(&self) -> ResourceSignature {
186        self.inner.signature()
187    }
188}