std/sys/sync/once/
no_threads.rs1use 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
33unsafe 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!("Once instance has previously been poisoned");
80 }
81 State::Incomplete | State::Poisoned => {
82 self.state.set(State::Running);
83 let mut guard =
85 CompletionGuard { state: &self.state, set_state_on_drop_to: State::Poisoned };
86 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}