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 fetch_update<F>(&self, set_order: Ordering, fetch_order: Ordering, f: F) -> Result<bool, bool>
65    where
66        F: FnMut(bool) -> Option<bool>,
67    {
68        self.inner.fetch_update(set_order, fetch_order, f)
69    }
70
71    /// Stores a value into the atomic boolean if the current value is the same as the
72    /// `current` value.
73    #[deprecated(since = "0.0.6", note = "Use `compare_exchange` or `compare_exchange_weak` instead")]
74    pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
75        match self.compare_exchange(current, new, order, order) {
76            Ok(v) => v,
77            Err(v) => v,
78        }
79    }
80
81    /// Stores a value into the atomic boolean if the current value is the same as the
82    /// `current` value.
83    ///
84    /// The return value is a result indicating whether the new value was written and
85    /// containing the previous value. On success this value is guaranteed to be equal to
86    /// `current`.
87    pub fn compare_exchange(
88        &self,
89        current: bool,
90        new: bool,
91        success: Ordering,
92        failure: Ordering,
93    ) -> Result<bool, bool> {
94        self.fetch_update(success, failure, |val| (val == current).then_some(new))
95    }
96
97    /// Stores a value into the atomic boolean if the current value is the same as the
98    /// `current` value.
99    ///
100    /// Unlike [`AtomicBool::compare_exchange`], this function is allowed to spuriously fail
101    /// even when the comparison succeeds, which can result in more efficient code on some
102    /// platforms. The return value is a result indicating whether the new value was written
103    /// and containing the previous value.
104    // TODO actually produce spurious failures
105    pub fn compare_exchange_weak(
106        &self,
107        current: bool,
108        new: bool,
109        success: Ordering,
110        failure: Ordering,
111    ) -> Result<bool, bool> {
112        self.compare_exchange(current, new, success, failure)
113    }
114
115    /// Logical "and" with the current value. Returns the previous value.
116    pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
117        self.fetch_update(order, order, |old| Some(old & val)).unwrap()
118    }
119
120    /// Logical "nand" with the current value. Returns the previous value.
121    pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
122        self.fetch_update(order, order, |old| Some(!(old & val))).unwrap()
123    }
124
125    /// Logical "or" with the current value. Returns the previous value.
126    pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
127        self.fetch_update(order, order, |old| Some(old | val)).unwrap()
128    }
129
130    /// Logical "xor" with the current value. Returns the previous value.
131    pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
132        self.fetch_update(order, order, |old| Some(old ^ val)).unwrap()
133    }
134
135    /// Load the atomic value directly without triggering any Shuttle context switches.
136    ///
137    /// # Safety
138    ///
139    /// Shuttle does not consider potential concurrent interleavings of this function call,
140    /// and so it should be used when those interleavings aren't important (primarily in
141    /// debugging scenarios where we might want to just print this atomic's value).
142    pub unsafe fn raw_load(&self) -> bool {
143        self.inner.raw_load()
144    }
145
146    #[cfg(test)]
147    pub(crate) fn signature(&self) -> ResourceSignature {
148        self.inner.signature()
149    }
150}