shuttle-std 0.1.5

Mirrors of std compatible with the Shuttle concurrency testing tool
Documentation
use crate::sync::atomic::Atomic;
#[cfg(test)]
use crate::sync::ResourceSignature;
use std::sync::atomic::Ordering;

/// A boolean type which can be safely shared between threads.
pub struct AtomicBool {
    inner: Atomic<bool>,
}

impl Default for AtomicBool {
    fn default() -> Self {
        Self::new(Default::default())
    }
}

impl From<bool> for AtomicBool {
    fn from(b: bool) -> Self {
        Self::new(b)
    }
}

impl std::fmt::Debug for AtomicBool {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(unsafe { &self.raw_load() }, f)
    }
}

impl AtomicBool {
    /// Creates a new atomic boolean.
    #[track_caller]
    pub const fn new(v: bool) -> Self {
        Self { inner: Atomic::new(v) }
    }

    /// Returns a mutable reference to the underlying boolean.
    pub fn get_mut(&mut self) -> &mut bool {
        self.inner.get_mut()
    }

    /// Consumes the atomic and returns the contained value.
    pub fn into_inner(self) -> bool {
        self.inner.into_inner()
    }

    /// Loads a value from the atomic boolean.
    pub fn load(&self, order: Ordering) -> bool {
        self.inner.load(order)
    }

    /// Stores a value into the atomic boolean.
    pub fn store(&self, val: bool, order: Ordering) {
        self.inner.store(val, order)
    }

    /// Stores a value into the atomic boolean, returning the previous value.
    pub fn swap(&self, val: bool, order: Ordering) -> bool {
        self.inner.swap(val, order)
    }

    /// Fetches the value, and applies a function to it that returns an optional new value.
    /// Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
    /// `Err(previous_value)`.
    pub fn try_update(
        &self,
        set_order: Ordering,
        fetch_order: Ordering,
        mut f: impl FnMut(bool) -> Option<bool>,
    ) -> Result<bool, bool> {
        let mut prev = self.load(fetch_order);
        while let Some(next) = f(prev) {
            match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
                x @ Ok(_) => return x,
                Err(next_prev) => prev = next_prev,
            }
        }
        Err(prev)
    }

    /// Fetches the value, and applies a function to it that returns an optional new value.
    ///
    /// Since Rust 1.95 this is an alias for [`try_update`](Self::try_update). Deprecated since
    /// Rust 1.99.
    pub fn fetch_update<F>(&self, set_order: Ordering, fetch_order: Ordering, f: F) -> Result<bool, bool>
    where
        F: FnMut(bool) -> Option<bool>,
    {
        self.try_update(set_order, fetch_order, f)
    }

    /// Fetches the value, applies a function to it that returns a new value, and stores the new
    /// value. Returns the previous value.
    pub fn update(&self, set_order: Ordering, fetch_order: Ordering, mut f: impl FnMut(bool) -> bool) -> bool {
        let mut prev = self.load(fetch_order);
        loop {
            match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
                Ok(x) => break x,
                Err(next_prev) => prev = next_prev,
            }
        }
    }

    /// Stores a value into the atomic boolean if the current value is the same as the
    /// `current` value.
    #[deprecated(since = "0.0.6", note = "Use `compare_exchange` or `compare_exchange_weak` instead")]
    pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
        match self.compare_exchange(current, new, order, order) {
            Ok(v) => v,
            Err(v) => v,
        }
    }

    /// Stores a value into the atomic boolean if the current value is the same as the
    /// `current` value.
    ///
    /// The return value is a result indicating whether the new value was written and
    /// containing the previous value. On success this value is guaranteed to be equal to
    /// `current`.
    pub fn compare_exchange(
        &self,
        current: bool,
        new: bool,
        success: Ordering,
        failure: Ordering,
    ) -> Result<bool, bool> {
        self.inner
            .try_update(success, failure, |val| (val == current).then_some(new))
    }

    /// Stores a value into the atomic boolean if the current value is the same as the
    /// `current` value.
    ///
    /// Unlike [`AtomicBool::compare_exchange`], this function is allowed to spuriously fail
    /// even when the comparison succeeds, which can result in more efficient code on some
    /// platforms. The return value is a result indicating whether the new value was written
    /// and containing the previous value.
    // TODO actually produce spurious failures
    pub fn compare_exchange_weak(
        &self,
        current: bool,
        new: bool,
        success: Ordering,
        failure: Ordering,
    ) -> Result<bool, bool> {
        self.compare_exchange(current, new, success, failure)
    }

    /// Logical "and" with the current value. Returns the previous value.
    pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
        self.inner.try_update(order, order, |old| Some(old & val)).unwrap()
    }

    /// Logical "nand" with the current value. Returns the previous value.
    pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
        self.inner.try_update(order, order, |old| Some(!(old & val))).unwrap()
    }

    /// Logical "or" with the current value. Returns the previous value.
    pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
        self.inner.try_update(order, order, |old| Some(old | val)).unwrap()
    }

    /// Logical "xor" with the current value. Returns the previous value.
    pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
        self.inner.try_update(order, order, |old| Some(old ^ val)).unwrap()
    }

    /// Logical "not" with the current value. Returns the previous value.
    pub fn fetch_not(&self, order: Ordering) -> bool {
        self.fetch_xor(true, order)
    }

    /// Load the atomic value directly without triggering any Shuttle context switches.
    ///
    /// # Safety
    ///
    /// Shuttle does not consider potential concurrent interleavings of this function call,
    /// and so it should be used when those interleavings aren't important (primarily in
    /// debugging scenarios where we might want to just print this atomic's value).
    pub unsafe fn raw_load(&self) -> bool {
        self.inner.raw_load()
    }

    #[cfg(test)]
    pub(crate) fn signature(&self) -> ResourceSignature {
        self.inner.signature()
    }
}