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)
    }
}