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