diff options
| author | Maybe Waffle <waffle.lapkin@gmail.com> | 2022-06-16 19:39:39 +0400 |
|---|---|---|
| committer | Maybe Waffle <waffle.lapkin@gmail.com> | 2022-06-16 19:54:42 +0400 |
| commit | c1a2db3372a4d6896744919284f3287650a38ab7 (patch) | |
| tree | 636b2ff560a6dc628c5cec1440db82210b73dee5 /library/std/src/lazy.rs | |
| parent | 7c360dc117d554a11f7193505da0835c4b890c6f (diff) | |
| download | rust-c1a2db3372a4d6896744919284f3287650a38ab7.tar.gz rust-c1a2db3372a4d6896744919284f3287650a38ab7.zip | |
Move/rename `lazy::Sync{OnceCell,Lazy}` to `sync::{Once,Lazy}Lock`
Diffstat (limited to 'library/std/src/lazy.rs')
| -rw-r--r-- | library/std/src/lazy.rs | 616 |
1 files changed, 0 insertions, 616 deletions
diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index d7450962359..f8c06c3f9ae 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -1,617 +1 @@ //! Lazy values and one-time initialization of static data. - -#[cfg(test)] -mod tests; - -use crate::{ - cell::{Cell, UnsafeCell}, - fmt, - marker::PhantomData, - mem::MaybeUninit, - ops::{Deref, Drop}, - panic::{RefUnwindSafe, UnwindSafe}, - pin::Pin, - sync::Once, -}; - -#[doc(inline)] -#[unstable(feature = "once_cell", issue = "74465")] -pub use core::lazy::*; - -/// A synchronization primitive which can be written to only once. -/// -/// This type is a thread-safe `OnceCell`. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::lazy::SyncOnceCell; -/// -/// static CELL: SyncOnceCell<String> = SyncOnceCell::new(); -/// assert!(CELL.get().is_none()); -/// -/// std::thread::spawn(|| { -/// let value: &String = CELL.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// }).join().unwrap(); -/// -/// let value: Option<&String> = CELL.get(); -/// assert!(value.is_some()); -/// assert_eq!(value.unwrap().as_str(), "Hello, World!"); -/// ``` -#[unstable(feature = "once_cell", issue = "74465")] -pub struct SyncOnceCell<T> { - once: Once, - // Whether or not the value is initialized is tracked by `state_and_queue`. - value: UnsafeCell<MaybeUninit<T>>, - /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl. - /// - /// ```compile_fail,E0597 - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// struct A<'a>(&'a str); - /// - /// impl<'a> Drop for A<'a> { - /// fn drop(&mut self) {} - /// } - /// - /// let cell = SyncOnceCell::new(); - /// { - /// let s = String::new(); - /// let _ = cell.set(A(&s)); - /// } - /// ``` - _marker: PhantomData<T>, -} - -// Why do we need `T: Send`? -// Thread A creates a `SyncOnceCell` and shares it with -// scoped thread B, which fills the cell, which is -// then destroyed by A. That is, destructor observes -// a sent value. -#[unstable(feature = "once_cell", issue = "74465")] -unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {} -#[unstable(feature = "once_cell", issue = "74465")] -unsafe impl<T: Send> Send for SyncOnceCell<T> {} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {} -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {} - -#[unstable(feature = "once_cell", issue = "74465")] -#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] -impl<T> const Default for SyncOnceCell<T> { - /// Creates a new empty cell. - /// - /// # Example - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// fn main() { - /// assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default()); - /// } - /// ``` - fn default() -> SyncOnceCell<T> { - SyncOnceCell::new() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("Once").field(v).finish(), - None => f.write_str("Once(Uninit)"), - } - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Clone> Clone for SyncOnceCell<T> { - fn clone(&self) -> SyncOnceCell<T> { - let cell = Self::new(); - if let Some(value) = self.get() { - match cell.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - cell - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T> From<T> for SyncOnceCell<T> { - /// Create a new cell with its contents set to `value`. - /// - /// # Example - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// # fn main() -> Result<(), i32> { - /// let a = SyncOnceCell::from(3); - /// let b = SyncOnceCell::new(); - /// b.set(3)?; - /// assert_eq!(a, b); - /// Ok(()) - /// # } - /// ``` - fn from(value: T) -> Self { - let cell = Self::new(); - match cell.set(value) { - Ok(()) => cell, - Err(_) => unreachable!(), - } - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: PartialEq> PartialEq for SyncOnceCell<T> { - fn eq(&self, other: &SyncOnceCell<T>) -> bool { - self.get() == other.get() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Eq> Eq for SyncOnceCell<T> {} - -impl<T> SyncOnceCell<T> { - /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "74465")] - #[must_use] - pub const fn new() -> SyncOnceCell<T> { - SyncOnceCell { - once: Once::new(), - value: UnsafeCell::new(MaybeUninit::uninit()), - _marker: PhantomData, - } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty, or being initialized. This - /// method never blocks. - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get(&self) -> Option<&T> { - if self.is_initialized() { - // Safe b/c checked is_initialized - Some(unsafe { self.get_unchecked() }) - } else { - None - } - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. This method never blocks. - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get_mut(&mut self) -> Option<&mut T> { - if self.is_initialized() { - // Safe b/c checked is_initialized and we have a unique access - Some(unsafe { self.get_unchecked_mut() }) - } else { - None - } - } - - /// Sets the contents of this cell to `value`. - /// - /// May block if another thread is currently attempting to initialize the cell. The cell is - /// guaranteed to contain a value when set returns, though not necessarily the one provided. - /// - /// Returns `Ok(())` if the cell's value was set by this call. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new(); - /// - /// fn main() { - /// assert!(CELL.get().is_none()); - /// - /// std::thread::spawn(|| { - /// assert_eq!(CELL.set(92), Ok(())); - /// }).join().unwrap(); - /// - /// assert_eq!(CELL.set(62), Err(62)); - /// assert_eq!(CELL.get(), Some(&92)); - /// } - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn set(&self, value: T) -> Result<(), T> { - let mut value = Some(value); - self.get_or_init(|| value.take().unwrap()); - match value { - None => Ok(()), - Some(value) => Err(value), - } - } - - /// Gets the contents of the cell, initializing it with `f` if the cell - /// was empty. - /// - /// Many threads may call `get_or_init` concurrently with different - /// initializing functions, but it is guaranteed that only one function - /// will be executed. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. The - /// exact outcome is unspecified. Current implementation deadlocks, but - /// this may be changed to a panic in the future. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let cell = SyncOnceCell::new(); - /// let value = cell.get_or_init(|| 92); - /// assert_eq!(value, &92); - /// let value = cell.get_or_init(|| unreachable!()); - /// assert_eq!(value, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get_or_init<F>(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - match self.get_or_try_init(|| Ok::<T, !>(f())) { - Ok(val) => val, - } - } - - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and - /// the cell remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. - /// The exact outcome is unspecified. Current implementation - /// deadlocks, but this may be changed to a panic in the future. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let cell = SyncOnceCell::new(); - /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - /// assert!(cell.get().is_none()); - /// let value = cell.get_or_try_init(|| -> Result<i32, ()> { - /// Ok(92) - /// }); - /// assert_eq!(value, Ok(&92)); - /// assert_eq!(cell.get(), Some(&92)) - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result<T, E>, - { - // Fast path check - // NOTE: We need to perform an acquire on the state in this method - // in order to correctly synchronize `SyncLazy::force`. This is - // currently done by calling `self.get()`, which in turn calls - // `self.is_initialized()`, which in turn performs the acquire. - if let Some(value) = self.get() { - return Ok(value); - } - self.initialize(f)?; - - debug_assert!(self.is_initialized()); - - // SAFETY: The inner value has been initialized - Ok(unsafe { self.get_unchecked() }) - } - - /// Internal-only API that gets the contents of the cell, initializing it - /// in two steps with `f` and `g` if the cell was empty. - /// - /// `f` is called to construct the value, which is then moved into the cell - /// and given as a (pinned) mutable reference to `g` to finish - /// initialization. - /// - /// This allows `g` to inspect an manipulate the value after it has been - /// moved into its final place in the cell, but before the cell is - /// considered initialized. - /// - /// # Panics - /// - /// If `f` or `g` panics, the panic is propagated to the caller, and the - /// cell remains uninitialized. - /// - /// With the current implementation, if `g` panics, the value from `f` will - /// not be dropped. This should probably be fixed if this is ever used for - /// a type where this matters. - /// - /// It is an error to reentrantly initialize the cell from `f`. The exact - /// outcome is unspecified. Current implementation deadlocks, but this may - /// be changed to a panic in the future. - pub(crate) fn get_or_init_pin<F, G>(self: Pin<&Self>, f: F, g: G) -> Pin<&T> - where - F: FnOnce() -> T, - G: FnOnce(Pin<&mut T>), - { - if let Some(value) = self.get_ref().get() { - // SAFETY: The inner value was already initialized, and will not be - // moved anymore. - return unsafe { Pin::new_unchecked(value) }; - } - - let slot = &self.value; - - // Ignore poisoning from other threads - // If another thread panics, then we'll be able to run our closure - self.once.call_once_force(|_| { - let value = f(); - // SAFETY: We use the Once (self.once) to guarantee unique access - // to the UnsafeCell (slot). - let value: &mut T = unsafe { (&mut *slot.get()).write(value) }; - // SAFETY: The value has been written to its final place in - // self.value. We do not to move it anymore, which we promise here - // with a Pin<&mut T>. - g(unsafe { Pin::new_unchecked(value) }); - }); - - // SAFETY: The inner value has been initialized, and will not be moved - // anymore. - unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) } - } - - /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns - /// `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let cell: SyncOnceCell<String> = SyncOnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = SyncOnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn into_inner(mut self) -> Option<T> { - self.take() - } - - /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state. - /// - /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized. - /// - /// Safety is guaranteed by requiring a mutable reference. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let mut cell: SyncOnceCell<String> = SyncOnceCell::new(); - /// assert_eq!(cell.take(), None); - /// - /// let mut cell = SyncOnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.take(), Some("hello".to_string())); - /// assert_eq!(cell.get(), None); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn take(&mut self) -> Option<T> { - if self.is_initialized() { - self.once = Once::new(); - // SAFETY: `self.value` is initialized and contains a valid `T`. - // `self.once` is reset, so `is_initialized()` will be false again - // which prevents the value from being read twice. - unsafe { Some((&mut *self.value.get()).assume_init_read()) } - } else { - None - } - } - - #[inline] - fn is_initialized(&self) -> bool { - self.once.is_completed() - } - - #[cold] - fn initialize<F, E>(&self, f: F) -> Result<(), E> - where - F: FnOnce() -> Result<T, E>, - { - let mut res: Result<(), E> = Ok(()); - let slot = &self.value; - - // Ignore poisoning from other threads - // If another thread panics, then we'll be able to run our closure - self.once.call_once_force(|p| { - match f() { - Ok(value) => { - unsafe { (&mut *slot.get()).write(value) }; - } - Err(e) => { - res = Err(e); - - // Treat the underlying `Once` as poisoned since we - // failed to initialize our value. Calls - p.poison(); - } - } - }); - res - } - - /// # Safety - /// - /// The value must be initialized - unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.is_initialized()); - (&*self.value.get()).assume_init_ref() - } - - /// # Safety - /// - /// The value must be initialized - unsafe fn get_unchecked_mut(&mut self) -> &mut T { - debug_assert!(self.is_initialized()); - (&mut *self.value.get()).assume_init_mut() - } -} - -unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> { - fn drop(&mut self) { - if self.is_initialized() { - // SAFETY: The cell is initialized and being dropped, so it can't - // be accessed again. We also don't touch the `T` other than - // dropping it, which validates our usage of #[may_dangle]. - unsafe { (&mut *self.value.get()).assume_init_drop() }; - } - } -} - -/// A value which is initialized on the first access. -/// -/// This type is a thread-safe `Lazy`, and can be used in statics. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::collections::HashMap; -/// -/// use std::lazy::SyncLazy; -/// -/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| { -/// println!("initializing"); -/// let mut m = HashMap::new(); -/// m.insert(13, "Spica".to_string()); -/// m.insert(74, "Hoyten".to_string()); -/// m -/// }); -/// -/// fn main() { -/// println!("ready"); -/// std::thread::spawn(|| { -/// println!("{:?}", HASHMAP.get(&13)); -/// }).join().unwrap(); -/// println!("{:?}", HASHMAP.get(&74)); -/// -/// // Prints: -/// // ready -/// // initializing -/// // Some("Spica") -/// // Some("Hoyten") -/// } -/// ``` -#[unstable(feature = "once_cell", issue = "74465")] -pub struct SyncLazy<T, F = fn() -> T> { - cell: SyncOnceCell<T>, - init: Cell<Option<F>>, -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive() - } -} - -// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine -// to not impl `Sync` for `F` -// we do create a `&mut Option<F>` in `force`, but this is -// properly synchronized, so it only happens once -// so it also does not contribute to this impl. -#[unstable(feature = "once_cell", issue = "74465")] -unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {} -// auto-derived `Send` impl is OK. - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T, F: UnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {} -#[unstable(feature = "once_cell", issue = "74465")] -impl<T, F: UnwindSafe> UnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: UnwindSafe {} - -impl<T, F> SyncLazy<T, F> { - /// Creates a new lazy value with the given initializing - /// function. - #[unstable(feature = "once_cell", issue = "74465")] - pub const fn new(f: F) -> SyncLazy<T, F> { - SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } - } -} - -impl<T, F: FnOnce() -> T> SyncLazy<T, F> { - /// Forces the evaluation of this lazy value and - /// returns a reference to result. This is equivalent - /// to the `Deref` impl, but is explicit. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncLazy; - /// - /// let lazy = SyncLazy::new(|| 92); - /// - /// assert_eq!(SyncLazy::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn force(this: &SyncLazy<T, F>) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("Lazy instance has previously been poisoned"), - }) - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> { - type Target = T; - fn deref(&self) -> &T { - SyncLazy::force(self) - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Default> Default for SyncLazy<T> { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> SyncLazy<T> { - SyncLazy::new(T::default) - } -} |
