poly_once/once.rs
1//! Standard once cell for one-time initialization.
2//!
3//! This module provides the [`Once<T>`] type, a thread-safe cell that can be
4//! written to exactly once. It's useful for lazy initialization of global state,
5//! caching expensive computations, or any scenario where you need to ensure
6//! initialization happens exactly once across multiple threads.
7//!
8//! The implementation uses atomic operations for the fast path (checking if
9//! initialized) and futex-based synchronization for the slow path (waiting
10//! for initialization to complete).
11
12use core::cell::UnsafeCell;
13use core::future::Future;
14use core::sync::atomic::Ordering;
15use core::{fmt, mem};
16
17use super::state::OnceLock;
18
19/// A thread-safe cell which can be written to only once.
20///
21/// This structure provides safe initialization for values that might be accessed
22/// concurrently by multiple threads. It ensures that the initialization logic
23/// runs only once, even if multiple threads attempt to initialize the value simultaneously.
24///
25/// It uses atomic operations and `parking_lot`'s futex-based synchronization for
26/// efficient blocking when necessary.
27pub struct Once<T> {
28 value: UnsafeCell<mem::MaybeUninit<T>>,
29 lock: OnceLock,
30}
31
32impl<T> Once<T> {
33 /// Creates a new, uninitialized `Once` cell.
34 #[inline]
35 #[must_use]
36 pub const fn new() -> Self {
37 Self {
38 lock: OnceLock::new(),
39 value: UnsafeCell::new(mem::MaybeUninit::uninit()),
40 }
41 }
42
43 /// Creates a new `Once` cell that is already initialized with the given value.
44 #[inline]
45 #[must_use]
46 pub const fn with_value(value: T) -> Self {
47 Self {
48 lock: OnceLock::done(),
49 value: UnsafeCell::new(mem::MaybeUninit::new(value)),
50 }
51 }
52
53 /// Checks if the cell has been initialized.
54 ///
55 /// This method never blocks.
56 #[inline]
57 pub fn is_done(&self) -> bool {
58 self.lock.is_done(Ordering::Relaxed)
59 }
60
61 /// Returns a reference to the contained value if initialized.
62 ///
63 /// Returns `None` if the cell is uninitialized or currently being initialized.
64 /// This method never blocks.
65 #[inline]
66 pub fn get(&self) -> Option<&T> {
67 if self.is_done() {
68 // SAFETY: is_done() returned true, so the value is initialized.
69 Some(unsafe { self.get_unchecked() })
70 } else {
71 None
72 }
73 }
74
75 /// Returns a mutable reference to the contained value if initialized.
76 ///
77 /// Returns `None` if the cell is uninitialized or currently being initialized.
78 /// This method requires exclusive access (`&mut self`) and never blocks.
79 #[inline]
80 pub fn get_mut(&mut self) -> Option<&mut T> {
81 if self.is_done() {
82 // SAFETY: is_done() returned true and we have exclusive access (`&mut self`).
83 Some(unsafe { self.get_unchecked_mut() })
84 } else {
85 None
86 }
87 }
88
89 /// Attempts to initialize the cell with `value` without blocking.
90 ///
91 /// - If the cell is uninitialized and not locked, initializes it with `value` and returns `Ok(&value)`.
92 /// - If the cell is already initialized, returns `Err(value)`.
93 /// - If the cell is currently locked by another thread, returns `Err(value)`.
94 #[inline]
95 pub fn try_set(&self, value: T) -> Result<&T, T> {
96 let Some(guard) = self.lock.try_lock() else {
97 return Err(value);
98 };
99 // SAFETY: We hold the lock, so we have exclusive access to initialize the value.
100 let refv = unsafe { (*self.value.get()).write(value) };
101 guard.commit();
102 Ok(refv)
103 }
104
105 /// Replaces the cell's value, returning the old value if initialized.
106 ///
107 /// - If uninitialized, sets the value to `value` and returns `None`.
108 /// - If initialized, replaces the existing value with `value` and returns the old value.
109 ///
110 /// Requires exclusive access (`&mut self`), so it never blocks.
111 #[inline]
112 pub fn replace_mut(&mut self, value: T) -> Option<T> {
113 let mref = self.value.get_mut();
114
115 if self.lock.set_done() {
116 // Was uninitialized, now set to done. Write the new value.
117 mref.write(value);
118 None
119 } else {
120 // Was already initialized. Replace the existing value.
121 // SAFETY: We have exclusive access and the cell is initialized.
122 let old_value = unsafe { mref.assume_init_mut() };
123 Some(mem::replace(old_value, value))
124 }
125 }
126
127 /// Gets a mutable reference, initializing with `value` if needed.
128 ///
129 /// - If initialized, returns a mutable reference to the existing value.
130 /// - If uninitialized, initializes it with `value` and returns a mutable reference.
131 ///
132 /// Requires exclusive access (`&mut self`), so it never blocks.
133 #[inline]
134 pub fn get_mut_or_set(&mut self, value: T) -> &mut T {
135 if self.lock.set_done() {
136 // Was uninitialized, now set to done. Write the new value.
137 self.value.get_mut().write(value);
138 }
139 // SAFETY: The cell is guaranteed to be initialized here, either previously
140 // or by the call above, and we have exclusive access.
141 unsafe { self.get_unchecked_mut() }
142 }
143
144 /// Gets a mutable reference, initializing with `Default::default()` if needed.
145 ///
146 /// - If initialized, returns a mutable reference to the existing value.
147 /// - If uninitialized, initializes it with `T::default()` and returns a mutable reference.
148 ///
149 /// Requires exclusive access (`&mut self`), so it never blocks.
150 #[inline]
151 pub fn get_mut_or_default(&mut self) -> &mut T
152 where
153 T: Default,
154 {
155 if self.lock.set_done() {
156 // Was uninitialized, now set to done. Write the default value.
157 self.value.get_mut().write(T::default());
158 }
159 // SAFETY: The cell is guaranteed to be initialized here, either previously
160 // or by the call above, and we have exclusive access.
161 unsafe { self.get_unchecked_mut() }
162 }
163
164 /// Returns a reference to the value without checking if it's initialized.
165 ///
166 /// # Safety
167 ///
168 /// Calling this method on an uninitialized `Once` cell is *undefined behavior*.
169 /// The caller must ensure the cell is initialized, e.g., by calling `is_done()` or `get()`.
170 #[inline]
171 pub unsafe fn get_unchecked(&self) -> &T {
172 debug_assert!(self.is_done(), "get_unchecked called on uninitialized Once");
173 // SAFETY: The caller guarantees that the cell is initialized.
174 (*self.value.get()).assume_init_ref()
175 }
176
177 /// Returns a mutable reference to the value without checking if it's initialized.
178 ///
179 /// # Safety
180 ///
181 /// Calling this method on an uninitialized `Once` cell is *undefined behavior*.
182 /// The caller must ensure the cell is initialized and that they have exclusive access.
183 #[inline]
184 pub unsafe fn get_unchecked_mut(&mut self) -> &mut T {
185 debug_assert!(
186 self.is_done(),
187 "get_unchecked_mut called on uninitialized Once"
188 );
189 // SAFETY: The caller guarantees that the cell is initialized and we have exclusive access.
190 unsafe { (*self.value.get()).assume_init_mut() }
191 }
192
193 /// Takes the value out of the cell, leaving it uninitialized.
194 ///
195 /// Returns `Some(value)` if the cell was initialized, `None` otherwise.
196 /// Requires exclusive access (`&mut self`), so it never blocks.
197 #[inline]
198 pub fn take(&mut self) -> Option<T> {
199 if self.lock.set_uninit() {
200 // Was initialized, now set to uninit. Read the value out.
201 // SAFETY: The cell was initialized (guaranteed by set_uninit returning true).
202 // The state is now uninitialized, preventing further reads of the old value.
203 // We have exclusive access.
204 unsafe { Some((*self.value.get()).assume_init_read()) }
205 } else {
206 // Was already uninitialized.
207 None
208 }
209 }
210
211 /// Initializes the cell with `value`. Blocks if another thread is initializing.
212 ///
213 /// - If uninitialized, initializes it with `value` and returns `Ok(())`.
214 /// - If already initialized, returns `Err(value)`.
215 ///
216 /// Guarantees the cell is initialized upon return, but not necessarily with `value`
217 /// if another thread completed initialization first.
218 #[inline]
219 pub fn set(&self, value: T) -> Result<(), T> {
220 match self.try_insert(value) {
221 Ok(_) => Ok(()), // Successfully inserted our value
222 Err((_current_value, original_value)) => Err(original_value), // Already initialized by someone else
223 }
224 }
225
226 /// Initializes the cell with `value` if uninitialized, returning a reference. Blocks if needed.
227 ///
228 /// - If uninitialized, initializes with `value` and returns `Ok(&value)`.
229 /// - If already initialized, returns `Err((¤t_value, value))`.
230 ///
231 /// Guarantees the cell is initialized upon return.
232 #[inline]
233 pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
234 // `get_or_init` ensures initialization. We use `value` only if the cell was empty.
235 let mut value_opt = Some(value);
236 let res_ref = self.get_or_init(|| value_opt.take().unwrap());
237 match value_opt {
238 None => Ok(res_ref), // Our value was used for initialization
239 Some(original_value) => Err((res_ref, original_value)), // Someone else initialized it first
240 }
241 }
242
243 /// Gets the value, initializing with `f()` if needed. Blocks if needed.
244 ///
245 /// - If initialized, returns a reference to the existing value.
246 /// - If uninitialized, calls `f()`, stores the result, and returns a reference.
247 ///
248 /// If multiple threads call this concurrently, only one `f()` execution happens.
249 #[inline]
250 pub fn get_or_init<F>(&self, f: F) -> &T
251 where
252 F: FnOnce() -> T,
253 {
254 if let Some(value) = self.get() {
255 return value;
256 }
257 // Cold path: needs initialization
258 self.initialize(f);
259 // SAFETY: initialize ensures the value is now initialized.
260 unsafe { self.get_unchecked() }
261 }
262
263 /// Gets a mutable reference, initializing with `f()` if needed.
264 ///
265 /// - If initialized, returns a mutable reference to the existing value.
266 /// - If uninitialized, calls `f()`, stores the result, and returns a mutable reference.
267 ///
268 /// Requires exclusive access (`&mut self`), so it never blocks.
269 #[inline]
270 pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T
271 where
272 F: FnOnce() -> T,
273 {
274 if self.is_done() {
275 // Already initialized.
276 } else if let Some(guard) = self.lock.try_lock() {
277 // We got the lock (because is_done was false and no one else had it). Initialize it.
278 // SAFETY: We hold the lock, exclusive access to initialize.
279 unsafe { (*self.value.get()).write(f()) };
280 guard.commit();
281 } else {
282 // This case should theoretically not happen with &mut self,
283 // as try_lock should succeed if !is_done().
284 // If it did, it implies a logic error or unexpected concurrent access.
285 unreachable!("Could not lock for init despite having exclusive access");
286 }
287
288 // SAFETY: The cell is guaranteed to be initialized now, and we have exclusive access.
289 unsafe { self.get_unchecked_mut() }
290 }
291
292 /// Gets the value, initializing with fallible `f()` if needed. Blocks if needed.
293 ///
294 /// - If initialized, returns `Ok(&value)`.
295 /// - If uninitialized, calls `f()`:
296 /// - On `Ok(value)`, initializes the cell and returns `Ok(&value)`.
297 /// - On `Err(e)`, returns `Err(e)` and leaves the cell uninitialized.
298 ///
299 /// If multiple threads call this concurrently, only one `f()` execution happens.
300 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
301 where
302 F: FnOnce() -> Result<T, E>,
303 {
304 if let Some(value) = self.get() {
305 return Ok(value);
306 }
307 // Cold path: needs initialization attempt
308 self.try_initialize(f)?;
309 // If try_initialize succeeded, it's now initialized.
310 debug_assert!(self.is_done());
311 // SAFETY: try_initialize succeeded, so the value is initialized.
312 Ok(unsafe { self.get_unchecked() })
313 }
314
315 /// Gets a mutable reference, initializing with fallible `f()` if needed.
316 ///
317 /// - If initialized, returns `Ok(&mut value)`.
318 /// - If uninitialized, calls `f()`:
319 /// - On `Ok(value)`, initializes the cell and returns `Ok(&mut value)`.
320 /// - On `Err(e)`, returns `Err(e)` and leaves the cell uninitialized.
321 ///
322 /// Requires exclusive access (`&mut self`), so it never blocks (initialization happens inline).
323 pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E>
324 where
325 F: FnOnce() -> Result<T, E>,
326 {
327 if let Some(guard) = self.lock.try_lock() {
328 // We got the lock. Try to initialize.
329 self.value.get_mut().write(f()?);
330 guard.commit();
331 }
332 // SAFETY: The cell is guaranteed to be initialized now (or we returned Err),
333 // and we have exclusive access.
334 Ok(unsafe { self.get_unchecked_mut() })
335 }
336
337 /// Gets the value, initializing asynchronously with `f()` if needed. Blocks if needed.
338 ///
339 /// - If initialized, returns a reference to the existing value.
340 /// - If uninitialized, awaits `f()`, stores the result, and returns a reference.
341 ///
342 /// If multiple tasks call this concurrently, only one `f()` execution happens.
343 #[inline]
344 pub async fn get_or_init_async<F, Fut>(&self, f: F) -> &T
345 where
346 F: FnOnce() -> Fut,
347 Fut: Future<Output = T>,
348 {
349 if let Some(value) = self.get() {
350 return value;
351 }
352 // Cold path: needs async initialization
353 self.initialize_async(f).await;
354 // SAFETY: initialize_async ensures the value is now initialized.
355 unsafe { self.get_unchecked() }
356 }
357
358 /// Gets a mutable reference, initializing asynchronously with `f()` if needed.
359 ///
360 /// - If initialized, returns a mutable reference to the existing value.
361 /// - If uninitialized, awaits `f()`, stores the result, and returns a mutable reference.
362 ///
363 /// Requires exclusive access (`&mut self`), so it never blocks (initialization happens inline).
364 #[inline]
365 pub async fn get_mut_or_init_async<F, Fut>(&mut self, f: F) -> &mut T
366 where
367 F: FnOnce() -> Fut,
368 Fut: Future<Output = T>,
369 {
370 if let Some(guard) = self.lock.try_lock() {
371 // We got the lock. Try to initialize.
372 self.value.get_mut().write(f().await);
373 guard.commit();
374 }
375 // SAFETY: The cell is guaranteed to be initialized now (or we returned Err),
376 // and we have exclusive access.
377 unsafe { self.get_unchecked_mut() }
378 }
379
380 /// Gets the value, initializing asynchronously with fallible `f()` if needed. Blocks if needed.
381 ///
382 /// - If initialized, returns `Ok(&value)`.
383 /// - If uninitialized, awaits `f()`:
384 /// - On `Ok(value)`, initializes the cell and returns `Ok(&value)`.
385 /// - On `Err(e)`, returns `Err(e)` and leaves the cell uninitialized.
386 ///
387 /// If multiple tasks call this concurrently, only one `f()` execution happens.
388 pub async fn get_or_try_init_async<F, Fut, E>(&self, f: F) -> Result<&T, E>
389 where
390 F: FnOnce() -> Fut,
391 Fut: Future<Output = Result<T, E>>,
392 {
393 if let Some(value) = self.get() {
394 return Ok(value);
395 }
396 // Cold path: needs async initialization attempt
397 self.try_initialize_async(f).await?;
398 // If try_initialize_async succeeded, it's now initialized.
399 debug_assert!(self.is_done());
400 // SAFETY: try_initialize_async succeeded, so the value is initialized.
401 Ok(unsafe { self.get_unchecked() })
402 }
403
404 /// Gets a mutable reference, initializing asynchronously with fallible `f()` if needed.
405 ///
406 /// - If initialized, returns `Ok(&mut value)`.
407 /// - If uninitialized, awaits `f()`:
408 /// - On `Ok(value)`, initializes the cell and returns `Ok(&mut value)`.
409 /// - On `Err(e)`, returns `Err(e)` and leaves the cell uninitialized.
410 ///
411 /// Requires exclusive access (`&mut self`), so it never blocks (initialization happens inline).
412 pub async fn get_mut_or_try_init_async<F, Fut, E>(&mut self, f: F) -> Result<&mut T, E>
413 where
414 F: FnOnce() -> Fut,
415 Fut: Future<Output = Result<T, E>>,
416 {
417 if let Some(guard) = self.lock.try_lock() {
418 // We got the lock. Try to initialize.
419 self.value.get_mut().write(f().await?);
420 guard.commit();
421 }
422
423 // SAFETY: The cell is guaranteed to be initialized now (or we returned Err),
424 // and we have exclusive access.
425 Ok(unsafe { self.get_unchecked_mut() })
426 }
427
428 // --- Internal Initialization Helpers ---
429
430 /// Cold path for `get_or_init_async`. Acquires lock asynchronously and awaits initializer.
431 #[cold]
432 async fn initialize_async<F, Fut>(&self, f: F)
433 where
434 F: FnOnce() -> Fut,
435 Fut: Future<Output = T>,
436 {
437 let Some(guard) = self.lock.lock_async().await else {
438 return; // Another task initialized it while we waited
439 };
440 // SAFETY: We hold the lock, exclusive access to initialize the value.
441 unsafe { (*self.value.get()).write(f().await) };
442 guard.commit(); // Mark as done and notify waiters
443 }
444
445 /// Cold path for `get_or_try_init_async`. Acquires lock asynchronously and awaits fallible initializer.
446 #[cold]
447 async fn try_initialize_async<Fn, Fut, E>(&self, f: Fn) -> Result<(), E>
448 where
449 Fn: FnOnce() -> Fut,
450 Fut: Future<Output = Result<T, E>>,
451 {
452 let Some(guard) = self.lock.lock_async().await else {
453 return Ok(()); // Another task initialized it while we waited
454 };
455 let value = f().await?; // Await initializer. If it fails, guard is dropped, state reset.
456 // SAFETY: We hold the lock, exclusive access to initialize the value.
457 unsafe { (*self.value.get()).write(value) };
458 guard.commit(); // Mark as done and notify waiters
459 Ok(())
460 }
461
462 /// Cold path for `get_or_init`. Acquires lock and calls initializer.
463 #[cold]
464 fn initialize<F>(&self, f: F)
465 where
466 F: FnOnce() -> T,
467 {
468 let Some(guard) = self.lock.lock() else {
469 return; // Another thread initialized it while we waited for the lock
470 };
471 // SAFETY: We hold the lock, exclusive access to initialize the value.
472 unsafe { (*self.value.get()).write(f()) };
473 guard.commit(); // Mark as done and notify waiters
474 }
475
476 /// Cold path for `get_or_try_init`. Acquires lock and calls fallible initializer.
477 #[cold]
478 fn try_initialize<F, E>(&self, f: F) -> Result<(), E>
479 where
480 F: FnOnce() -> Result<T, E>,
481 {
482 let Some(guard) = self.lock.lock() else {
483 return Ok(()); // Another thread initialized it while we waited for the lock
484 };
485 let value = f()?; // Call initializer. If it fails, guard is dropped, state reset.
486 // SAFETY: We hold the lock, exclusive access to initialize the value.
487 unsafe { (*self.value.get()).write(value) };
488 guard.commit(); // Mark as done and notify waiters
489 Ok(())
490 }
491}
492
493// --- Trait Implementations ---
494
495impl<T> From<Option<T>> for Once<T> {
496 /// Creates an initialized `Once` from `Some(value)` or an uninitialized one from `None`.
497 fn from(value: Option<T>) -> Self {
498 match value {
499 Some(value) => Self::with_value(value),
500 None => Self::new(),
501 }
502 }
503}
504
505// SAFETY:
506// `&Once<T>` is `Sync` if `&T` is `Sync` (requiring `T: Sync`)
507// and if the initialization mechanism is thread-safe (which it is).
508// `T: Send` is also required because a value provided by one thread
509// might be read or dropped by another.
510unsafe impl<T: Sync + Send> Sync for Once<T> {}
511// SAFETY:
512// `Once<T>` is `Send` if `T` is `Send`, as the ownership of `T`
513// can be transferred across threads via initialization or `take()`.
514unsafe impl<T: Send> Send for Once<T> {}
515
516impl<T> Default for Once<T> {
517 /// Creates a new, uninitialized `Once` cell.
518 #[inline]
519 fn default() -> Self {
520 Self::new()
521 }
522}
523
524impl<T: fmt::Display> fmt::Display for Once<T> {
525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 match self.get() {
527 Some(v) => fmt::Display::fmt(v, f),
528 None => f.write_str("<uninit>"),
529 }
530 }
531}
532
533impl<T: fmt::Debug> fmt::Debug for Once<T> {
534 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535 let mut d = f.debug_tuple("Once");
536 match self.get() {
537 Some(v) => d.field(v),
538 None => d.field(&format_args!("<uninit>")),
539 };
540 d.finish()
541 }
542}
543
544impl<T: Clone> Clone for Once<T> {
545 /// Clones the `Once` cell.
546 ///
547 /// If the original cell is initialized, the clone will be initialized
548 /// with a cloned value. If the original is uninitialized, the clone
549 /// will also be uninitialized.
550 #[inline]
551 fn clone(&self) -> Self {
552 match self.get() {
553 Some(value) => Self::with_value(value.clone()),
554 None => Self::new(),
555 }
556 }
557}
558
559impl<T> From<T> for Once<T> {
560 /// Creates a new, initialized `Once` cell from the given value.
561 #[inline]
562 fn from(value: T) -> Self {
563 Self::with_value(value)
564 }
565}
566
567impl<T: PartialEq> PartialEq for Once<T> {
568 /// Checks if two `Once` cells are equal.
569 ///
570 /// They are equal if both are uninitialized, or if both are initialized
571 /// and their contained values are equal according to `PartialEq`.
572 #[inline]
573 fn eq(&self, other: &Self) -> bool {
574 self.get() == other.get()
575 }
576}
577
578impl<T: Eq> Eq for Once<T> {}
579
580impl<T> Drop for Once<T> {
581 #[inline]
582 fn drop(&mut self) {
583 if self.is_done() {
584 // The state indicates the cell is initialized.
585 // SAFETY: We have exclusive access (`&mut self`), the cell is initialized,
586 // and we are dropping it, so the value won't be accessed again.
587 unsafe { self.value.get_mut().assume_init_drop() };
588 }
589 }
590}