1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
use super::Atomic;
use std::sync::atomic::Ordering;
/// Mock implementation of `std::sync::atomic::AtomicBool`.
///
/// NOTE: Unlike `std::sync::atomic::AtomicBool`, this type has a different
/// in-memory representation than `bool`.
#[derive(Debug)]
pub struct AtomicBool(Atomic<bool>);
impl AtomicBool {
/// Creates a new instance of `AtomicBool`.
#[track_caller]
pub fn new(v: bool) -> AtomicBool {
AtomicBool(Atomic::new(v, location!()))
}
/// Load the value without any synchronization.
///
/// # Safety
///
/// An unsynchronized atomic load technically always has undefined behavior.
/// However, if the atomic value is not currently visible by other threads,
/// this *should* always be equivalent to a non-atomic load of an un-shared
/// `bool` value.
#[track_caller]
pub unsafe fn unsync_load(&self) -> bool {
self.0.unsync_load()
}
/// Consumes the atomic and returns the contained value.
#[track_caller]
pub fn into_inner(self) -> bool {
// SAFETY: ownership guarantees that no other threads are concurrently
// accessing the atomic value.
unsafe { self.unsync_load() }
}
/// Loads a value from the atomic bool.
#[track_caller]
pub fn load(&self, order: Ordering) -> bool {
self.0.load(order)
}
/// Stores a value into the atomic bool.
#[track_caller]
pub fn store(&self, val: bool, order: Ordering) {
self.0.store(val, order)
}
/// Stores a value into the atomic bool, returning the previous value.
#[track_caller]
pub fn swap(&self, val: bool, order: Ordering) -> bool {
self.0.swap(val, order)
}
/// Stores a value into the atomic bool if the current value is the same as the `current` value.
#[track_caller]
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
self.0.compare_and_swap(current, new, order)
}
/// Stores a value into the atomic if the current value is the same as the `current` value.
#[track_caller]
pub fn compare_exchange(
&self,
current: bool,
new: bool,
success: Ordering,
failure: Ordering,
) -> Result<bool, bool> {
self.0.compare_exchange(current, new, success, failure)
}
/// Stores a value into the atomic if the current value is the same as the current value.
#[track_caller]
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.
#[track_caller]
pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
self.0.rmw(|v| v & val, order)
}
/// Logical "nand" with the current value.
#[track_caller]
pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
self.0.rmw(|v| !(v & val), order)
}
/// Logical "or" with the current value.
#[track_caller]
pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
self.0.rmw(|v| v | val, order)
}
/// Logical "xor" with the current value.
#[track_caller]
pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
self.0.rmw(|v| v ^ 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)`.
#[track_caller]
pub fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<bool, bool>
where
F: FnMut(bool) -> Option<bool>,
{
self.0.fetch_update(set_order, fetch_order, f)
}
}
impl Default for AtomicBool {
fn default() -> AtomicBool {
AtomicBool::new(Default::default())
}
}
impl From<bool> for AtomicBool {
fn from(b: bool) -> Self {
Self::new(b)
}
}