Coverage Report

Created: 2025-10-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/conquer-once-0.3.2/src/state.rs
Line
Count
Source
1
use core::convert::{TryFrom, TryInto};
2
use core::sync::atomic::{AtomicUsize, Ordering};
3
4
#[cfg(feature = "std")]
5
use crate::park::StackWaiter;
6
use crate::POISON_PANIC_MSG;
7
8
use self::OnceState::{Ready, Uninit, WouldBlock};
9
10
const WOULD_BLOCK: usize = 0;
11
const UNINIT: usize = 1;
12
const READY: usize = 2;
13
const POISONED: usize = 3;
14
15
////////////////////////////////////////////////////////////////////////////////////////////////////
16
// AtomicState (public but not exported)
17
////////////////////////////////////////////////////////////////////////////////////////////////////
18
19
/// The concurrently and atomically mutable internal state of a [`OnceCell`].
20
///
21
/// A `WOULD_BLOCK` value is also interpreted as a `null` pointer to an empty
22
/// [`WaiterQueue`] indicating that there is only a single blocked thread.
23
#[derive(Debug)]
24
pub struct AtomicOnceState(AtomicUsize);
25
26
/********** impl inherent *************************************************************************/
27
28
impl AtomicOnceState {
29
    /// Creates a new `UNINIT` state.
30
    #[inline]
31
    pub(crate) const fn new() -> Self {
32
        Self(AtomicUsize::new(UNINIT))
33
    }
34
35
    /// Creates a new `READY` state.
36
    #[inline]
37
    pub(crate) const fn ready() -> Self {
38
        Self(AtomicUsize::new(READY))
39
    }
40
41
    /// Loads the current state using `ordering`.
42
    ///
43
    /// A Poisoning of the state is returned as a [`PoisonError`].
44
    #[inline]
45
0
    pub(crate) fn load(&self, order: Ordering) -> Result<OnceState, PoisonError> {
46
0
        self.0.load(order).try_into()
47
0
    }
48
49
    /// Attempts to set the state to blocked and fails if the state is either
50
    /// already initialized or blocked.
51
    #[inline]
52
0
    pub(crate) fn try_block(&self, order: Ordering) -> Result<(), TryBlockError> {
53
0
        let prev = match self.0.compare_exchange(UNINIT, WOULD_BLOCK, order, Ordering::Relaxed) {
54
0
            Ok(prev) => prev,
55
0
            Err(prev) => prev,
56
        };
57
58
0
        match prev.try_into().expect(POISON_PANIC_MSG) {
59
0
            Uninit => Ok(()),
60
0
            Ready => Err(TryBlockError::AlreadyInit),
61
0
            WouldBlock(state) => Err(TryBlockError::WouldBlock(state)),
62
        }
63
0
    }
64
65
    /// Unblocks the state by replacing it with either `Ready` or `Poisoned`.
66
    ///
67
    /// # Safety
68
    ///
69
    /// Must not be called if unblocking might cause data races due to
70
    /// un-synchronized reads and/or writes.
71
    #[inline]
72
0
    pub(crate) unsafe fn unblock(&self, state: SwapState, order: Ordering) -> BlockedState {
73
0
        BlockedState(self.0.swap(state as usize, order))
74
0
    }
75
76
    #[cfg(feature = "std")]
77
    /// Attempts to compare-and-swap the head of the `current` [`WaiterQueue]`
78
    /// with the `next` queue.
79
    #[inline]
80
    pub(crate) unsafe fn try_swap_blocked(
81
        &self,
82
        current: BlockedState,
83
        new: BlockedState,
84
        success: Ordering,
85
    ) -> Result<(), OnceState> {
86
        let prev =
87
            match self.0.compare_exchange(current.into(), new.into(), success, Ordering::Relaxed) {
88
                Ok(prev) => prev,
89
                Err(prev) => prev,
90
            };
91
92
        match prev {
93
            prev if prev == current.into() => Ok(()),
94
            prev => Err(prev.try_into().expect(POISON_PANIC_MSG)),
95
        }
96
    }
97
}
98
99
////////////////////////////////////////////////////////////////////////////////////////////////////
100
// OnceState
101
////////////////////////////////////////////////////////////////////////////////////////////////////
102
103
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
104
pub(crate) enum OnceState {
105
    /// Initial (uninitialized) state.
106
    Uninit,
107
    /// Ready (initialized) state.
108
    Ready,
109
    /// Blocked state with queue of waiting threads.
110
    WouldBlock(BlockedState),
111
}
112
113
/********** impl TryFrom **************************************************************************/
114
115
impl TryFrom<usize> for OnceState {
116
    type Error = PoisonError;
117
118
    #[inline]
119
0
    fn try_from(value: usize) -> Result<Self, Self::Error> {
120
0
        match value {
121
0
            POISONED => Err(PoisonError),
122
0
            UNINIT => Ok(Uninit),
123
0
            READY => Ok(Ready),
124
0
            state => Ok(WouldBlock(BlockedState(state))),
125
        }
126
0
    }
127
}
128
129
/********** impl From (usize) *********************************************************************/
130
131
impl From<OnceState> for usize {
132
    #[inline]
133
    fn from(state: OnceState) -> Self {
134
        match state {
135
            OnceState::Ready => READY,
136
            OnceState::Uninit => UNINIT,
137
            OnceState::WouldBlock(BlockedState(state)) => state,
138
        }
139
    }
140
}
141
142
////////////////////////////////////////////////////////////////////////////////////////////////////
143
// TryBlockError
144
////////////////////////////////////////////////////////////////////////////////////////////////////
145
146
#[derive(Debug)]
147
pub enum TryBlockError {
148
    AlreadyInit,
149
    WouldBlock(BlockedState),
150
}
151
152
////////////////////////////////////////////////////////////////////////////////////////////////////
153
// PoisonError
154
////////////////////////////////////////////////////////////////////////////////////////////////////
155
156
/// An error type indicating a `OnceCell` has been poisoned.
157
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
158
pub struct PoisonError;
159
160
////////////////////////////////////////////////////////////////////////////////////////////////////
161
// BlockedState (public but not exported)
162
////////////////////////////////////////////////////////////////////////////////////////////////////
163
164
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
165
pub struct BlockedState(usize);
166
167
/********** impl inherent *************************************************************************/
168
169
impl BlockedState {
170
    #[cfg(feature = "std")]
171
    pub(crate) fn as_ptr(self) -> *const () {
172
        self.0 as *const _
173
    }
174
}
175
176
/********** impl From (for usize) *****************************************************************/
177
178
impl From<BlockedState> for usize {
179
    #[inline]
180
    fn from(state: BlockedState) -> Self {
181
        state.0
182
    }
183
}
184
185
/********** impl From (*const StackWaiter) ********************************************************/
186
187
#[cfg(feature = "std")]
188
impl From<*const StackWaiter> for BlockedState {
189
    #[inline]
190
    fn from(waiter: *const StackWaiter) -> Self {
191
        Self(waiter as usize)
192
    }
193
}
194
195
////////////////////////////////////////////////////////////////////////////////////////////////////
196
// SwapState
197
////////////////////////////////////////////////////////////////////////////////////////////////////
198
199
#[repr(usize)]
200
pub(crate) enum SwapState {
201
    Ready = READY,
202
    Poisoned = POISONED,
203
}