std/sys/sync/once/
no_threads.rs

1use crate::cell::Cell;
2use crate::sync as public;
3use crate::sync::poison::once::ExclusiveState;
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 fn is_completed(&self) -> bool {
44        self.state.get() == State::Complete
45    }
46
47    #[inline]
48    pub(crate) fn state(&mut self) -> ExclusiveState {
49        match self.state.get() {
50            State::Incomplete => ExclusiveState::Incomplete,
51            State::Poisoned => ExclusiveState::Poisoned,
52            State::Complete => ExclusiveState::Complete,
53            _ => unreachable!("invalid Once state"),
54        }
55    }
56
57    #[inline]
58    pub(crate) fn set_state(&mut self, new_state: ExclusiveState) {
59        self.state.set(match new_state {
60            ExclusiveState::Incomplete => State::Incomplete,
61            ExclusiveState::Poisoned => State::Poisoned,
62            ExclusiveState::Complete => State::Complete,
63        });
64    }
65
66    #[cold]
67    #[track_caller]
68    pub fn wait(&self, _ignore_poisoning: bool) {
69        panic!("not implementable on this target");
70    }
71
72    #[cold]
73    #[track_caller]
74    pub fn call(&self, ignore_poisoning: bool, f: &mut impl FnMut(&public::OnceState)) {
75        let state = self.state.get();
76        match state {
77            State::Poisoned if !ignore_poisoning => {
78                // Panic to propagate the poison.
79                panic!("Once instance has previously been poisoned");
80            }
81            State::Incomplete | State::Poisoned => {
82                self.state.set(State::Running);
83                // `guard` will set the new state on drop.
84                let mut guard =
85                    CompletionGuard { state: &self.state, set_state_on_drop_to: State::Poisoned };
86                // Run the function, letting it know if we're poisoned or not.
87                let f_state = public::OnceState {
88                    inner: OnceState {
89                        poisoned: state == State::Poisoned,
90                        set_state_to: Cell::new(State::Complete),
91                    },
92                };
93                f(&f_state);
94                guard.set_state_on_drop_to = f_state.inner.set_state_to.get();
95            }
96            State::Running => {
97                panic!("one-time initialization may not be performed recursively");
98            }
99            State::Complete => {}
100        }
101    }
102}
103
104impl OnceState {
105    #[inline]
106    pub fn is_poisoned(&self) -> bool {
107        self.poisoned
108    }
109
110    #[inline]
111    pub fn poison(&self) {
112        self.set_state_to.set(State::Poisoned)
113    }
114}