Skip to main content

std/sys/sync/once/
no_threads.rs

1use crate::cell::Cell;
2use crate::sync as public;
3use crate::sync::once::OnceExclusiveState;
4
5pub struct Once {
6    state: Cell<State>,
7}
8
9pub struct OnceState {
10    poisoned: bool,
11    set_state_to: Cell<State>,
12}
13
14#[derive(Clone, Copy, PartialEq, Eq)]
15enum State {
16    Incomplete,
17    Poisoned,
18    Running,
19    Complete,
20}
21
22struct CompletionGuard<'a> {
23    state: &'a Cell<State>,
24    set_state_on_drop_to: State,
25}
26
27impl<'a> Drop for CompletionGuard<'a> {
28    fn drop(&mut self) {
29        self.state.set(self.set_state_on_drop_to);
30    }
31}
32
33// Safety: threads are not supported on this platform.
34unsafe impl Sync for Once {}
35
36impl Once {
37    #[inline]
38    pub const fn new() -> Once {
39        Once { state: Cell::new(State::Incomplete) }
40    }
41
42    #[inline]
43    pub const fn new_complete() -> Once {
44        Once { state: Cell::new(State::Complete) }
45    }
46
47    #[inline]
48    pub fn is_completed(&self) -> bool {
49        self.state.get() == State::Complete
50    }
51
52    #[inline]
53    pub(crate) fn state(&mut self) -> OnceExclusiveState {
54        match self.state.get() {
55            State::Incomplete => OnceExclusiveState::Incomplete,
56            State::Poisoned => OnceExclusiveState::Poisoned,
57            State::Complete => OnceExclusiveState::Complete,
58            _ => unreachable!("invalid Once state"),
59        }
60    }
61
62    #[inline]
63    pub(crate) fn set_state(&mut self, new_state: OnceExclusiveState) {
64        self.state.set(match new_state {
65            OnceExclusiveState::Incomplete => State::Incomplete,
66            OnceExclusiveState::Poisoned => State::Poisoned,
67            OnceExclusiveState::Complete => State::Complete,
68        });
69    }
70
71    #[cold]
72    #[track_caller]
73    pub fn wait(&self, _ignore_poisoning: bool) {
74        panic!("not implementable on this target");
75    }
76
77    #[cold]
78    #[track_caller]
79    pub fn call(&self, ignore_poisoning: bool, f: &mut impl FnMut(&public::OnceState)) {
80        let state = self.state.get();
81        match state {
82            State::Poisoned if !ignore_poisoning => {
83                // Panic to propagate the poison.
84                panic!("Once instance has previously been poisoned");
85            }
86            State::Incomplete | State::Poisoned => {
87                self.state.set(State::Running);
88                // `guard` will set the new state on drop.
89                let mut guard =
90                    CompletionGuard { state: &self.state, set_state_on_drop_to: State::Poisoned };
91                // Run the function, letting it know if we're poisoned or not.
92                let f_state = public::OnceState {
93                    inner: OnceState {
94                        poisoned: state == State::Poisoned,
95                        set_state_to: Cell::new(State::Complete),
96                    },
97                };
98                f(&f_state);
99                guard.set_state_on_drop_to = f_state.inner.set_state_to.get();
100            }
101            State::Running => {
102                panic!("one-time initialization may not be performed recursively");
103            }
104            State::Complete => {}
105        }
106    }
107}
108
109impl OnceState {
110    #[inline]
111    pub fn is_poisoned(&self) -> bool {
112        self.poisoned
113    }
114
115    #[inline]
116    pub fn poison(&self) {
117        self.set_state_to.set(State::Poisoned)
118    }
119}