Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_platform/src/sync/once.rs
6849 views
1
//! Provides `Once`, `OnceState`, `OnceLock`
2
3
pub use implementation::{Once, OnceLock, OnceState};
4
5
#[cfg(feature = "std")]
6
use std::sync as implementation;
7
8
#[cfg(not(feature = "std"))]
9
mod implementation {
10
use core::{
11
fmt,
12
panic::{RefUnwindSafe, UnwindSafe},
13
};
14
15
/// Fallback implementation of `OnceLock` from the standard library.
16
pub struct OnceLock<T> {
17
inner: spin::Once<T>,
18
}
19
20
impl<T> OnceLock<T> {
21
/// Creates a new empty cell.
22
///
23
/// See the standard library for further details.
24
#[must_use]
25
pub const fn new() -> Self {
26
Self {
27
inner: spin::Once::new(),
28
}
29
}
30
31
/// Gets the reference to the underlying value.
32
///
33
/// See the standard library for further details.
34
pub fn get(&self) -> Option<&T> {
35
self.inner.get()
36
}
37
38
/// Gets the mutable reference to the underlying value.
39
///
40
/// See the standard library for further details.
41
pub fn get_mut(&mut self) -> Option<&mut T> {
42
self.inner.get_mut()
43
}
44
45
/// Sets the contents of this cell to `value`.
46
///
47
/// See the standard library for further details.
48
pub fn set(&self, value: T) -> Result<(), T> {
49
let mut value = Some(value);
50
51
self.inner.call_once(|| value.take().unwrap());
52
53
match value {
54
Some(value) => Err(value),
55
None => Ok(()),
56
}
57
}
58
59
/// Gets the contents of the cell, initializing it with `f` if the cell
60
/// was empty.
61
///
62
/// See the standard library for further details.
63
pub fn get_or_init<F>(&self, f: F) -> &T
64
where
65
F: FnOnce() -> T,
66
{
67
self.inner.call_once(f)
68
}
69
70
/// Consumes the `OnceLock`, returning the wrapped value. Returns
71
/// `None` if the cell was empty.
72
///
73
/// See the standard library for further details.
74
pub fn into_inner(mut self) -> Option<T> {
75
self.take()
76
}
77
78
/// Takes the value out of this `OnceLock`, moving it back to an uninitialized state.
79
///
80
/// See the standard library for further details.
81
pub fn take(&mut self) -> Option<T> {
82
if self.inner.is_completed() {
83
let mut inner = spin::Once::new();
84
85
core::mem::swap(&mut self.inner, &mut inner);
86
87
inner.try_into_inner()
88
} else {
89
None
90
}
91
}
92
}
93
94
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
95
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
96
97
impl<T> Default for OnceLock<T> {
98
fn default() -> OnceLock<T> {
99
OnceLock::new()
100
}
101
}
102
103
impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
104
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105
let mut d = f.debug_tuple("OnceLock");
106
match self.get() {
107
Some(v) => d.field(v),
108
None => d.field(&format_args!("<uninit>")),
109
};
110
d.finish()
111
}
112
}
113
114
impl<T: Clone> Clone for OnceLock<T> {
115
fn clone(&self) -> OnceLock<T> {
116
let cell = Self::new();
117
if let Some(value) = self.get() {
118
cell.set(value.clone()).ok().unwrap();
119
}
120
cell
121
}
122
}
123
124
impl<T> From<T> for OnceLock<T> {
125
fn from(value: T) -> Self {
126
let cell = Self::new();
127
cell.set(value).map(move |_| cell).ok().unwrap()
128
}
129
}
130
131
impl<T: PartialEq> PartialEq for OnceLock<T> {
132
fn eq(&self, other: &OnceLock<T>) -> bool {
133
self.get() == other.get()
134
}
135
}
136
137
impl<T: Eq> Eq for OnceLock<T> {}
138
139
/// Fallback implementation of `Once` from the standard library.
140
pub struct Once {
141
inner: OnceLock<()>,
142
}
143
144
impl Once {
145
/// Creates a new `Once` value.
146
///
147
/// See the standard library for further details.
148
#[expect(clippy::new_without_default, reason = "matching std::sync::Once")]
149
pub const fn new() -> Self {
150
Self {
151
inner: OnceLock::new(),
152
}
153
}
154
155
/// Performs an initialization routine once and only once. The given closure
156
/// will be executed if this is the first time `call_once` has been called,
157
/// and otherwise the routine will *not* be invoked.
158
///
159
/// See the standard library for further details.
160
pub fn call_once<F: FnOnce()>(&self, f: F) {
161
self.inner.get_or_init(f);
162
}
163
164
/// Performs the same function as [`call_once()`] except ignores poisoning.
165
///
166
/// See the standard library for further details.
167
pub fn call_once_force<F: FnOnce(&OnceState)>(&self, f: F) {
168
const STATE: OnceState = OnceState { _private: () };
169
170
self.call_once(move || f(&STATE));
171
}
172
173
/// Returns `true` if some [`call_once()`] call has completed
174
/// successfully. Specifically, `is_completed` will return false in
175
/// the following situations:
176
/// * [`call_once()`] was not called at all,
177
/// * [`call_once()`] was called, but has not yet completed,
178
/// * the [`Once`] instance is poisoned
179
///
180
/// See the standard library for further details.
181
pub fn is_completed(&self) -> bool {
182
self.inner.get().is_some()
183
}
184
}
185
186
impl RefUnwindSafe for Once {}
187
impl UnwindSafe for Once {}
188
189
impl fmt::Debug for Once {
190
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191
f.debug_struct("Once").finish_non_exhaustive()
192
}
193
}
194
195
/// Fallback implementation of `OnceState` from the standard library.
196
pub struct OnceState {
197
_private: (),
198
}
199
200
impl OnceState {
201
/// Returns `true` if the associated [`Once`] was poisoned prior to the
202
/// invocation of the closure passed to [`Once::call_once_force()`].
203
///
204
/// See the standard library for further details.
205
pub fn is_poisoned(&self) -> bool {
206
false
207
}
208
}
209
210
impl fmt::Debug for OnceState {
211
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212
f.debug_struct("OnceState")
213
.field("poisoned", &self.is_poisoned())
214
.finish()
215
}
216
}
217
}
218
219