xref: /drstd/src/std/sync/once_lock.rs (revision 0fe3ff0054d3aec7fbf9bddecfecb10bc7d23a51)
1 use crate::std::cell::UnsafeCell;
2 use crate::std::fmt;
3 use crate::std::marker::PhantomData;
4 use crate::std::mem::MaybeUninit;
5 use crate::std::panic::{RefUnwindSafe, UnwindSafe};
6 use crate::std::sync::Once;
7 
8 /// A synchronization primitive which can be written to only once.
9 ///
10 /// This type is a thread-safe [`OnceCell`], and can be used in statics.
11 ///
12 /// [`OnceCell`]: crate::std::cell::OnceCell
13 ///
14 /// # Examples
15 ///
16 /// ```
17 /// use std::sync::OnceLock;
18 ///
19 /// static CELL: OnceLock<String> = OnceLock::new();
20 /// assert!(CELL.get().is_none());
21 ///
22 /// std::thread::spawn(|| {
23 ///     let value: &String = CELL.get_or_init(|| {
24 ///         "Hello, World!".to_string()
25 ///     });
26 ///     assert_eq!(value, "Hello, World!");
27 /// }).join().unwrap();
28 ///
29 /// let value: Option<&String> = CELL.get();
30 /// assert!(value.is_some());
31 /// assert_eq!(value.unwrap().as_str(), "Hello, World!");
32 /// ```
33 pub struct OnceLock<T> {
34     once: Once,
35     // Whether or not the value is initialized is tracked by `once.is_completed()`.
36     value: UnsafeCell<MaybeUninit<T>>,
37     /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
38     ///
39     /// ```compile_fail,E0597
40     /// use std::sync::OnceLock;
41     ///
42     /// struct A<'a>(&'a str);
43     ///
44     /// impl<'a> Drop for A<'a> {
45     ///     fn drop(&mut self) {}
46     /// }
47     ///
48     /// let cell = OnceLock::new();
49     /// {
50     ///     let s = String::new();
51     ///     let _ = cell.set(A(&s));
52     /// }
53     /// ```
54     _marker: PhantomData<T>,
55 }
56 
57 impl<T> OnceLock<T> {
58     /// Creates a new empty cell.
59     #[inline]
60     #[must_use]
61     pub const fn new() -> OnceLock<T> {
62         OnceLock {
63             once: Once::new(),
64             value: UnsafeCell::new(MaybeUninit::uninit()),
65             _marker: PhantomData,
66         }
67     }
68 
69     /// Gets the reference to the underlying value.
70     ///
71     /// Returns `None` if the cell is empty, or being initialized. This
72     /// method never blocks.
73     #[inline]
74     pub fn get(&self) -> Option<&T> {
75         if self.is_initialized() {
76             // Safe b/c checked is_initialized
77             Some(unsafe { self.get_unchecked() })
78         } else {
79             None
80         }
81     }
82 
83     /// Gets the mutable reference to the underlying value.
84     ///
85     /// Returns `None` if the cell is empty. This method never blocks.
86     #[inline]
87     pub fn get_mut(&mut self) -> Option<&mut T> {
88         if self.is_initialized() {
89             // Safe b/c checked is_initialized and we have a unique access
90             Some(unsafe { self.get_unchecked_mut() })
91         } else {
92             None
93         }
94     }
95 
96     /// Sets the contents of this cell to `value`.
97     ///
98     /// May block if another thread is currently attempting to initialize the cell. The cell is
99     /// guaranteed to contain a value when set returns, though not necessarily the one provided.
100     ///
101     /// Returns `Ok(())` if the cell's value was set by this call.
102     ///
103     /// # Examples
104     ///
105     /// ```
106     /// use std::sync::OnceLock;
107     ///
108     /// static CELL: OnceLock<i32> = OnceLock::new();
109     ///
110     /// fn main() {
111     ///     assert!(CELL.get().is_none());
112     ///
113     ///     std::thread::spawn(|| {
114     ///         assert_eq!(CELL.set(92), Ok(()));
115     ///     }).join().unwrap();
116     ///
117     ///     assert_eq!(CELL.set(62), Err(62));
118     ///     assert_eq!(CELL.get(), Some(&92));
119     /// }
120     /// ```
121     #[inline]
122     pub fn set(&self, value: T) -> Result<(), T> {
123         let mut value = Some(value);
124         self.get_or_init(|| value.take().unwrap());
125         match value {
126             None => Ok(()),
127             Some(value) => Err(value),
128         }
129     }
130 
131     /// Gets the contents of the cell, initializing it with `f` if the cell
132     /// was empty.
133     ///
134     /// Many threads may call `get_or_init` concurrently with different
135     /// initializing functions, but it is guaranteed that only one function
136     /// will be executed.
137     ///
138     /// # Panics
139     ///
140     /// If `f` panics, the panic is propagated to the caller, and the cell
141     /// remains uninitialized.
142     ///
143     /// It is an error to reentrantly initialize the cell from `f`. The
144     /// exact outcome is unspecified. Current implementation deadlocks, but
145     /// this may be changed to a panic in the future.
146     ///
147     /// # Examples
148     ///
149     /// ```
150     /// use std::sync::OnceLock;
151     ///
152     /// let cell = OnceLock::new();
153     /// let value = cell.get_or_init(|| 92);
154     /// assert_eq!(value, &92);
155     /// let value = cell.get_or_init(|| unreachable!());
156     /// assert_eq!(value, &92);
157     /// ```
158     #[inline]
159     pub fn get_or_init<F>(&self, f: F) -> &T
160     where
161         F: FnOnce() -> T,
162     {
163         match self.get_or_try_init(|| Ok::<T, !>(f())) {
164             Ok(val) => val,
165             Err(_) => todo!(),
166         }
167     }
168 
169     /// Gets the contents of the cell, initializing it with `f` if
170     /// the cell was empty. If the cell was empty and `f` failed, an
171     /// error is returned.
172     ///
173     /// # Panics
174     ///
175     /// If `f` panics, the panic is propagated to the caller, and
176     /// the cell remains uninitialized.
177     ///
178     /// It is an error to reentrantly initialize the cell from `f`.
179     /// The exact outcome is unspecified. Current implementation
180     /// deadlocks, but this may be changed to a panic in the future.
181     ///
182     /// # Examples
183     ///
184     /// ```
185     /// #![feature(once_cell_try)]
186     ///
187     /// use std::sync::OnceLock;
188     ///
189     /// let cell = OnceLock::new();
190     /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
191     /// assert!(cell.get().is_none());
192     /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
193     ///     Ok(92)
194     /// });
195     /// assert_eq!(value, Ok(&92));
196     /// assert_eq!(cell.get(), Some(&92))
197     /// ```
198     #[inline]
199     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
200     where
201         F: FnOnce() -> Result<T, E>,
202     {
203         // Fast path check
204         // NOTE: We need to perform an acquire on the state in this method
205         // in order to correctly synchronize `LazyLock::force`. This is
206         // currently done by calling `self.get()`, which in turn calls
207         // `self.is_initialized()`, which in turn performs the acquire.
208         if let Some(value) = self.get() {
209             return Ok(value);
210         }
211         self.initialize(f)?;
212 
213         debug_assert!(self.is_initialized());
214 
215         // SAFETY: The inner value has been initialized
216         Ok(unsafe { self.get_unchecked() })
217     }
218 
219     /// Consumes the `OnceLock`, returning the wrapped value. Returns
220     /// `None` if the cell was empty.
221     ///
222     /// # Examples
223     ///
224     /// ```
225     /// use std::sync::OnceLock;
226     ///
227     /// let cell: OnceLock<String> = OnceLock::new();
228     /// assert_eq!(cell.into_inner(), None);
229     ///
230     /// let cell = OnceLock::new();
231     /// cell.set("hello".to_string()).unwrap();
232     /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
233     /// ```
234     #[inline]
235     pub fn into_inner(mut self) -> Option<T> {
236         self.take()
237     }
238 
239     /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state.
240     ///
241     /// Has no effect and returns `None` if the `OnceLock` hasn't been initialized.
242     ///
243     /// Safety is guaranteed by requiring a mutable reference.
244     ///
245     /// # Examples
246     ///
247     /// ```
248     /// use std::sync::OnceLock;
249     ///
250     /// let mut cell: OnceLock<String> = OnceLock::new();
251     /// assert_eq!(cell.take(), None);
252     ///
253     /// let mut cell = OnceLock::new();
254     /// cell.set("hello".to_string()).unwrap();
255     /// assert_eq!(cell.take(), Some("hello".to_string()));
256     /// assert_eq!(cell.get(), None);
257     /// ```
258     #[inline]
259     pub fn take(&mut self) -> Option<T> {
260         if self.is_initialized() {
261             self.once = Once::new();
262             // SAFETY: `self.value` is initialized and contains a valid `T`.
263             // `self.once` is reset, so `is_initialized()` will be false again
264             // which prevents the value from being read twice.
265             unsafe { Some((&mut *self.value.get()).assume_init_read()) }
266         } else {
267             None
268         }
269     }
270 
271     #[inline]
272     fn is_initialized(&self) -> bool {
273         self.once.is_completed()
274     }
275 
276     #[cold]
277     fn initialize<F, E>(&self, f: F) -> Result<(), E>
278     where
279         F: FnOnce() -> Result<T, E>,
280     {
281         let mut res: Result<(), E> = Ok(());
282         let slot = &self.value;
283 
284         // Ignore poisoning from other threads
285         // If another thread panics, then we'll be able to run our closure
286         self.once.call_once_force(|p| {
287             match f() {
288                 Ok(value) => {
289                     unsafe { (&mut *slot.get()).write(value) };
290                 }
291                 Err(e) => {
292                     res = Err(e);
293 
294                     // Treat the underlying `Once` as poisoned since we
295                     // failed to initialize our value. Calls
296                     p.poison();
297                 }
298             }
299         });
300         res
301     }
302 
303     /// # Safety
304     ///
305     /// The value must be initialized
306     #[inline]
307     unsafe fn get_unchecked(&self) -> &T {
308         debug_assert!(self.is_initialized());
309         (&*self.value.get()).assume_init_ref()
310     }
311 
312     /// # Safety
313     ///
314     /// The value must be initialized
315     #[inline]
316     unsafe fn get_unchecked_mut(&mut self) -> &mut T {
317         debug_assert!(self.is_initialized());
318         (&mut *self.value.get()).assume_init_mut()
319     }
320 }
321 
322 // Why do we need `T: Send`?
323 // Thread A creates a `OnceLock` and shares it with
324 // scoped thread B, which fills the cell, which is
325 // then destroyed by A. That is, destructor observes
326 // a sent value.
327 unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
328 unsafe impl<T: Send> Send for OnceLock<T> {}
329 
330 impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
331 impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
332 
333 impl<T> Default for OnceLock<T> {
334     /// Creates a new empty cell.
335     ///
336     /// # Example
337     ///
338     /// ```
339     /// use std::sync::OnceLock;
340     ///
341     /// fn main() {
342     ///     assert_eq!(OnceLock::<()>::new(), OnceLock::default());
343     /// }
344     /// ```
345     #[inline]
346     fn default() -> OnceLock<T> {
347         OnceLock::new()
348     }
349 }
350 
351 impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
352     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353         let mut d = f.debug_tuple("OnceLock");
354         match self.get() {
355             Some(v) => d.field(v),
356             None => d.field(&format_args!("<uninit>")),
357         };
358         d.finish()
359     }
360 }
361 
362 impl<T: Clone> Clone for OnceLock<T> {
363     #[inline]
364     fn clone(&self) -> OnceLock<T> {
365         let cell = Self::new();
366         if let Some(value) = self.get() {
367             match cell.set(value.clone()) {
368                 Ok(()) => (),
369                 Err(_) => unreachable!(),
370             }
371         }
372         cell
373     }
374 }
375 
376 impl<T> From<T> for OnceLock<T> {
377     /// Create a new cell with its contents set to `value`.
378     ///
379     /// # Example
380     ///
381     /// ```
382     /// use std::sync::OnceLock;
383     ///
384     /// # fn main() -> Result<(), i32> {
385     /// let a = OnceLock::from(3);
386     /// let b = OnceLock::new();
387     /// b.set(3)?;
388     /// assert_eq!(a, b);
389     /// Ok(())
390     /// # }
391     /// ```
392     #[inline]
393     fn from(value: T) -> Self {
394         let cell = Self::new();
395         match cell.set(value) {
396             Ok(()) => cell,
397             Err(_) => unreachable!(),
398         }
399     }
400 }
401 
402 impl<T: PartialEq> PartialEq for OnceLock<T> {
403     #[inline]
404     fn eq(&self, other: &OnceLock<T>) -> bool {
405         self.get() == other.get()
406     }
407 }
408 
409 impl<T: Eq> Eq for OnceLock<T> {}
410 
411 unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
412     #[inline]
413     fn drop(&mut self) {
414         if self.is_initialized() {
415             // SAFETY: The cell is initialized and being dropped, so it can't
416             // be accessed again. We also don't touch the `T` other than
417             // dropping it, which validates our usage of #[may_dangle].
418             unsafe { (&mut *self.value.get()).assume_init_drop() };
419         }
420     }
421 }
422 
423 #[cfg(test)]
424 mod tests;
425