1 | #![allow (dead_code)] |
2 | use std::cell::UnsafeCell; |
3 | use std::mem::MaybeUninit; |
4 | use std::sync::Once; |
5 | |
6 | pub(crate) struct OnceCell<T> { |
7 | once: Once, |
8 | value: UnsafeCell<MaybeUninit<T>>, |
9 | } |
10 | |
11 | unsafe impl<T: Send + Sync> Send for OnceCell<T> {} |
12 | unsafe impl<T: Send + Sync> Sync for OnceCell<T> {} |
13 | |
14 | impl<T> OnceCell<T> { |
15 | pub(crate) const fn new() -> Self { |
16 | Self { |
17 | once: Once::new(), |
18 | value: UnsafeCell::new(MaybeUninit::uninit()), |
19 | } |
20 | } |
21 | |
22 | /// Get the value inside this cell, initializing it using the provided |
23 | /// function if necessary. |
24 | /// |
25 | /// If the `init` closure panics, then the `OnceCell` is poisoned and all |
26 | /// future calls to `get` will panic. |
27 | #[inline ] |
28 | pub(crate) fn get(&self, init: impl FnOnce() -> T) -> &T { |
29 | if !self.once.is_completed() { |
30 | self.do_init(init); |
31 | } |
32 | |
33 | // Safety: The `std::sync::Once` guarantees that we can only reach this |
34 | // line if a `call_once` closure has been run exactly once and without |
35 | // panicking. Thus, the value is not uninitialized. |
36 | // |
37 | // There is also no race because the only `&self` method that modifies |
38 | // `value` is `do_init`, but if the `call_once` closure is still |
39 | // running, then no thread has gotten past the `call_once`. |
40 | unsafe { &*(self.value.get() as *const T) } |
41 | } |
42 | |
43 | #[cold ] |
44 | fn do_init(&self, init: impl FnOnce() -> T) { |
45 | let value_ptr = self.value.get() as *mut T; |
46 | |
47 | self.once.call_once(|| { |
48 | let set_to = init(); |
49 | |
50 | // Safety: The `std::sync::Once` guarantees that this initialization |
51 | // will run at most once, and that no thread can get past the |
52 | // `call_once` until it has run exactly once. Thus, we have |
53 | // exclusive access to `value`. |
54 | unsafe { |
55 | std::ptr::write(value_ptr, set_to); |
56 | } |
57 | }); |
58 | } |
59 | } |
60 | |
61 | impl<T> Drop for OnceCell<T> { |
62 | fn drop(&mut self) { |
63 | if self.once.is_completed() { |
64 | let value_ptr: *mut T = self.value.get() as *mut T; |
65 | unsafe { |
66 | std::ptr::drop_in_place(to_drop:value_ptr); |
67 | } |
68 | } |
69 | } |
70 | } |
71 | |