From bba2d0944447a88e997f2b0ec74f440999d64b08 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov <aleksey.kladov@gmail.com> Date: Sun, 12 Jan 2020 18:14:29 +0100 Subject: [PATCH 1/6] First cut of `std::lazy` module --- src/libstd/lazy.rs | 1002 ++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 6 + 2 files changed, 1008 insertions(+) create mode 100644 src/libstd/lazy.rs diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs new file mode 100644 index 0000000000000..bcac2dc311aff --- /dev/null +++ b/src/libstd/lazy.rs @@ -0,0 +1,1002 @@ +//! `lazy` modules provides lazy values and one-time initialization of static data. +//! +//! `lazy` provides two new cell-like types, `OnceCell` and `SyncOnceCell`. `OnceCell` +//! might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access +//! to the stored contents. In a nutshell, API looks *roughly* like this: +//! +//! ```rust,ignore +//! impl<T> OnceCell<T> { +//! fn new() -> OnceCell<T> { ... } +//! fn set(&self, value: T) -> Result<(), T> { ... } +//! fn get(&self) -> Option<&T> { ... } +//! } +//! ``` +//! +//! Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. +//! Because of the single assignment restriction `get` can return an `&T` instead of `Ref<T>` +//! or `MutexGuard<T>`. +//! +//! The `SyncOnceCell` flavor is thread-safe (that is, implements [`Sync`]) trait, while `OnceCell` one is not. +//! +//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html +//! +//! # Patterns +//! +//! `OnceCell` might be useful for a variety of patterns. +//! +//! ## Safe Initialization of global data +//! +//! ```rust +//! use std::{env, io}; +//! use std::lazy::SyncOnceCell; +//! +//! #[derive(Debug)] +//! pub struct Logger { +//! // ... +//! } +//! static INSTANCE: OnceCell<Logger> = OnceCell::new(); +//! +//! impl Logger { +//! pub fn global() -> &'static Logger { +//! INSTANCE.get().expect("logger is not initialized") +//! } +//! +//! fn from_cli(args: env::Args) -> Result<Logger, std::io::Error> { +//! // ... +//! # Ok(Logger {}) +//! } +//! } +//! +//! fn main() { +//! let logger = Logger::from_cli(env::args()).unwrap(); +//! INSTANCE.set(logger).unwrap(); +//! // use `Logger::global()` from now on +//! } +//! ``` +//! +//! ## Lazy initialized global data +//! +//! This is essentially `lazy_static!` macro, but without a macro. +//! +//! ```rust +//! use std::{sync::Mutex, collections::HashMap}; +//! use lazy::SyncOnceCell; +//! +//! fn global_data() -> &'static Mutex<HashMap<i32, String>> { +//! static INSTANCE: OnceCell<Mutex<HashMap<i32, String>>> = OnceCell::new(); +//! INSTANCE.get_or_init(|| { +//! let mut m = HashMap::new(); +//! m.insert(13, "Spica".to_string()); +//! m.insert(74, "Hoyten".to_string()); +//! Mutex::new(m) +//! }) +//! } +//! ``` +//! +//! There are also `sync::Lazy` and `unsync::Lazy` convenience types to streamline this pattern: +//! +//! ```rust +//! use std::{sync::Mutex, collections::HashMap}; +//! use lazy::SyncLazy; +//! +//! static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| { +//! let mut m = HashMap::new(); +//! m.insert(13, "Spica".to_string()); +//! m.insert(74, "Hoyten".to_string()); +//! Mutex::new(m) +//! }); +//! +//! fn main() { +//! println!("{:?}", GLOBAL_DATA.lock().unwrap()); +//! } +//! ``` +//! +//! ## General purpose lazy evaluation +//! +//! `Lazy` also works with local variables. +//! +//! ```rust +//! use std::lazy::Lazy; +//! +//! fn main() { +//! let ctx = vec![1, 2, 3]; +//! let thunk = Lazy::new(|| { +//! ctx.iter().sum::<i32>() +//! }); +//! assert_eq!(*thunk, 6); +//! } +//! ``` +//! +//! If you need a lazy field in a struct, you probably should use `OnceCell` +//! directly, because that will allow you to access `self` during initialization. +//! +//! ```rust +//! use std::{fs, path::PathBuf}; +//! +//! use std::lazy::OnceCell; +//! +//! struct Ctx { +//! config_path: PathBuf, +//! config: OnceCell<String>, +//! } +//! +//! impl Ctx { +//! pub fn get_config(&self) -> Result<&str, std::io::Error> { +//! let cfg = self.config.get_or_try_init(|| { +//! fs::read_to_string(&self.config_path) +//! })?; +//! Ok(cfg.as_str()) +//! } +//! } +//! ``` +//! +//! ## Building block +//! +//! Naturally, it is possible to build other abstractions on top of `OnceCell`. +//! For example, this is a `regex!` macro which takes a string literal and returns an +//! *expression* that evaluates to a `&'static Regex`: +//! +//! ``` +//! macro_rules! regex { +//! ($re:literal $(,)?) => {{ +//! static RE: std::lazy::SyncOnceCell<regex::Regex> = std::lazy::SyncOnceCell::new(); +//! RE.get_or_init(|| regex::Regex::new($re).unwrap()) +//! }}; +//! } +//! ``` +//! +//! This macro can be useful to avoid "compile regex on every loop iteration" problem. +//! +//! # Comparison with other interior mutatbility types +//! +//! |`!Sync` types | Access Mode | Drawbacks | +//! |----------------------|------------------------|-----------------------------------------------| +//! |`Cell<T>` | `T` | requires `T: Copy` for `get` | +//! |`RefCell<T>` | `RefMut<T>` / `Ref<T>` | may panic at runtime | +//! |`OnceCell<T>` | `&T` | assignable only once | +//! +//! |`Sync` types | Access Mode | Drawbacks | +//! |----------------------|------------------------|-----------------------------------------------| +//! |`AtomicT` | `T` | works only with certain `Copy` types | +//! |`Mutex<T>` | `MutexGuard<T>` | may deadlock at runtime, may block the thread | +//! |`SyncOnceCell<T>` | `&T` | assignable only once, may block the thread | +//! +//! Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls +//! itself. However, because the assignment can happen only once, such cases should be more rare than +//! equivalents with `RefCell` and `Mutex`. + +use crate::{ + cell::{Cell, UnsafeCell}, + fmt, + hint::unreachable_unchecked, + marker::PhantomData, + ops::Deref, + panic::{RefUnwindSafe, UnwindSafe}, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, + thread::{self, Thread}, +}; + +/// A cell which can be written to only once. Not thread safe. +/// +/// Unlike `:td::cell::RefCell`, a `OnceCell` provides simple `&` +/// references to the contents. +/// +/// # Example +/// ``` +/// use std::lazy::OnceCell; +/// +/// let cell = OnceCell::new(); +/// assert!(cell.get().is_none()); +/// +/// let value: &String = cell.get_or_init(|| { +/// "Hello, World!".to_string() +/// }); +/// assert_eq!(value, "Hello, World!"); +/// assert!(cell.get().is_some()); +/// ``` +pub struct OnceCell<T> { + // Invariant: written to at most once. + inner: UnsafeCell<Option<T>>, +} + +// Similarly to a `Sync` bound on `SyncOnceCell`, we can use +// `&OnceCell` to sneak a `T` through `catch_unwind`, +// by initializing the cell in closure and extracting the value in the +// `Drop`. +#[cfg(feature = "std")] +impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {} +#[cfg(feature = "std")] +impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {} + +impl<T> Default for OnceCell<T> { + fn default() -> Self { + Self::new() + } +} + +impl<T: fmt::Debug> fmt::Debug for OnceCell<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("OnceCell").field(v).finish(), + None => f.write_str("OnceCell(Uninit)"), + } + } +} + +impl<T: Clone> Clone for OnceCell<T> { + fn clone(&self) -> OnceCell<T> { + let res = OnceCell::new(); + if let Some(value) = self.get() { + match res.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + res + } +} + +impl<T: PartialEq> PartialEq for OnceCell<T> { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} + +impl<T: Eq> Eq for OnceCell<T> {} + +impl<T> From<T> for OnceCell<T> { + fn from(value: T) -> Self { + OnceCell { inner: UnsafeCell::new(Some(value)) } + } +} + +impl<T> OnceCell<T> { + /// Creates a new empty cell. + pub const fn new() -> OnceCell<T> { + OnceCell { inner: UnsafeCell::new(None) } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + pub fn get(&self) -> Option<&T> { + // Safe due to `inner`'s invariant + unsafe { &*self.inner.get() }.as_ref() + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + pub fn get_mut(&mut self) -> Option<&mut T> { + // Safe because we have unique access + unsafe { &mut *self.inner.get() }.as_mut() + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. + /// + /// # Example + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.set(92), Ok(())); + /// assert_eq!(cell.set(62), Err(62)); + /// + /// assert!(cell.get().is_some()); + /// ``` + pub fn set(&self, value: T) -> Result<(), T> { + let slot = unsafe { &*self.inner.get() }; + if slot.is_some() { + return Err(value); + } + let slot = unsafe { &mut *self.inner.get() }; + // This is the only place where we set the slot, no races + // due to reentrancy/concurrency are possible, and we've + // checked that slot is currently `None`, so this write + // maintains the `inner`'s invariant. + *slot = Some(value); + Ok(()) + } + + /// Gets the contents of the cell, initializing it with `f` + /// if the cell was empty. + /// + /// # 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`. Doing + /// so results in a panic. + /// + /// # Example + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::new(); + /// let value = cell.get_or_init(|| 92); + /// assert_eq!(value, &92); + /// let value = cell.get_or_init(|| unreachable!()); + /// assert_eq!(value, &92); + /// ``` + 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`. Doing + /// so results in a panic. + /// + /// # Example + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::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)) + /// ``` + pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + if let Some(val) = self.get() { + return Ok(val); + } + let val = f()?; + // Note that *some* forms of reentrant initialization might lead to + // UB (see `reentrant_init` test). I believe that just removing this + // `assert`, while keeping `set/get` would be sound, but it seems + // better to panic, rather than to silently use an old value. + assert!(self.set(val).is_ok(), "reentrant init"); + Ok(self.get().unwrap()) + } + + /// Consumes the `OnceCell`, returning the wrapped value. + /// + /// Returns `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell: OnceCell<String> = OnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + pub fn into_inner(self) -> Option<T> { + // Because `into_inner` takes `self` by value, the compiler statically verifies + // that it is not currently borrowed. So it is safe to move out `Option<T>`. + self.inner.into_inner() + } +} + +/// A value which is initialized on the first access. +/// +/// # Example +/// ``` +/// use std::lazy::Lazy; +/// +/// let lazy: Lazy<i32> = Lazy::new(|| { +/// println!("initializing"); +/// 92 +/// }); +/// println!("ready"); +/// println!("{}", *lazy); +/// println!("{}", *lazy); +/// +/// // Prints: +/// // ready +/// // initializing +/// // 92 +/// // 92 +/// ``` +pub struct Lazy<T, F = fn() -> T> { + cell: OnceCell<T>, + init: Cell<Option<F>>, +} + +#[cfg(feature = "std")] +impl<T, F: RefUnwindSafe> RefUnwindSafe for Lazy<T, F> where OnceCell<T>: RefUnwindSafe {} + +impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for Lazy<T, F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + } +} + +impl<T, F> Lazy<T, F> { + /// Creates a new lazy value with the given initializing function. + /// + /// # Example + /// ``` + /// # fn main() { + /// use std::lazy::Lazy; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = Lazy::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// # } + /// ``` + pub const fn new(init: F) -> Lazy<T, F> { + Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } + } +} + +impl<T, F: FnOnce() -> T> Lazy<T, F> { + /// Forces the evaluation of this lazy value and returns a reference to + /// the result. + /// + /// This is equivalent to the `Deref` impl, but is explicit. + /// + /// # Example + /// ``` + /// use std::lazy::Lazy; + /// + /// let lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + pub fn force(this: &Lazy<T, F>) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("Lazy instance has previously been poisoned"), + }) + } +} + +impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { + type Target = T; + fn deref(&self) -> &T { + Lazy::force(self) + } +} + +impl<T: Default> Default for Lazy<T> { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> Lazy<T> { + Lazy::new(T::default) + } +} + +/// A thread-safe cell which can be written to only once. +/// +/// `OnceCell` provides `&` references to the contents without RAII guards. +/// +/// Reading a non-`None` value out of `OnceCell` establishes a +/// happens-before relationship with a corresponding write. For example, if +/// thread A initializes the cell with `get_or_init(f)`, and thread B +/// subsequently reads the result of this call, B also observes all the side +/// effects of `f`. +/// +/// # Example +/// ``` +/// use std::lazy::SyncOnceCell; +/// +/// static CELL: OnceCell<String> = OnceCell::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!"); +/// ``` +pub struct SyncOnceCell<T> { + // This `state` word is actually an encoded version of just a pointer to a + // `Waiter`, so we add the `PhantomData` appropriately. + state_and_queue: AtomicUsize, + _marker: PhantomData<*mut Waiter>, + // FIXME: switch to `std::mem::MaybeUninit` once we are ready to bump MSRV + // that far. It was stabilized in 1.36.0, so, if you are reading this and + // it's higher than 1.46.0 outside, please send a PR! ;) (and do the same + // for `Lazy`, while we are at it). + pub(crate) value: UnsafeCell<Option<T>>, +} + +// Why do we need `T: Send`? +// Thread A creates a `OnceCell` and shares it with +// scoped thread B, which fills the cell, which is +// then destroyed by A. That is, destructor observes +// a sent value. +unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {} +unsafe impl<T: Send> Send for SyncOnceCell<T> {} + +impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {} +impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {} + +impl<T> Default for SyncOnceCell<T> { + fn default() -> SyncOnceCell<T> { + SyncOnceCell::new() + } +} + +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("SyncOnceCell").field(v).finish(), + None => f.write_str("SyncOnceCell(Uninit)"), + } + } +} + +impl<T: Clone> Clone for SyncOnceCell<T> { + fn clone(&self) -> SyncOnceCell<T> { + let res = SyncOnceCell::new(); + if let Some(value) = self.get() { + match res.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + res + } +} + +impl<T> From<T> for SyncOnceCell<T> { + fn from(value: T) -> Self { + let cell = Self::new(); + cell.get_or_init(|| value); + cell + } +} + +impl<T: PartialEq> PartialEq for SyncOnceCell<T> { + fn eq(&self, other: &SyncOnceCell<T>) -> bool { + self.get() == other.get() + } +} + +impl<T: Eq> Eq for SyncOnceCell<T> {} + +impl<T> SyncOnceCell<T> { + /// Creates a new empty cell. + pub const fn new() -> SyncOnceCell<T> { + SyncOnceCell { + state_and_queue: AtomicUsize::new(INCOMPLETE), + _marker: PhantomData, + value: UnsafeCell::new(None), + } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty, or being initialized. This + /// method never blocks. + pub fn get(&self) -> Option<&T> { + if self.is_initialized() { + // Safe b/c checked is_initialize + Some(unsafe { self.get_unchecked() }) + } else { + None + } + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + pub fn get_mut(&mut self) -> Option<&mut T> { + // Safe b/c we have a unique access. + unsafe { &mut *self.value.get() }.as_mut() + } + + /// Get the reference to the underlying value, without checking if the + /// cell is initialized. + /// + /// Safety: + /// + /// Caller must ensure that the cell is in initialized state, and that + /// the contents are acquired by (synchronized to) this thread. + pub unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + let slot: &Option<T> = &*self.value.get(); + match slot { + Some(value) => value, + // This unsafe does improve performance, see `examples/bench`. + None => { + debug_assert!(false); + unreachable_unchecked() + } + } + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. + /// + /// # Example + /// ``` + /// 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)); + /// } + /// ``` + 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. + /// + /// # Example + /// ``` + /// 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); + /// ``` + 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. + /// + /// # Example + /// ``` + /// 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)) + /// ``` + pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + // Fast path check + if let Some(value) = self.get() { + return Ok(value); + } + self.initialize(f)?; + + // Safe b/c called initialize + debug_assert!(self.is_initialized()); + Ok(unsafe { self.get_unchecked() }) + } + + /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns + /// `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// 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())); + /// ``` + pub fn into_inner(self) -> Option<T> { + // Because `into_inner` takes `self` by value, the compiler statically verifies + // that it is not currently borrowed. So it is safe to move out `Option<T>`. + self.value.into_inner() + } + + /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). + #[inline] + fn is_initialized(&self) -> bool { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us, and, this being a fast path, weaker + // ordering helps with performance. This `Acquire` synchronizes with + // `SeqCst` operations on the slow path. + self.state_and_queue.load(Ordering::Acquire) == COMPLETE + } + + /// Safety: synchronizes with store to value via SeqCst read from state, + /// writes value only once because we never get to INCOMPLETE state after a + /// successful write. + #[cold] + fn initialize<F, E>(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result<T, E>, + { + let mut f = Some(f); + let mut res: Result<(), E> = Ok(()); + let slot = &self.value; + initialize_inner(&self.state_and_queue, &mut || { + let f = f.take().unwrap(); + match f() { + Ok(value) => { + unsafe { *slot.get() = Some(value) }; + true + } + Err(e) => { + res = Err(e); + false + } + } + }); + res + } +} + +// region: copy-paste +// The following code is copied from `sync::Once`. +// This should be uncopypasted once we decide the right way to handle panics. +const INCOMPLETE: usize = 0x0; +const RUNNING: usize = 0x1; +const COMPLETE: usize = 0x2; + +const STATE_MASK: usize = 0x3; + + +#[repr(align(4))] +struct Waiter { + thread: Cell<Option<Thread>>, + signaled: AtomicBool, + next: *const Waiter, +} + +struct WaiterQueue<'a> { + state_and_queue: &'a AtomicUsize, + set_state_on_drop_to: usize, +} + +impl Drop for WaiterQueue<'_> { + fn drop(&mut self) { + let state_and_queue = + self.state_and_queue.swap(self.set_state_on_drop_to, Ordering::AcqRel); + + assert_eq!(state_and_queue & STATE_MASK, RUNNING); + + unsafe { + let mut queue = (state_and_queue & !STATE_MASK) as *const Waiter; + while !queue.is_null() { + let next = (*queue).next; + let thread = (*queue).thread.replace(None).unwrap(); + (*queue).signaled.store(true, Ordering::Release); + queue = next; + thread.unpark(); + } + } + } +} + +fn initialize_inner(my_state_and_queue: &AtomicUsize, init: &mut dyn FnMut() -> bool) -> bool { + let mut state_and_queue = my_state_and_queue.load(Ordering::Acquire); + + loop { + match state_and_queue { + COMPLETE => return true, + INCOMPLETE => { + let old = my_state_and_queue.compare_and_swap( + state_and_queue, + RUNNING, + Ordering::Acquire, + ); + if old != state_and_queue { + state_and_queue = old; + continue; + } + let mut waiter_queue = WaiterQueue { + state_and_queue: my_state_and_queue, + set_state_on_drop_to: INCOMPLETE, + }; + let success = init(); + + waiter_queue.set_state_on_drop_to = if success { COMPLETE } else { INCOMPLETE }; + return success; + } + _ => { + assert!(state_and_queue & STATE_MASK == RUNNING); + wait(&my_state_and_queue, state_and_queue); + state_and_queue = my_state_and_queue.load(Ordering::Acquire); + } + } + } +} + +fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { + loop { + if current_state & STATE_MASK != RUNNING { + return; + } + + let node = Waiter { + thread: Cell::new(Some(thread::current())), + signaled: AtomicBool::new(false), + next: (current_state & !STATE_MASK) as *const Waiter, + }; + let me = &node as *const Waiter as usize; + + let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release); + if old != current_state { + current_state = old; + continue; + } + + while !node.signaled.load(Ordering::Acquire) { + thread::park(); + } + break; + } +} +// endregion: copy-paste + +/// A value which is initialized on the first access. +/// +/// This type is thread-safe and can be used in statics: +/// +/// # Example +/// ``` +/// use std::collections::HashMap; +/// +/// use std::lazy::Lazy; +/// +/// static HASHMAP: Lazy<HashMap<i32, String>> = Lazy::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") +/// } +/// ``` +pub struct SyncLazy<T, F = fn() -> T> { + cell: SyncOnceCell<T>, + init: Cell<Option<F>>, +} + +impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for SyncLazy<T, F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SyncLazy").field("cell", &self.cell).field("init", &"..").finish() + } +} + +// 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. +unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {} +// auto-derived `Send` impl is OK. + +#[cfg(feature = "std")] +impl<T, F: RefUnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {} + +impl<T, F> SyncLazy<T, F> { + /// Creates a new lazy value with the given initializing + /// function. + 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. + /// + /// # Example + /// ``` + /// use std::lazy::SyncLazy; + /// + /// let lazy = SyncLazy::new(|| 92); + /// + /// assert_eq!(SyncLazy::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + pub fn force(this: &SyncLazy<T, F>) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("SyncLazy instance has previously been poisoned"), + }) + } +} + +impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> { + type Target = T; + fn deref(&self) -> &T { + SyncLazy::force(self) + } +} + +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) + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bc07c6b487b17..0720aa769238e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -466,6 +466,12 @@ pub mod process; pub mod sync; pub mod time; +#[unstable( + feature = "std_lazy", + issue = "99", +)] +pub mod lazy; + #[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. From 973e9531771481a657df82483380a9070fb1e3b9 Mon Sep 17 00:00:00 2001 From: Ashley Mannix <ashleymannix@live.com.au> Date: Tue, 14 Jan 2020 13:34:23 +1000 Subject: [PATCH 2/6] integrate Lazy into std layout --- src/libcore/cell.rs | 362 ++++++++++++++++++++++++++- src/libstd/lazy.rs | 594 +++++++++++++------------------------------- src/libstd/lib.rs | 6 +- src/stdsimd | 1 + 4 files changed, 529 insertions(+), 434 deletions(-) create mode 160000 src/stdsimd diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index e7eecf7540ad7..45b5c5b7fd77e 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -18,15 +18,16 @@ //! [`RwLock`](../../std/sync/struct.RwLock.html) or //! [`atomic`](../../core/sync/atomic/index.html) types. //! -//! Values of the `Cell<T>` and `RefCell<T>` types may be mutated through shared references (i.e. +//! Values of the cell types may be mutated through shared references (i.e. //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`) -//! references. We say that `Cell<T>` and `RefCell<T>` provide 'interior mutability', in contrast +//! references. We say that cells provide 'interior mutability', in contrast //! with typical Rust types that exhibit 'inherited mutability'. //! -//! Cell types come in two flavors: `Cell<T>` and `RefCell<T>`. `Cell<T>` implements interior +//! Cell types come in several flavors. `Cell<T>` implements interior //! mutability by moving values in and out of the `Cell<T>`. To use references instead of values, -//! one must use the `RefCell<T>` type, acquiring a write lock before mutating. `Cell<T>` provides -//! methods to retrieve and change the current interior value: +//! one must use the `RefCell<T>` type, acquiring a write lock before mutating. For values that +//! only need lazy initialization, one can use the `OnceCell<T>` or `LazyCell<T, F>` types. `Cell<T>` +//! provides methods to retrieve and change the current interior value: //! //! - For types that implement `Copy`, the `get` method retrieves the current interior value. //! - For types that implement `Default`, the `take` method replaces the current interior value @@ -43,6 +44,12 @@ //! to borrow a value that is already mutably borrowed; when this happens it results in thread //! panic. //! +//! `OnceCell<T>` allows one to access a value by also providing an initialization function for it. +//! If the `OnceCell<T>` already contains an initialized value then it is returned, otherwise the +//! initialization function is run and the result is stored in the cell. +//! `LazyCell<T, F>` is similar to `OnceCell<T>`, but keeps its initialization function as part of +//! the type, so it doesn't need to be provided whenever the cell is accessed. +//! //! # When to choose interior mutability //! //! The more common inherited mutability, where one must have unique access to mutate a value, is @@ -1414,6 +1421,351 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> { } } +/// A cell which can be written to only once. +/// +/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value. +/// Unlike `Cell`, a `OnceCell` doesn't require `T: Copy` to access its value. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::cell::OnceCell; +/// +/// let cell = OnceCell::new(); +/// assert!(cell.get().is_none()); +/// +/// let value: &String = cell.get_or_init(|| { +/// "Hello, World!".to_string() +/// }); +/// assert_eq!(value, "Hello, World!"); +/// assert!(cell.get().is_some()); +/// ``` +#[unstable(feature = "once_cell", issue = "68198")] +pub struct OnceCell<T> { + // Invariant: written to at most once. + inner: UnsafeCell<Option<T>>, +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T> Default for OnceCell<T> { + fn default() -> Self { + Self::new() + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: fmt::Debug> fmt::Debug for OnceCell<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("OnceCell").field(v).finish(), + None => f.write_str("OnceCell(Uninit)"), + } + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Clone> Clone for OnceCell<T> { + fn clone(&self) -> OnceCell<T> { + let res = OnceCell::new(); + if let Some(value) = self.get() { + match res.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + res + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: PartialEq> PartialEq for OnceCell<T> { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Eq> Eq for OnceCell<T> {} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T> From<T> for OnceCell<T> { + fn from(value: T) -> Self { + OnceCell { inner: UnsafeCell::new(Some(value)) } + } +} + +impl<T> OnceCell<T> { + /// Creates a new empty cell. + #[unstable(feature = "once_cell", issue = "68198")] + pub const fn new() -> OnceCell<T> { + OnceCell { inner: UnsafeCell::new(None) } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + #[unstable(feature = "once_cell", issue = "68198")] + pub fn get(&self) -> Option<&T> { + // Safe due to `inner`'s invariant + unsafe { &*self.inner.get() }.as_ref() + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + #[unstable(feature = "once_cell", issue = "68198")] + pub fn get_mut(&mut self) -> Option<&mut T> { + // Safe because we have unique access + unsafe { &mut *self.inner.get() }.as_mut() + } + + /// Sets the contents of the cell to `value`. + /// + /// # Errors + /// + /// This method returns `Ok(())` if the cell was empty and `Err(value)` if + /// it was full. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.set(92), Ok(())); + /// assert_eq!(cell.set(62), Err(62)); + /// + /// assert!(cell.get().is_some()); + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub fn set(&self, value: T) -> Result<(), T> { + let slot = unsafe { &*self.inner.get() }; + if slot.is_some() { + return Err(value); + } + let slot = unsafe { &mut *self.inner.get() }; + // This is the only place where we set the slot, no races + // due to reentrancy/concurrency are possible, and we've + // checked that slot is currently `None`, so this write + // maintains the `inner`'s invariant. + *slot = Some(value); + Ok(()) + } + + /// Gets the contents of the cell, initializing it with `f` + /// if the cell was empty. + /// + /// # 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`. Doing + /// so results in a panic. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell = OnceCell::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 = "68198")] + 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`. Doing + /// so results in a panic. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell = OnceCell::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 = "68198")] + pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + if let Some(val) = self.get() { + return Ok(val); + } + let val = f()?; + // Note that *some* forms of reentrant initialization might lead to + // UB (see `reentrant_init` test). I believe that just removing this + // `assert`, while keeping `set/get` would be sound, but it seems + // better to panic, rather than to silently use an old value. + assert!(self.set(val).is_ok(), "reentrant init"); + Ok(self.get().unwrap()) + } + + /// Consumes the cell, returning the wrapped value. + /// + /// Returns `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell: OnceCell<String> = OnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub fn into_inner(self) -> Option<T> { + // Because `into_inner` takes `self` by value, the compiler statically verifies + // that it is not currently borrowed. So it is safe to move out `Option<T>`. + self.inner.into_inner() + } +} + +/// A value which is initialized on the first access. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::cell::LazyCell; +/// +/// let lazy: LazyCell<i32> = LazyCell::new(|| { +/// println!("initializing"); +/// 92 +/// }); +/// println!("ready"); +/// println!("{}", *lazy); +/// println!("{}", *lazy); +/// +/// // Prints: +/// // ready +/// // initializing +/// // 92 +/// // 92 +/// ``` +#[unstable(feature = "once_cell", issue = "68198")] +pub struct LazyCell<T, F = fn() -> T> { + cell: OnceCell<T>, + init: Cell<Option<F>>, +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for LazyCell<T, F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("LazyCell").field("cell", &self.cell).field("init", &"..").finish() + } +} + +impl<T, F> LazyCell<T, F> { + /// Creates a new lazy value with the given initializing function. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// # fn main() { + /// use std::cell::LazyCell; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = LazyCell::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// # } + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub const fn new(init: F) -> LazyCell<T, F> { + LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) } + } +} + +impl<T, F: FnOnce() -> T> LazyCell<T, F> { + /// Forces the evaluation of this lazy value and returns a reference to + /// the result. + /// + /// This is equivalent to the `Deref` impl, but is explicit. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::LazyCell; + /// + /// let lazy = LazyCell::new(|| 92); + /// + /// assert_eq!(LazyCell::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub fn force(this: &LazyCell<T, F>) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("`LazyCell` instance has previously been poisoned"), + }) + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> { + type Target = T; + fn deref(&self) -> &T { + LazyCell::force(self) + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Default> Default for LazyCell<T> { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> LazyCell<T> { + LazyCell::new(T::default) + } +} + /// The core primitive for interior mutability in Rust. /// /// `UnsafeCell<T>` is a type that wraps some `T` and indicates unsafe interior operations on the diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index bcac2dc311aff..11b5e5d40a10d 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -1,40 +1,30 @@ -//! `lazy` modules provides lazy values and one-time initialization of static data. +//! Lazy values and one-time initialization of static data. //! -//! `lazy` provides two new cell-like types, `OnceCell` and `SyncOnceCell`. `OnceCell` +//! `lazy` provides two new cell-like types, `Once` and `Lazy`. `Once` //! might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access -//! to the stored contents. In a nutshell, API looks *roughly* like this: -//! -//! ```rust,ignore -//! impl<T> OnceCell<T> { -//! fn new() -> OnceCell<T> { ... } -//! fn set(&self, value: T) -> Result<(), T> { ... } -//! fn get(&self) -> Option<&T> { ... } -//! } -//! ``` +//! to the stored contents. //! //! Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. //! Because of the single assignment restriction `get` can return an `&T` instead of `Ref<T>` //! or `MutexGuard<T>`. //! -//! The `SyncOnceCell` flavor is thread-safe (that is, implements [`Sync`]) trait, while `OnceCell` one is not. -//! -//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html -//! //! # Patterns //! -//! `OnceCell` might be useful for a variety of patterns. +//! `Once` can be useful for a variety of patterns. //! //! ## Safe Initialization of global data //! //! ```rust +//! #![feature(once_cell)] +//! //! use std::{env, io}; -//! use std::lazy::SyncOnceCell; +//! use std::lazy::Once; //! //! #[derive(Debug)] //! pub struct Logger { //! // ... //! } -//! static INSTANCE: OnceCell<Logger> = OnceCell::new(); +//! static INSTANCE: Once<Logger> = Once::new(); //! //! impl Logger { //! pub fn global() -> &'static Logger { @@ -59,11 +49,13 @@ //! This is essentially `lazy_static!` macro, but without a macro. //! //! ```rust +//! #![feature(once_cell)] +//! //! use std::{sync::Mutex, collections::HashMap}; -//! use lazy::SyncOnceCell; +//! use lazy::Once; //! //! fn global_data() -> &'static Mutex<HashMap<i32, String>> { -//! static INSTANCE: OnceCell<Mutex<HashMap<i32, String>>> = OnceCell::new(); +//! static INSTANCE: Once<Mutex<HashMap<i32, String>>> = Once::new(); //! INSTANCE.get_or_init(|| { //! let mut m = HashMap::new(); //! m.insert(13, "Spica".to_string()); @@ -73,11 +65,13 @@ //! } //! ``` //! -//! There are also `sync::Lazy` and `unsync::Lazy` convenience types to streamline this pattern: +//! There is also `Lazy` to streamline this pattern: //! //! ```rust +//! #![feature(once_cell)] +//! //! use std::{sync::Mutex, collections::HashMap}; -//! use lazy::SyncLazy; +//! use lazy::Lazy; //! //! static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| { //! let mut m = HashMap::new(); @@ -96,6 +90,8 @@ //! `Lazy` also works with local variables. //! //! ```rust +//! #![feature(once_cell)] +//! //! use std::lazy::Lazy; //! //! fn main() { @@ -107,17 +103,19 @@ //! } //! ``` //! -//! If you need a lazy field in a struct, you probably should use `OnceCell` +//! If you need a lazy field in a struct, you probably should use `Once` //! directly, because that will allow you to access `self` during initialization. //! //! ```rust +//! #![feature(once_cell)] +//! //! use std::{fs, path::PathBuf}; //! -//! use std::lazy::OnceCell; +//! use std::lazy::Once; //! //! struct Ctx { //! config_path: PathBuf, -//! config: OnceCell<String>, +//! config: Once<String>, //! } //! //! impl Ctx { @@ -132,14 +130,14 @@ //! //! ## Building block //! -//! Naturally, it is possible to build other abstractions on top of `OnceCell`. +//! Naturally, it is possible to build other abstractions on top of `Once`. //! For example, this is a `regex!` macro which takes a string literal and returns an //! *expression* that evaluates to a `&'static Regex`: //! //! ``` //! macro_rules! regex { //! ($re:literal $(,)?) => {{ -//! static RE: std::lazy::SyncOnceCell<regex::Regex> = std::lazy::SyncOnceCell::new(); +//! static RE: std::lazy::Once<regex::Regex> = std::lazy::Once::new(); //! RE.get_or_init(|| regex::Regex::new($re).unwrap()) //! }}; //! } @@ -147,19 +145,21 @@ //! //! This macro can be useful to avoid "compile regex on every loop iteration" problem. //! -//! # Comparison with other interior mutatbility types +//! # Comparison with other interior mutability types //! //! |`!Sync` types | Access Mode | Drawbacks | //! |----------------------|------------------------|-----------------------------------------------| //! |`Cell<T>` | `T` | requires `T: Copy` for `get` | //! |`RefCell<T>` | `RefMut<T>` / `Ref<T>` | may panic at runtime | //! |`OnceCell<T>` | `&T` | assignable only once | +//! |`LazyCell<T, F>` | `&T` | assignable only once | //! //! |`Sync` types | Access Mode | Drawbacks | //! |----------------------|------------------------|-----------------------------------------------| //! |`AtomicT` | `T` | works only with certain `Copy` types | //! |`Mutex<T>` | `MutexGuard<T>` | may deadlock at runtime, may block the thread | -//! |`SyncOnceCell<T>` | `&T` | assignable only once, may block the thread | +//! |`Once<T>` | `&T` | assignable only once, may block the thread | +//! |`Lazy<T, F>` | `&T` | assignable only once, may block the thread | //! //! Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls //! itself. However, because the assignment can happen only once, such cases should be more rare than @@ -168,326 +168,14 @@ use crate::{ cell::{Cell, UnsafeCell}, fmt, - hint::unreachable_unchecked, marker::PhantomData, + mem::MaybeUninit, ops::Deref, panic::{RefUnwindSafe, UnwindSafe}, sync::atomic::{AtomicBool, AtomicUsize, Ordering}, thread::{self, Thread}, }; -/// A cell which can be written to only once. Not thread safe. -/// -/// Unlike `:td::cell::RefCell`, a `OnceCell` provides simple `&` -/// references to the contents. -/// -/// # Example -/// ``` -/// use std::lazy::OnceCell; -/// -/// let cell = OnceCell::new(); -/// assert!(cell.get().is_none()); -/// -/// let value: &String = cell.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// assert!(cell.get().is_some()); -/// ``` -pub struct OnceCell<T> { - // Invariant: written to at most once. - inner: UnsafeCell<Option<T>>, -} - -// Similarly to a `Sync` bound on `SyncOnceCell`, we can use -// `&OnceCell` to sneak a `T` through `catch_unwind`, -// by initializing the cell in closure and extracting the value in the -// `Drop`. -#[cfg(feature = "std")] -impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {} -#[cfg(feature = "std")] -impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {} - -impl<T> Default for OnceCell<T> { - fn default() -> Self { - Self::new() - } -} - -impl<T: fmt::Debug> fmt::Debug for OnceCell<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("OnceCell").field(v).finish(), - None => f.write_str("OnceCell(Uninit)"), - } - } -} - -impl<T: Clone> Clone for OnceCell<T> { - fn clone(&self) -> OnceCell<T> { - let res = OnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - res - } -} - -impl<T: PartialEq> PartialEq for OnceCell<T> { - fn eq(&self, other: &Self) -> bool { - self.get() == other.get() - } -} - -impl<T: Eq> Eq for OnceCell<T> {} - -impl<T> From<T> for OnceCell<T> { - fn from(value: T) -> Self { - OnceCell { inner: UnsafeCell::new(Some(value)) } - } -} - -impl<T> OnceCell<T> { - /// Creates a new empty cell. - pub const fn new() -> OnceCell<T> { - OnceCell { inner: UnsafeCell::new(None) } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - pub fn get(&self) -> Option<&T> { - // Safe due to `inner`'s invariant - unsafe { &*self.inner.get() }.as_ref() - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - pub fn get_mut(&mut self) -> Option<&mut T> { - // Safe because we have unique access - unsafe { &mut *self.inner.get() }.as_mut() - } - - /// Sets the contents of this cell to `value`. - /// - /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was - /// full. - /// - /// # Example - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert!(cell.get().is_none()); - /// - /// assert_eq!(cell.set(92), Ok(())); - /// assert_eq!(cell.set(62), Err(62)); - /// - /// assert!(cell.get().is_some()); - /// ``` - pub fn set(&self, value: T) -> Result<(), T> { - let slot = unsafe { &*self.inner.get() }; - if slot.is_some() { - return Err(value); - } - let slot = unsafe { &mut *self.inner.get() }; - // This is the only place where we set the slot, no races - // due to reentrancy/concurrency are possible, and we've - // checked that slot is currently `None`, so this write - // maintains the `inner`'s invariant. - *slot = Some(value); - Ok(()) - } - - /// Gets the contents of the cell, initializing it with `f` - /// if the cell was empty. - /// - /// # 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`. Doing - /// so results in a panic. - /// - /// # Example - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// let value = cell.get_or_init(|| 92); - /// assert_eq!(value, &92); - /// let value = cell.get_or_init(|| unreachable!()); - /// assert_eq!(value, &92); - /// ``` - 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`. Doing - /// so results in a panic. - /// - /// # Example - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::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)) - /// ``` - pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result<T, E>, - { - if let Some(val) = self.get() { - return Ok(val); - } - let val = f()?; - // Note that *some* forms of reentrant initialization might lead to - // UB (see `reentrant_init` test). I believe that just removing this - // `assert`, while keeping `set/get` would be sound, but it seems - // better to panic, rather than to silently use an old value. - assert!(self.set(val).is_ok(), "reentrant init"); - Ok(self.get().unwrap()) - } - - /// Consumes the `OnceCell`, returning the wrapped value. - /// - /// Returns `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell: OnceCell<String> = OnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = OnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); - /// ``` - pub fn into_inner(self) -> Option<T> { - // Because `into_inner` takes `self` by value, the compiler statically verifies - // that it is not currently borrowed. So it is safe to move out `Option<T>`. - self.inner.into_inner() - } -} - -/// A value which is initialized on the first access. -/// -/// # Example -/// ``` -/// use std::lazy::Lazy; -/// -/// let lazy: Lazy<i32> = Lazy::new(|| { -/// println!("initializing"); -/// 92 -/// }); -/// println!("ready"); -/// println!("{}", *lazy); -/// println!("{}", *lazy); -/// -/// // Prints: -/// // ready -/// // initializing -/// // 92 -/// // 92 -/// ``` -pub struct Lazy<T, F = fn() -> T> { - cell: OnceCell<T>, - init: Cell<Option<F>>, -} - -#[cfg(feature = "std")] -impl<T, F: RefUnwindSafe> RefUnwindSafe for Lazy<T, F> where OnceCell<T>: RefUnwindSafe {} - -impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for Lazy<T, F> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() - } -} - -impl<T, F> Lazy<T, F> { - /// Creates a new lazy value with the given initializing function. - /// - /// # Example - /// ``` - /// # fn main() { - /// use std::lazy::Lazy; - /// - /// let hello = "Hello, World!".to_string(); - /// - /// let lazy = Lazy::new(|| hello.to_uppercase()); - /// - /// assert_eq!(&*lazy, "HELLO, WORLD!"); - /// # } - /// ``` - pub const fn new(init: F) -> Lazy<T, F> { - Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } - } -} - -impl<T, F: FnOnce() -> T> Lazy<T, F> { - /// Forces the evaluation of this lazy value and returns a reference to - /// the result. - /// - /// This is equivalent to the `Deref` impl, but is explicit. - /// - /// # Example - /// ``` - /// use std::lazy::Lazy; - /// - /// let lazy = Lazy::new(|| 92); - /// - /// assert_eq!(Lazy::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - pub fn force(this: &Lazy<T, F>) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("Lazy instance has previously been poisoned"), - }) - } -} - -impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { - type Target = T; - fn deref(&self) -> &T { - Lazy::force(self) - } -} - -impl<T: Default> Default for Lazy<T> { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> Lazy<T> { - Lazy::new(T::default) - } -} - /// A thread-safe cell which can be written to only once. /// /// `OnceCell` provides `&` references to the contents without RAII guards. @@ -498,9 +186,12 @@ impl<T: Default> Default for Lazy<T> { /// subsequently reads the result of this call, B also observes all the side /// effects of `f`. /// -/// # Example +/// # Examples +/// /// ``` -/// use std::lazy::SyncOnceCell; +/// #![feature(once_cell)] +/// +/// use std::lazy::Once; /// /// static CELL: OnceCell<String> = OnceCell::new(); /// assert!(CELL.get().is_none()); @@ -516,16 +207,14 @@ impl<T: Default> Default for Lazy<T> { /// assert!(value.is_some()); /// assert_eq!(value.unwrap().as_str(), "Hello, World!"); /// ``` -pub struct SyncOnceCell<T> { +#[unstable(feature = "once_cell", issue = "68198")] +pub struct Once<T> { // This `state` word is actually an encoded version of just a pointer to a // `Waiter`, so we add the `PhantomData` appropriately. state_and_queue: AtomicUsize, _marker: PhantomData<*mut Waiter>, - // FIXME: switch to `std::mem::MaybeUninit` once we are ready to bump MSRV - // that far. It was stabilized in 1.36.0, so, if you are reading this and - // it's higher than 1.46.0 outside, please send a PR! ;) (and do the same - // for `Lazy`, while we are at it). - pub(crate) value: UnsafeCell<Option<T>>, + // Whether or not the value is initialized is tracked by `state_and_queue`. + value: UnsafeCell<MaybeUninit<T>>, } // Why do we need `T: Send`? @@ -533,30 +222,37 @@ pub struct SyncOnceCell<T> { // scoped thread B, which fills the cell, which is // then destroyed by A. That is, destructor observes // a sent value. -unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {} -unsafe impl<T: Send> Send for SyncOnceCell<T> {} +#[unstable(feature = "once_cell", issue = "68198")] +unsafe impl<T: Sync + Send> Sync for Once<T> {} +#[unstable(feature = "once_cell", issue = "68198")] +unsafe impl<T: Send> Send for Once<T> {} -impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {} -impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {} +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for Once<T> {} +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: UnwindSafe> UnwindSafe for Once<T> {} -impl<T> Default for SyncOnceCell<T> { - fn default() -> SyncOnceCell<T> { - SyncOnceCell::new() +#[unstable(feature = "once_cell", issue = "68198")] +impl<T> Default for Once<T> { + fn default() -> Once<T> { + Once::new() } } -impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> { +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: fmt::Debug> fmt::Debug for Once<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.get() { - Some(v) => f.debug_tuple("SyncOnceCell").field(v).finish(), - None => f.write_str("SyncOnceCell(Uninit)"), + Some(v) => f.debug_tuple("Once").field(v).finish(), + None => f.write_str("Once(Uninit)"), } } } -impl<T: Clone> Clone for SyncOnceCell<T> { - fn clone(&self) -> SyncOnceCell<T> { - let res = SyncOnceCell::new(); +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Clone> Clone for Once<T> { + fn clone(&self) -> Once<T> { + let res = Once::new(); if let Some(value) = self.get() { match res.set(value.clone()) { Ok(()) => (), @@ -567,7 +263,8 @@ impl<T: Clone> Clone for SyncOnceCell<T> { } } -impl<T> From<T> for SyncOnceCell<T> { +#[unstable(feature = "once_cell", issue = "68198")] +impl<T> From<T> for Once<T> { fn from(value: T) -> Self { let cell = Self::new(); cell.get_or_init(|| value); @@ -575,21 +272,24 @@ impl<T> From<T> for SyncOnceCell<T> { } } -impl<T: PartialEq> PartialEq for SyncOnceCell<T> { - fn eq(&self, other: &SyncOnceCell<T>) -> bool { +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: PartialEq> PartialEq for Once<T> { + fn eq(&self, other: &Once<T>) -> bool { self.get() == other.get() } } -impl<T: Eq> Eq for SyncOnceCell<T> {} +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Eq> Eq for Once<T> {} -impl<T> SyncOnceCell<T> { +impl<T> Once<T> { /// Creates a new empty cell. - pub const fn new() -> SyncOnceCell<T> { - SyncOnceCell { + #[unstable(feature = "once_cell", issue = "68198")] + pub const fn new() -> Once<T> { + Once { state_and_queue: AtomicUsize::new(INCOMPLETE), _marker: PhantomData, - value: UnsafeCell::new(None), + value: UnsafeCell::new(MaybeUninit::uninit()), } } @@ -597,6 +297,7 @@ impl<T> SyncOnceCell<T> { /// /// Returns `None` if the cell is empty, or being initialized. This /// method never blocks. + #[unstable(feature = "once_cell", issue = "68198")] pub fn get(&self) -> Option<&T> { if self.is_initialized() { // Safe b/c checked is_initialize @@ -609,9 +310,14 @@ impl<T> SyncOnceCell<T> { /// Gets the mutable reference to the underlying value. /// /// Returns `None` if the cell is empty. + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_mut(&mut self) -> Option<&mut T> { - // Safe b/c we have a unique access. - unsafe { &mut *self.value.get() }.as_mut() + if self.is_initialized() { + // Safe b/c checked is_initialize and we have a unique access + Some(unsafe { self.get_unchecked_mut() }) + } else { + None + } } /// Get the reference to the underlying value, without checking if the @@ -621,17 +327,23 @@ impl<T> SyncOnceCell<T> { /// /// Caller must ensure that the cell is in initialized state, and that /// the contents are acquired by (synchronized to) this thread. + #[unstable(feature = "once_cell", issue = "68198")] pub unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); - let slot: &Option<T> = &*self.value.get(); - match slot { - Some(value) => value, - // This unsafe does improve performance, see `examples/bench`. - None => { - debug_assert!(false); - unreachable_unchecked() - } - } + (&*self.value.get()).get_ref() + } + + /// Get the reference to the underlying value, without checking if the + /// cell is initialized. + /// + /// Safety: + /// + /// Caller must ensure that the cell is in initialized state, and that + /// the contents are acquired by (synchronized to) this thread. + #[unstable(feature = "once_cell", issue = "68198")] + pub unsafe fn get_unchecked_mut(&mut self) -> &mut T { + debug_assert!(self.is_initialized()); + (&mut *self.value.get()).get_mut() } /// Sets the contents of this cell to `value`. @@ -639,11 +351,14 @@ impl<T> SyncOnceCell<T> { /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was /// full. /// - /// # Example + /// # Examples + /// /// ``` - /// use std::lazy::SyncOnceCell; + /// #![feature(once_cell)] /// - /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new(); + /// use std::lazy::Once; + /// + /// static CELL: Once<i32> = Once::new(); /// /// fn main() { /// assert!(CELL.get().is_none()); @@ -656,6 +371,7 @@ impl<T> SyncOnceCell<T> { /// assert_eq!(CELL.get(), Some(&92)); /// } /// ``` + #[unstable(feature = "once_cell", issue = "68198")] pub fn set(&self, value: T) -> Result<(), T> { let mut value = Some(value); self.get_or_init(|| value.take().unwrap()); @@ -681,16 +397,20 @@ impl<T> SyncOnceCell<T> { /// exact outcome is unspecified. Current implementation deadlocks, but /// this may be changed to a panic in the future. /// - /// # Example + /// # Examples + /// /// ``` - /// use std::lazy::SyncOnceCell; + /// #![feature(once_cell)] + /// + /// use std::lazy::Once; /// - /// let cell = SyncOnceCell::new(); + /// let cell = Once::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 = "68198")] pub fn get_or_init<F>(&self, f: F) -> &T where F: FnOnce() -> T, @@ -713,11 +433,14 @@ impl<T> SyncOnceCell<T> { /// The exact outcome is unspecified. Current implementation /// deadlocks, but this may be changed to a panic in the future. /// - /// # Example + /// # Examples + /// /// ``` - /// use std::lazy::SyncOnceCell; + /// #![feature(once_cell)] /// - /// let cell = SyncOnceCell::new(); + /// use std::lazy::Once; + /// + /// let cell = Once::new(); /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); /// assert!(cell.get().is_none()); /// let value = cell.get_or_try_init(|| -> Result<i32, ()> { @@ -726,6 +449,7 @@ impl<T> SyncOnceCell<T> { /// assert_eq!(value, Ok(&92)); /// assert_eq!(cell.get(), Some(&92)) /// ``` + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result<T, E>, @@ -741,25 +465,33 @@ impl<T> SyncOnceCell<T> { Ok(unsafe { self.get_unchecked() }) } - /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns + /// Consumes the `Once`, returning the wrapped value. Returns /// `None` if the cell was empty. /// /// # Examples /// /// ``` - /// use std::lazy::SyncOnceCell; + /// #![feature(once_cell)] + /// + /// use std::lazy::Once; /// - /// let cell: SyncOnceCell<String> = SyncOnceCell::new(); + /// let cell: Once<String> = Once::new(); /// assert_eq!(cell.into_inner(), None); /// - /// let cell = SyncOnceCell::new(); + /// let cell = Once::new(); /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` + #[unstable(feature = "once_cell", issue = "68198")] pub fn into_inner(self) -> Option<T> { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option<T>`. - self.value.into_inner() + if self.is_initialized() { + // Safe b/c called initialize + return Some(unsafe { self.value.into_inner().assume_init() }); + } + + None } /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). @@ -787,7 +519,7 @@ impl<T> SyncOnceCell<T> { let f = f.take().unwrap(); match f() { Ok(value) => { - unsafe { *slot.get() = Some(value) }; + unsafe { (&mut *slot.get()).write(value) }; true } Err(e) => { @@ -800,16 +532,16 @@ impl<T> SyncOnceCell<T> { } } -// region: copy-paste -// The following code is copied from `sync::Once`. +// FIXME: The following code is copied from `sync::Once`. // This should be uncopypasted once we decide the right way to handle panics. +// Do we want to effectively move the `Once` synchronization here and make `Once` +// a newtype: `pub struct Once(lazy::Once<()>)`? const INCOMPLETE: usize = 0x0; const RUNNING: usize = 0x1; const COMPLETE: usize = 0x2; const STATE_MASK: usize = 0x3; - #[repr(align(4))] struct Waiter { thread: Cell<Option<Thread>>, @@ -901,14 +633,16 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { break; } } -// endregion: copy-paste /// A value which is initialized on the first access. /// /// This type is thread-safe and can be used in statics: /// -/// # Example +/// # Examples +/// /// ``` +/// #![feature(once_cell)] +/// /// use std::collections::HashMap; /// /// use std::lazy::Lazy; @@ -935,68 +669,78 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { /// // Some("Hoyten") /// } /// ``` -pub struct SyncLazy<T, F = fn() -> T> { - cell: SyncOnceCell<T>, +#[unstable(feature = "once_cell", issue = "68198")] +pub struct Lazy<T, F = fn() -> T> { + cell: Once<T>, init: Cell<Option<F>>, } -impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for SyncLazy<T, F> { +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for Lazy<T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SyncLazy").field("cell", &self.cell).field("init", &"..").finish() + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() } } -// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine +// We never create a `&F` from a `&Lazy<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. -unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {} +#[unstable(feature = "once_cell", issue = "68198")] +unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {} // auto-derived `Send` impl is OK. -#[cfg(feature = "std")] -impl<T, F: RefUnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {} +#[unstable(feature = "once_cell", issue = "68198")] +impl<T, F: RefUnwindSafe> RefUnwindSafe for Lazy<T, F> where Once<T>: RefUnwindSafe {} -impl<T, F> SyncLazy<T, F> { +impl<T, F> Lazy<T, F> { /// Creates a new lazy value with the given initializing /// function. - pub const fn new(f: F) -> SyncLazy<T, F> { - SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } + #[unstable(feature = "once_cell", issue = "68198")] + pub const fn new(f: F) -> Lazy<T, F> { + Lazy { cell: Once::new(), init: Cell::new(Some(f)) } } } -impl<T, F: FnOnce() -> T> SyncLazy<T, F> { +impl<T, F: FnOnce() -> T> Lazy<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. /// - /// # Example + /// # Examples + /// /// ``` - /// use std::lazy::SyncLazy; + /// #![feature(once_cell)] + /// + /// use std::lazy::Lazy; /// - /// let lazy = SyncLazy::new(|| 92); + /// let lazy = Lazy::new(|| 92); /// - /// assert_eq!(SyncLazy::force(&lazy), &92); + /// assert_eq!(Lazy::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` - pub fn force(this: &SyncLazy<T, F>) -> &T { + #[unstable(feature = "once_cell", issue = "68198")] + pub fn force(this: &Lazy<T, F>) -> &T { this.cell.get_or_init(|| match this.init.take() { Some(f) => f(), - None => panic!("SyncLazy instance has previously been poisoned"), + None => panic!("Lazy instance has previously been poisoned"), }) } } -impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> { +#[unstable(feature = "once_cell", issue = "68198")] +impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { type Target = T; fn deref(&self) -> &T { - SyncLazy::force(self) + Lazy::force(self) } } -impl<T: Default> Default for SyncLazy<T> { +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Default> Default for Lazy<T> { /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> SyncLazy<T> { - SyncLazy::new(T::default) + fn default() -> Lazy<T> { + Lazy::new(T::default) } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0720aa769238e..06a581c27da62 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -276,6 +276,7 @@ #![feature(link_args)] #![feature(linkage)] #![feature(log_syntax)] +#![feature(maybe_uninit_extra)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] #![feature(needs_panic_runtime)] @@ -466,10 +467,7 @@ pub mod process; pub mod sync; pub mod time; -#[unstable( - feature = "std_lazy", - issue = "99", -)] +#[unstable(feature = "once_cell", issue = "68198")] pub mod lazy; #[stable(feature = "futures_api", since = "1.36.0")] diff --git a/src/stdsimd b/src/stdsimd new file mode 160000 index 0000000000000..4bf456c35e85f --- /dev/null +++ b/src/stdsimd @@ -0,0 +1 @@ +Subproject commit 4bf456c35e85fcca5cf95008401af8ab25abf850 From 91c9d1c21ea2a8db64cbc026c5b315f2f7027751 Mon Sep 17 00:00:00 2001 From: Ashley Mannix <ashleymannix@live.com.au> Date: Wed, 15 Jan 2020 07:24:55 +1000 Subject: [PATCH 3/6] correctly impl Drop for lazy::Once --- src/libstd/lazy.rs | 96 ++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index 11b5e5d40a10d..f8c8f86cf0b05 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -169,22 +169,16 @@ use crate::{ cell::{Cell, UnsafeCell}, fmt, marker::PhantomData, - mem::MaybeUninit, - ops::Deref, + mem::{self, MaybeUninit}, + ops::{Deref, Drop}, panic::{RefUnwindSafe, UnwindSafe}, sync::atomic::{AtomicBool, AtomicUsize, Ordering}, thread::{self, Thread}, }; -/// A thread-safe cell which can be written to only once. +/// A synchronization primitive which can be written to only once. /// -/// `OnceCell` provides `&` references to the contents without RAII guards. -/// -/// Reading a non-`None` value out of `OnceCell` establishes a -/// happens-before relationship with a corresponding write. For example, if -/// thread A initializes the cell with `get_or_init(f)`, and thread B -/// subsequently reads the result of this call, B also observes all the side -/// effects of `f`. +/// This type is a thread-safe `OnceCell`. /// /// # Examples /// @@ -193,7 +187,7 @@ use crate::{ /// /// use std::lazy::Once; /// -/// static CELL: OnceCell<String> = OnceCell::new(); +/// static CELL: Once<String> = Once::new(); /// assert!(CELL.get().is_none()); /// /// std::thread::spawn(|| { @@ -218,7 +212,7 @@ pub struct Once<T> { } // Why do we need `T: Send`? -// Thread A creates a `OnceCell` and shares it with +// Thread A creates a `Once` and shares it with // scoped thread B, which fills the cell, which is // then destroyed by A. That is, destructor observes // a sent value. @@ -320,32 +314,6 @@ impl<T> Once<T> { } } - /// Get the reference to the underlying value, without checking if the - /// cell is initialized. - /// - /// Safety: - /// - /// Caller must ensure that the cell is in initialized state, and that - /// the contents are acquired by (synchronized to) this thread. - #[unstable(feature = "once_cell", issue = "68198")] - pub unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.is_initialized()); - (&*self.value.get()).get_ref() - } - - /// Get the reference to the underlying value, without checking if the - /// cell is initialized. - /// - /// Safety: - /// - /// Caller must ensure that the cell is in initialized state, and that - /// the contents are acquired by (synchronized to) this thread. - #[unstable(feature = "once_cell", issue = "68198")] - pub unsafe fn get_unchecked_mut(&mut self) -> &mut T { - debug_assert!(self.is_initialized()); - (&mut *self.value.get()).get_mut() - } - /// Sets the contents of this cell to `value`. /// /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was @@ -483,15 +451,32 @@ impl<T> Once<T> { /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` #[unstable(feature = "once_cell", issue = "68198")] - pub fn into_inner(self) -> Option<T> { - // Because `into_inner` takes `self` by value, the compiler statically verifies - // that it is not currently borrowed. So it is safe to move out `Option<T>`. + pub fn into_inner(mut self) -> Option<T> { + // Safety: Safe because we immediately free `self` without dropping + let inner = unsafe { self.take_inner() }; + + // Don't drop this `Once`. We just moved out one of the fields, but didn't set + // the state to uninitialized. + mem::ManuallyDrop::new(self); + inner + } + + /// Takes the wrapped value out of a `Once`. + /// Afterwards the cell is no longer initialized. + /// + /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell + /// are valid. Only used by `into_inner` and `drop`. + unsafe fn take_inner(&mut self) -> Option<T> { + // The mutable reference guarantees there are no other threads that can observe us + // taking out the wrapped value. + // Right after this function `self` is supposed to be freed, so it makes little sense + // to atomically set the state to uninitialized. if self.is_initialized() { - // Safe b/c called initialize - return Some(unsafe { self.value.into_inner().assume_init() }); + let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit())); + Some(value.into_inner().assume_init()) + } else { + None } - - None } /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). @@ -530,6 +515,25 @@ impl<T> Once<T> { }); res } + + /// Safety: The value must be initialized + unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + (&*self.value.get()).get_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()).get_mut() + } +} + +impl<T> Drop for Once<T> { + fn drop(&mut self) { + // Safety: The cell is being dropped, so it can't be accessed again + unsafe { self.take_inner() }; + } } // FIXME: The following code is copied from `sync::Once`. @@ -636,7 +640,7 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { /// A value which is initialized on the first access. /// -/// This type is thread-safe and can be used in statics: +/// This type is a thread-safe `LazyCell`, and can be used in statics. /// /// # Examples /// From 0f7f3de14d9a399b7da2e78c0c6758a0aad7cbd2 Mon Sep 17 00:00:00 2001 From: Ashley Mannix <ashleymannix@live.com.au> Date: Wed, 15 Jan 2020 16:37:51 +1000 Subject: [PATCH 4/6] move unsync OnceCell and Lazy into lazy module --- src/libcore/cell.rs | 351 ------------------------------------------- src/libcore/lazy.rs | 352 ++++++++++++++++++++++++++++++++++++++++++++ src/libcore/lib.rs | 2 + src/libstd/lazy.rs | 277 ++++++++-------------------------- src/libstd/lib.rs | 1 + 5 files changed, 413 insertions(+), 570 deletions(-) create mode 100644 src/libcore/lazy.rs diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 45b5c5b7fd77e..feda37e329278 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -44,12 +44,6 @@ //! to borrow a value that is already mutably borrowed; when this happens it results in thread //! panic. //! -//! `OnceCell<T>` allows one to access a value by also providing an initialization function for it. -//! If the `OnceCell<T>` already contains an initialized value then it is returned, otherwise the -//! initialization function is run and the result is stored in the cell. -//! `LazyCell<T, F>` is similar to `OnceCell<T>`, but keeps its initialization function as part of -//! the type, so it doesn't need to be provided whenever the cell is accessed. -//! //! # When to choose interior mutability //! //! The more common inherited mutability, where one must have unique access to mutate a value, is @@ -1421,351 +1415,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> { } } -/// A cell which can be written to only once. -/// -/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value. -/// Unlike `Cell`, a `OnceCell` doesn't require `T: Copy` to access its value. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::cell::OnceCell; -/// -/// let cell = OnceCell::new(); -/// assert!(cell.get().is_none()); -/// -/// let value: &String = cell.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// assert!(cell.get().is_some()); -/// ``` -#[unstable(feature = "once_cell", issue = "68198")] -pub struct OnceCell<T> { - // Invariant: written to at most once. - inner: UnsafeCell<Option<T>>, -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T> Default for OnceCell<T> { - fn default() -> Self { - Self::new() - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T: fmt::Debug> fmt::Debug for OnceCell<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("OnceCell").field(v).finish(), - None => f.write_str("OnceCell(Uninit)"), - } - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T: Clone> Clone for OnceCell<T> { - fn clone(&self) -> OnceCell<T> { - let res = OnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - res - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T: PartialEq> PartialEq for OnceCell<T> { - fn eq(&self, other: &Self) -> bool { - self.get() == other.get() - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T: Eq> Eq for OnceCell<T> {} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T> From<T> for OnceCell<T> { - fn from(value: T) -> Self { - OnceCell { inner: UnsafeCell::new(Some(value)) } - } -} - -impl<T> OnceCell<T> { - /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "68198")] - pub const fn new() -> OnceCell<T> { - OnceCell { inner: UnsafeCell::new(None) } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "68198")] - pub fn get(&self) -> Option<&T> { - // Safe due to `inner`'s invariant - unsafe { &*self.inner.get() }.as_ref() - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "68198")] - pub fn get_mut(&mut self) -> Option<&mut T> { - // Safe because we have unique access - unsafe { &mut *self.inner.get() }.as_mut() - } - - /// Sets the contents of the cell to `value`. - /// - /// # Errors - /// - /// This method returns `Ok(())` if the cell was empty and `Err(value)` if - /// it was full. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::cell::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert!(cell.get().is_none()); - /// - /// assert_eq!(cell.set(92), Ok(())); - /// assert_eq!(cell.set(62), Err(62)); - /// - /// assert!(cell.get().is_some()); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn set(&self, value: T) -> Result<(), T> { - let slot = unsafe { &*self.inner.get() }; - if slot.is_some() { - return Err(value); - } - let slot = unsafe { &mut *self.inner.get() }; - // This is the only place where we set the slot, no races - // due to reentrancy/concurrency are possible, and we've - // checked that slot is currently `None`, so this write - // maintains the `inner`'s invariant. - *slot = Some(value); - Ok(()) - } - - /// Gets the contents of the cell, initializing it with `f` - /// if the cell was empty. - /// - /// # 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`. Doing - /// so results in a panic. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::cell::OnceCell; - /// - /// let cell = OnceCell::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 = "68198")] - 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`. Doing - /// so results in a panic. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::cell::OnceCell; - /// - /// let cell = OnceCell::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 = "68198")] - pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result<T, E>, - { - if let Some(val) = self.get() { - return Ok(val); - } - let val = f()?; - // Note that *some* forms of reentrant initialization might lead to - // UB (see `reentrant_init` test). I believe that just removing this - // `assert`, while keeping `set/get` would be sound, but it seems - // better to panic, rather than to silently use an old value. - assert!(self.set(val).is_ok(), "reentrant init"); - Ok(self.get().unwrap()) - } - - /// Consumes the cell, returning the wrapped value. - /// - /// Returns `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::cell::OnceCell; - /// - /// let cell: OnceCell<String> = OnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = OnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn into_inner(self) -> Option<T> { - // Because `into_inner` takes `self` by value, the compiler statically verifies - // that it is not currently borrowed. So it is safe to move out `Option<T>`. - self.inner.into_inner() - } -} - -/// A value which is initialized on the first access. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::cell::LazyCell; -/// -/// let lazy: LazyCell<i32> = LazyCell::new(|| { -/// println!("initializing"); -/// 92 -/// }); -/// println!("ready"); -/// println!("{}", *lazy); -/// println!("{}", *lazy); -/// -/// // Prints: -/// // ready -/// // initializing -/// // 92 -/// // 92 -/// ``` -#[unstable(feature = "once_cell", issue = "68198")] -pub struct LazyCell<T, F = fn() -> T> { - cell: OnceCell<T>, - init: Cell<Option<F>>, -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for LazyCell<T, F> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("LazyCell").field("cell", &self.cell).field("init", &"..").finish() - } -} - -impl<T, F> LazyCell<T, F> { - /// Creates a new lazy value with the given initializing function. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// # fn main() { - /// use std::cell::LazyCell; - /// - /// let hello = "Hello, World!".to_string(); - /// - /// let lazy = LazyCell::new(|| hello.to_uppercase()); - /// - /// assert_eq!(&*lazy, "HELLO, WORLD!"); - /// # } - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub const fn new(init: F) -> LazyCell<T, F> { - LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) } - } -} - -impl<T, F: FnOnce() -> T> LazyCell<T, F> { - /// Forces the evaluation of this lazy value and returns a reference to - /// the result. - /// - /// This is equivalent to the `Deref` impl, but is explicit. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::cell::LazyCell; - /// - /// let lazy = LazyCell::new(|| 92); - /// - /// assert_eq!(LazyCell::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn force(this: &LazyCell<T, F>) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("`LazyCell` instance has previously been poisoned"), - }) - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> { - type Target = T; - fn deref(&self) -> &T { - LazyCell::force(self) - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl<T: Default> Default for LazyCell<T> { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> LazyCell<T> { - LazyCell::new(T::default) - } -} - /// The core primitive for interior mutability in Rust. /// /// `UnsafeCell<T>` is a type that wraps some `T` and indicates unsafe interior operations on the diff --git a/src/libcore/lazy.rs b/src/libcore/lazy.rs new file mode 100644 index 0000000000000..eb74faeaf11d3 --- /dev/null +++ b/src/libcore/lazy.rs @@ -0,0 +1,352 @@ +//! Lazy values and one-time initialization of static data. + +use crate::cell::{Cell, UnsafeCell}; +use crate::fmt; +use crate::ops::Deref; + +/// A cell which can be written to only once. +/// +/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value. +/// Unlike `Cell`, a `OnceCell` doesn't require `T: Copy` to access its value. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::lazy::OnceCell; +/// +/// let cell = OnceCell::new(); +/// assert!(cell.get().is_none()); +/// +/// let value: &String = cell.get_or_init(|| { +/// "Hello, World!".to_string() +/// }); +/// assert_eq!(value, "Hello, World!"); +/// assert!(cell.get().is_some()); +/// ``` +#[unstable(feature = "once_cell", issue = "68198")] +pub struct OnceCell<T> { + // Invariant: written to at most once. + inner: UnsafeCell<Option<T>>, +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T> Default for OnceCell<T> { + fn default() -> Self { + Self::new() + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: fmt::Debug> fmt::Debug for OnceCell<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("OnceCell").field(v).finish(), + None => f.write_str("OnceCell(Uninit)"), + } + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Clone> Clone for OnceCell<T> { + fn clone(&self) -> OnceCell<T> { + let res = OnceCell::new(); + if let Some(value) = self.get() { + match res.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + res + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: PartialEq> PartialEq for OnceCell<T> { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Eq> Eq for OnceCell<T> {} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T> From<T> for OnceCell<T> { + fn from(value: T) -> Self { + OnceCell { inner: UnsafeCell::new(Some(value)) } + } +} + +impl<T> OnceCell<T> { + /// Creates a new empty cell. + #[unstable(feature = "once_cell", issue = "68198")] + pub const fn new() -> OnceCell<T> { + OnceCell { inner: UnsafeCell::new(None) } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + #[unstable(feature = "once_cell", issue = "68198")] + pub fn get(&self) -> Option<&T> { + // Safety: Safe due to `inner`'s invariant + unsafe { &*self.inner.get() }.as_ref() + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + #[unstable(feature = "once_cell", issue = "68198")] + pub fn get_mut(&mut self) -> Option<&mut T> { + // Safety: Safe because we have unique access + unsafe { &mut *self.inner.get() }.as_mut() + } + + /// Sets the contents of the cell to `value`. + /// + /// # Errors + /// + /// This method returns `Ok(())` if the cell was empty and `Err(value)` if + /// it was full. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.set(92), Ok(())); + /// assert_eq!(cell.set(62), Err(62)); + /// + /// assert!(cell.get().is_some()); + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub fn set(&self, value: T) -> Result<(), T> { + // Safety: Safe because we cannot have overlapping mutable borrows + let slot = unsafe { &*self.inner.get() }; + if slot.is_some() { + return Err(value); + } + + // Safety: This is the only place where we set the slot, no races + // due to reentrancy/concurrency are possible, and we've + // checked that slot is currently `None`, so this write + // maintains the `inner`'s invariant. + let slot = unsafe { &mut *self.inner.get() }; + *slot = Some(value); + Ok(()) + } + + /// Gets the contents of the cell, initializing it with `f` + /// if the cell was empty. + /// + /// # 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`. Doing + /// so results in a panic. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::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 = "68198")] + 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`. Doing + /// so results in a panic. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::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 = "68198")] + pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + if let Some(val) = self.get() { + return Ok(val); + } + let val = f()?; + // Note that *some* forms of reentrant initialization might lead to + // UB (see `reentrant_init` test). I believe that just removing this + // `assert`, while keeping `set/get` would be sound, but it seems + // better to panic, rather than to silently use an old value. + assert!(self.set(val).is_ok(), "reentrant init"); + Ok(self.get().unwrap()) + } + + /// Consumes the cell, returning the wrapped value. + /// + /// Returns `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::OnceCell; + /// + /// let cell: OnceCell<String> = OnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub fn into_inner(self) -> Option<T> { + // Because `into_inner` takes `self` by value, the compiler statically verifies + // that it is not currently borrowed. So it is safe to move out `Option<T>`. + self.inner.into_inner() + } +} + +/// A value which is initialized on the first access. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::lazy::Lazy; +/// +/// let lazy: Lazy<i32> = Lazy::new(|| { +/// println!("initializing"); +/// 92 +/// }); +/// println!("ready"); +/// println!("{}", *lazy); +/// println!("{}", *lazy); +/// +/// // Prints: +/// // ready +/// // initializing +/// // 92 +/// // 92 +/// ``` +#[unstable(feature = "once_cell", issue = "68198")] +pub struct Lazy<T, F = fn() -> T> { + cell: OnceCell<T>, + init: Cell<Option<F>>, +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for Lazy<T, F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + } +} + +impl<T, F> Lazy<T, F> { + /// Creates a new lazy value with the given initializing function. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// # fn main() { + /// use std::lazy::Lazy; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = Lazy::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// # } + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub const fn new(init: F) -> Lazy<T, F> { + Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } + } +} + +impl<T, F: FnOnce() -> T> Lazy<T, F> { + /// Forces the evaluation of this lazy value and returns a reference to + /// the result. + /// + /// This is equivalent to the `Deref` impl, but is explicit. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::Lazy; + /// + /// let lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + #[unstable(feature = "once_cell", issue = "68198")] + pub fn force(this: &Lazy<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 = "68198")] +impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { + type Target = T; + fn deref(&self) -> &T { + Lazy::force(self) + } +} + +#[unstable(feature = "once_cell", issue = "68198")] +impl<T: Default> Default for Lazy<T> { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> Lazy<T> { + Lazy::new(T::default) + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ce7ddffd82584..4ea9f30845960 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -225,6 +225,8 @@ pub mod char; pub mod ffi; #[cfg(not(test))] // See #65860 pub mod iter; +#[unstable(feature = "once_cell", issue = "68198")] +pub mod lazy; pub mod option; pub mod panic; pub mod panicking; diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index f8c8f86cf0b05..4afd76107c1bd 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -1,169 +1,4 @@ //! Lazy values and one-time initialization of static data. -//! -//! `lazy` provides two new cell-like types, `Once` and `Lazy`. `Once` -//! might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access -//! to the stored contents. -//! -//! Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. -//! Because of the single assignment restriction `get` can return an `&T` instead of `Ref<T>` -//! or `MutexGuard<T>`. -//! -//! # Patterns -//! -//! `Once` can be useful for a variety of patterns. -//! -//! ## Safe Initialization of global data -//! -//! ```rust -//! #![feature(once_cell)] -//! -//! use std::{env, io}; -//! use std::lazy::Once; -//! -//! #[derive(Debug)] -//! pub struct Logger { -//! // ... -//! } -//! static INSTANCE: Once<Logger> = Once::new(); -//! -//! impl Logger { -//! pub fn global() -> &'static Logger { -//! INSTANCE.get().expect("logger is not initialized") -//! } -//! -//! fn from_cli(args: env::Args) -> Result<Logger, std::io::Error> { -//! // ... -//! # Ok(Logger {}) -//! } -//! } -//! -//! fn main() { -//! let logger = Logger::from_cli(env::args()).unwrap(); -//! INSTANCE.set(logger).unwrap(); -//! // use `Logger::global()` from now on -//! } -//! ``` -//! -//! ## Lazy initialized global data -//! -//! This is essentially `lazy_static!` macro, but without a macro. -//! -//! ```rust -//! #![feature(once_cell)] -//! -//! use std::{sync::Mutex, collections::HashMap}; -//! use lazy::Once; -//! -//! fn global_data() -> &'static Mutex<HashMap<i32, String>> { -//! static INSTANCE: Once<Mutex<HashMap<i32, String>>> = Once::new(); -//! INSTANCE.get_or_init(|| { -//! let mut m = HashMap::new(); -//! m.insert(13, "Spica".to_string()); -//! m.insert(74, "Hoyten".to_string()); -//! Mutex::new(m) -//! }) -//! } -//! ``` -//! -//! There is also `Lazy` to streamline this pattern: -//! -//! ```rust -//! #![feature(once_cell)] -//! -//! use std::{sync::Mutex, collections::HashMap}; -//! use lazy::Lazy; -//! -//! static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| { -//! let mut m = HashMap::new(); -//! m.insert(13, "Spica".to_string()); -//! m.insert(74, "Hoyten".to_string()); -//! Mutex::new(m) -//! }); -//! -//! fn main() { -//! println!("{:?}", GLOBAL_DATA.lock().unwrap()); -//! } -//! ``` -//! -//! ## General purpose lazy evaluation -//! -//! `Lazy` also works with local variables. -//! -//! ```rust -//! #![feature(once_cell)] -//! -//! use std::lazy::Lazy; -//! -//! fn main() { -//! let ctx = vec![1, 2, 3]; -//! let thunk = Lazy::new(|| { -//! ctx.iter().sum::<i32>() -//! }); -//! assert_eq!(*thunk, 6); -//! } -//! ``` -//! -//! If you need a lazy field in a struct, you probably should use `Once` -//! directly, because that will allow you to access `self` during initialization. -//! -//! ```rust -//! #![feature(once_cell)] -//! -//! use std::{fs, path::PathBuf}; -//! -//! use std::lazy::Once; -//! -//! struct Ctx { -//! config_path: PathBuf, -//! config: Once<String>, -//! } -//! -//! impl Ctx { -//! pub fn get_config(&self) -> Result<&str, std::io::Error> { -//! let cfg = self.config.get_or_try_init(|| { -//! fs::read_to_string(&self.config_path) -//! })?; -//! Ok(cfg.as_str()) -//! } -//! } -//! ``` -//! -//! ## Building block -//! -//! Naturally, it is possible to build other abstractions on top of `Once`. -//! For example, this is a `regex!` macro which takes a string literal and returns an -//! *expression* that evaluates to a `&'static Regex`: -//! -//! ``` -//! macro_rules! regex { -//! ($re:literal $(,)?) => {{ -//! static RE: std::lazy::Once<regex::Regex> = std::lazy::Once::new(); -//! RE.get_or_init(|| regex::Regex::new($re).unwrap()) -//! }}; -//! } -//! ``` -//! -//! This macro can be useful to avoid "compile regex on every loop iteration" problem. -//! -//! # Comparison with other interior mutability types -//! -//! |`!Sync` types | Access Mode | Drawbacks | -//! |----------------------|------------------------|-----------------------------------------------| -//! |`Cell<T>` | `T` | requires `T: Copy` for `get` | -//! |`RefCell<T>` | `RefMut<T>` / `Ref<T>` | may panic at runtime | -//! |`OnceCell<T>` | `&T` | assignable only once | -//! |`LazyCell<T, F>` | `&T` | assignable only once | -//! -//! |`Sync` types | Access Mode | Drawbacks | -//! |----------------------|------------------------|-----------------------------------------------| -//! |`AtomicT` | `T` | works only with certain `Copy` types | -//! |`Mutex<T>` | `MutexGuard<T>` | may deadlock at runtime, may block the thread | -//! |`Once<T>` | `&T` | assignable only once, may block the thread | -//! |`Lazy<T, F>` | `&T` | assignable only once, may block the thread | -//! -//! Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls -//! itself. However, because the assignment can happen only once, such cases should be more rare than -//! equivalents with `RefCell` and `Mutex`. use crate::{ cell::{Cell, UnsafeCell}, @@ -176,6 +11,10 @@ use crate::{ thread::{self, Thread}, }; +#[doc(inline)] +#[unstable(feature = "once_cell", issue = "68198")] +pub use core::lazy::*; + /// A synchronization primitive which can be written to only once. /// /// This type is a thread-safe `OnceCell`. @@ -185,9 +24,9 @@ use crate::{ /// ``` /// #![feature(once_cell)] /// -/// use std::lazy::Once; +/// use std::lazy::SyncOnceCell; /// -/// static CELL: Once<String> = Once::new(); +/// static CELL: SyncOnceCell<String> = SyncOnceCell::new(); /// assert!(CELL.get().is_none()); /// /// std::thread::spawn(|| { @@ -202,7 +41,7 @@ use crate::{ /// assert_eq!(value.unwrap().as_str(), "Hello, World!"); /// ``` #[unstable(feature = "once_cell", issue = "68198")] -pub struct Once<T> { +pub struct SyncOnceCell<T> { // This `state` word is actually an encoded version of just a pointer to a // `Waiter`, so we add the `PhantomData` appropriately. state_and_queue: AtomicUsize, @@ -217,24 +56,24 @@ pub struct Once<T> { // then destroyed by A. That is, destructor observes // a sent value. #[unstable(feature = "once_cell", issue = "68198")] -unsafe impl<T: Sync + Send> Sync for Once<T> {} +unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {} #[unstable(feature = "once_cell", issue = "68198")] -unsafe impl<T: Send> Send for Once<T> {} +unsafe impl<T: Send> Send for SyncOnceCell<T> {} #[unstable(feature = "once_cell", issue = "68198")] -impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for Once<T> {} +impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {} #[unstable(feature = "once_cell", issue = "68198")] -impl<T: UnwindSafe> UnwindSafe for Once<T> {} +impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {} #[unstable(feature = "once_cell", issue = "68198")] -impl<T> Default for Once<T> { - fn default() -> Once<T> { - Once::new() +impl<T> Default for SyncOnceCell<T> { + fn default() -> SyncOnceCell<T> { + SyncOnceCell::new() } } #[unstable(feature = "once_cell", issue = "68198")] -impl<T: fmt::Debug> fmt::Debug for Once<T> { +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(), @@ -244,9 +83,9 @@ impl<T: fmt::Debug> fmt::Debug for Once<T> { } #[unstable(feature = "once_cell", issue = "68198")] -impl<T: Clone> Clone for Once<T> { - fn clone(&self) -> Once<T> { - let res = Once::new(); +impl<T: Clone> Clone for SyncOnceCell<T> { + fn clone(&self) -> SyncOnceCell<T> { + let res = SyncOnceCell::new(); if let Some(value) = self.get() { match res.set(value.clone()) { Ok(()) => (), @@ -258,7 +97,7 @@ impl<T: Clone> Clone for Once<T> { } #[unstable(feature = "once_cell", issue = "68198")] -impl<T> From<T> for Once<T> { +impl<T> From<T> for SyncOnceCell<T> { fn from(value: T) -> Self { let cell = Self::new(); cell.get_or_init(|| value); @@ -267,20 +106,20 @@ impl<T> From<T> for Once<T> { } #[unstable(feature = "once_cell", issue = "68198")] -impl<T: PartialEq> PartialEq for Once<T> { - fn eq(&self, other: &Once<T>) -> bool { +impl<T: PartialEq> PartialEq for SyncOnceCell<T> { + fn eq(&self, other: &SyncOnceCell<T>) -> bool { self.get() == other.get() } } #[unstable(feature = "once_cell", issue = "68198")] -impl<T: Eq> Eq for Once<T> {} +impl<T: Eq> Eq for SyncOnceCell<T> {} -impl<T> Once<T> { +impl<T> SyncOnceCell<T> { /// Creates a new empty cell. #[unstable(feature = "once_cell", issue = "68198")] - pub const fn new() -> Once<T> { - Once { + pub const fn new() -> SyncOnceCell<T> { + SyncOnceCell { state_and_queue: AtomicUsize::new(INCOMPLETE), _marker: PhantomData, value: UnsafeCell::new(MaybeUninit::uninit()), @@ -324,9 +163,9 @@ impl<T> Once<T> { /// ``` /// #![feature(once_cell)] /// - /// use std::lazy::Once; + /// use std::lazy::SyncOnceCell; /// - /// static CELL: Once<i32> = Once::new(); + /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new(); /// /// fn main() { /// assert!(CELL.get().is_none()); @@ -370,9 +209,9 @@ impl<T> Once<T> { /// ``` /// #![feature(once_cell)] /// - /// use std::lazy::Once; + /// use std::lazy::SyncOnceCell; /// - /// let cell = Once::new(); + /// let cell = SyncOnceCell::new(); /// let value = cell.get_or_init(|| 92); /// assert_eq!(value, &92); /// let value = cell.get_or_init(|| unreachable!()); @@ -406,9 +245,9 @@ impl<T> Once<T> { /// ``` /// #![feature(once_cell)] /// - /// use std::lazy::Once; + /// use std::lazy::SyncOnceCell; /// - /// let cell = Once::new(); + /// 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, ()> { @@ -441,12 +280,12 @@ impl<T> Once<T> { /// ``` /// #![feature(once_cell)] /// - /// use std::lazy::Once; + /// use std::lazy::SyncOnceCell; /// - /// let cell: Once<String> = Once::new(); + /// let cell: SyncOnceCell<String> = SyncOnceCell::new(); /// assert_eq!(cell.into_inner(), None); /// - /// let cell = Once::new(); + /// let cell = SyncOnceCell::new(); /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` @@ -529,7 +368,7 @@ impl<T> Once<T> { } } -impl<T> Drop for Once<T> { +impl<T> Drop for SyncOnceCell<T> { fn drop(&mut self) { // Safety: The cell is being dropped, so it can't be accessed again unsafe { self.take_inner() }; @@ -539,7 +378,7 @@ impl<T> Drop for Once<T> { // FIXME: The following code is copied from `sync::Once`. // This should be uncopypasted once we decide the right way to handle panics. // Do we want to effectively move the `Once` synchronization here and make `Once` -// a newtype: `pub struct Once(lazy::Once<()>)`? +// a newtype: `pub struct Once(lazy::SyncOnceCell<()>)`? const INCOMPLETE: usize = 0x0; const RUNNING: usize = 0x1; const COMPLETE: usize = 0x2; @@ -640,7 +479,7 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { /// A value which is initialized on the first access. /// -/// This type is a thread-safe `LazyCell`, and can be used in statics. +/// This type is a thread-safe `Lazy`, and can be used in statics. /// /// # Examples /// @@ -649,9 +488,9 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { /// /// use std::collections::HashMap; /// -/// use std::lazy::Lazy; +/// use std::lazy::SyncLazy; /// -/// static HASHMAP: Lazy<HashMap<i32, String>> = Lazy::new(|| { +/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| { /// println!("initializing"); /// let mut m = HashMap::new(); /// m.insert(13, "Spica".to_string()); @@ -674,40 +513,40 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { /// } /// ``` #[unstable(feature = "once_cell", issue = "68198")] -pub struct Lazy<T, F = fn() -> T> { - cell: Once<T>, +pub struct SyncLazy<T, F = fn() -> T> { + cell: SyncOnceCell<T>, init: Cell<Option<F>>, } #[unstable(feature = "once_cell", issue = "68198")] -impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for Lazy<T, F> { +impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for SyncLazy<T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() } } -// We never create a `&F` from a `&Lazy<T, F>` so it is fine +// 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 = "68198")] -unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {} +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 = "68198")] -impl<T, F: RefUnwindSafe> RefUnwindSafe for Lazy<T, F> where Once<T>: RefUnwindSafe {} +impl<T, F: RefUnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {} -impl<T, F> Lazy<T, F> { +impl<T, F> SyncLazy<T, F> { /// Creates a new lazy value with the given initializing /// function. #[unstable(feature = "once_cell", issue = "68198")] - pub const fn new(f: F) -> Lazy<T, F> { - Lazy { cell: Once::new(), init: Cell::new(Some(f)) } + pub const fn new(f: F) -> SyncLazy<T, F> { + SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } } } -impl<T, F: FnOnce() -> T> Lazy<T, 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. @@ -717,15 +556,15 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> { /// ``` /// #![feature(once_cell)] /// - /// use std::lazy::Lazy; + /// use std::lazy::SyncLazy; /// - /// let lazy = Lazy::new(|| 92); + /// let lazy = SyncLazy::new(|| 92); /// - /// assert_eq!(Lazy::force(&lazy), &92); + /// assert_eq!(SyncLazy::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` #[unstable(feature = "once_cell", issue = "68198")] - pub fn force(this: &Lazy<T, F>) -> &T { + 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"), @@ -734,17 +573,17 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> { } #[unstable(feature = "once_cell", issue = "68198")] -impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { +impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> { type Target = T; fn deref(&self) -> &T { - Lazy::force(self) + SyncLazy::force(self) } } #[unstable(feature = "once_cell", issue = "68198")] -impl<T: Default> Default for Lazy<T> { +impl<T: Default> Default for SyncLazy<T> { /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> Lazy<T> { - Lazy::new(T::default) + fn default() -> SyncLazy<T> { + SyncLazy::new(T::default) } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 06a581c27da62..a791d426c05cb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -282,6 +282,7 @@ #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] +#![feature(once_cell)] #![feature(optin_builtin_traits)] #![feature(panic_info_message)] #![feature(panic_internals)] From 2d2202c7eb4a52bf9e5c0f1b493df2ef4547178d Mon Sep 17 00:00:00 2001 From: Ashley Mannix <ashleymannix@live.com.au> Date: Mon, 3 Feb 2020 18:17:17 +1000 Subject: [PATCH 5/6] Update src/libcore/lazy.rs Co-Authored-By: Paul Dicker <pitdicker@users.noreply.github.com> --- src/libcore/lazy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/lazy.rs b/src/libcore/lazy.rs index eb74faeaf11d3..bd6051d3c8962 100644 --- a/src/libcore/lazy.rs +++ b/src/libcore/lazy.rs @@ -7,7 +7,7 @@ use crate::ops::Deref; /// A cell which can be written to only once. /// /// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value. -/// Unlike `Cell`, a `OnceCell` doesn't require `T: Copy` to access its value. +/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it. /// /// # Examples /// From bde13db35d48179f3418eb91d06cbf4317be9e48 Mon Sep 17 00:00:00 2001 From: Ashley Mannix <ashleymannix@live.com.au> Date: Mon, 3 Feb 2020 20:22:16 +1000 Subject: [PATCH 6/6] port once_cell tests --- src/libcore/tests/lazy.rs | 124 ++++++++++++++ src/libcore/tests/lib.rs | 2 + src/libstd/lazy.rs | 338 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 464 insertions(+) create mode 100644 src/libcore/tests/lazy.rs diff --git a/src/libcore/tests/lazy.rs b/src/libcore/tests/lazy.rs new file mode 100644 index 0000000000000..1c0bddb9aef62 --- /dev/null +++ b/src/libcore/tests/lazy.rs @@ -0,0 +1,124 @@ +use core::{ + cell::Cell, + lazy::{Lazy, OnceCell}, + sync::atomic::{AtomicUsize, Ordering::SeqCst}, +}; + +#[test] +fn once_cell() { + let c = OnceCell::new(); + assert!(c.get().is_none()); + c.get_or_init(|| 92); + assert_eq!(c.get(), Some(&92)); + + c.get_or_init(|| panic!("Kabom!")); + assert_eq!(c.get(), Some(&92)); +} + +#[test] +fn once_cell_get_mut() { + let mut c = OnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); +} + +#[test] +fn once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = OnceCell::new(); + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + assert_eq!(DROP_CNT.load(SeqCst), 1); +} + +#[test] +fn unsync_once_cell_drop_empty() { + let x = OnceCell::<&'static str>::new(); + drop(x); +} + +#[test] +fn clone() { + let s = OnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello").unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(|c| *c), Some("hello")); +} + +#[test] +fn from_impl() { + assert_eq!(OnceCell::from("value").get(), Some(&"value")); + assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); +} + +#[test] +fn partialeq_impl() { + assert!(OnceCell::from("value") == OnceCell::from("value")); + assert!(OnceCell::from("foo") != OnceCell::from("bar")); + + assert!(OnceCell::<&'static str>::new() == OnceCell::new()); + assert!(OnceCell::<&'static str>::new() != OnceCell::from("value")); +} + +#[test] +fn into_inner() { + let cell: OnceCell<&'static str> = OnceCell::new(); + assert_eq!(cell.into_inner(), None); + let cell = OnceCell::new(); + cell.set("hello").unwrap(); + assert_eq!(cell.into_inner(), Some("hello")); +} + +#[test] +fn lazy_new() { + let called = Cell::new(0); + let x = Lazy::new(|| { + called.set(called.get() + 1); + 92 + }); + + assert_eq!(called.get(), 0); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.get(), 1); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.get(), 1); +} + +#[test] +fn aliasing_in_get() { + let x = OnceCell::new(); + x.set(42).unwrap(); + let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+ + let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>` | + println!("{}", at_x); // <------- up until here ---------------------------+ +} + +#[test] +#[should_panic(expected = "reentrant init")] +fn reentrant_init() { + let x: OnceCell<Box<i32>> = OnceCell::new(); + let dangling_ref: Cell<Option<&i32>> = Cell::new(None); + x.get_or_init(|| { + let r = x.get_or_init(|| Box::new(92)); + dangling_ref.set(Some(r)); + Box::new(62) + }); + eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 8fd19ef67fccf..4a108ae0f1225 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(try_find)] #![feature(is_sorted)] #![feature(iter_once_with)] +#![feature(once_cell)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] @@ -59,6 +60,7 @@ mod fmt; mod hash; mod intrinsics; mod iter; +mod lazy; mod manually_drop; mod mem; mod nonzero; diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index 4afd76107c1bd..be658727f2164 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -587,3 +587,341 @@ impl<T: Default> Default for SyncLazy<T> { SyncLazy::new(T::default) } } + +#[cfg(test)] +mod tests { + use crate::{ + lazy::{Lazy, SyncLazy, SyncOnceCell}, + panic, + sync::{ + atomic::{AtomicUsize, Ordering::SeqCst}, + mpsc::channel, + Mutex, + }, + }; + + #[test] + fn lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: Lazy<Mutex<Foo>> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + fn lazy_poisoning() { + let x: Lazy<String> = Lazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } + } + + // miri doesn't support threads + #[cfg(not(miri))] + fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { + crate::thread::spawn(f).join().unwrap() + } + + #[cfg(not(miri))] + fn spawn(f: impl FnOnce() + Send + 'static) { + let _ = crate::thread::spawn(f); + } + + // "stub threads" for Miri + #[cfg(miri)] + fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { + f(()) + } + + #[cfg(miri)] + fn spawn(f: impl FnOnce() + Send + 'static) { + f(()) + } + + #[test] + fn sync_once_cell() { + static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new(); + + assert!(ONCE_CELL.get().is_none()); + + spawn_and_wait(|| { + ONCE_CELL.get_or_init(|| 92); + assert_eq!(ONCE_CELL.get(), Some(&92)); + }); + + ONCE_CELL.get_or_init(|| panic!("Kabom!")); + assert_eq!(ONCE_CELL.get(), Some(&92)); + } + + #[test] + fn sync_once_cell_get_mut() { + let mut c = SyncOnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); + } + + #[test] + fn sync_once_cell_get_unchecked() { + let c = SyncOnceCell::new(); + c.set(92).unwrap(); + unsafe { + assert_eq!(c.get_unchecked(), &92); + } + } + + #[test] + fn sync_once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = SyncOnceCell::new(); + spawn_and_wait(move || { + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + }); + + assert_eq!(DROP_CNT.load(SeqCst), 1); + } + + #[test] + fn sync_once_cell_drop_empty() { + let x = SyncOnceCell::<String>::new(); + drop(x); + } + + #[test] + fn clone() { + let s = SyncOnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello".to_string()).unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(String::as_str), Some("hello")); + } + + #[test] + fn get_or_try_init() { + let cell: SyncOnceCell<String> = SyncOnceCell::new(); + assert!(cell.get().is_none()); + + let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); + assert!(res.is_err()); + assert!(cell.get().is_none()); + + assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + + assert_eq!( + cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), + Ok(&"hello".to_string()) + ); + assert_eq!(cell.get(), Some(&"hello".to_string())); + } + + #[test] + fn from_impl() { + assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); + assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); + } + + #[test] + fn partialeq_impl() { + assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); + assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); + + assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new()); + assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned())); + } + + #[test] + fn into_inner() { + 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())); + } + + #[test] + fn sync_lazy_new() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| { + CALLED.fetch_add(1, SeqCst); + 92 + }); + + assert_eq!(CALLED.load(SeqCst), 0); + + spawn_and_wait(|| { + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); + }); + + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + fn sync_lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: SyncLazy<Mutex<Foo>> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + #[cfg_attr(miri, ignore)] // leaks memory + fn static_sync_lazy() { + static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }); + + spawn_and_wait(|| { + assert_eq!(&*XS, &vec![1, 2, 3]); + }); + + assert_eq!(&*XS, &vec![1, 2, 3]); + } + + #[test] + #[cfg_attr(miri, ignore)] // leaks memory + fn static_sync_lazy_via_fn() { + fn xs() -> &'static Vec<i32> { + static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new(); + XS.get_or_init(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }) + } + assert_eq!(xs(), &vec![1, 2, 3]); + } + + #[test] + fn sync_lazy_poisoning() { + let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(|| x.len()); + assert!(res.is_err()); + } + } + + #[test] + fn is_sync_send() { + fn assert_traits<T: Send + Sync>() {} + assert_traits::<SyncOnceCell<String>>(); + assert_traits::<SyncLazy<String>>(); + } + + #[test] + fn eval_once_macro() { + macro_rules! eval_once { + (|| -> $ty:ty { + $($body:tt)* + }) => {{ + static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); + fn init() -> $ty { + $($body)* + } + ONCE_CELL.get_or_init(init) + }}; + } + + let fib: &'static Vec<i32> = eval_once! { + || -> Vec<i32> { + let mut res = vec![1, 1]; + for i in 0..10 { + let next = res[i] + res[i + 1]; + res.push(next); + } + res + } + }; + assert_eq!(fib[5], 8) + } + + #[test] + #[cfg_attr(miri, ignore)] // deadlocks without real threads + fn sync_once_cell_does_not_leak_partially_constructed_boxes() { + static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new(); + + let n_readers = 10; + let n_writers = 3; + const MSG: &str = "Hello, World"; + + let (tx, rx) = channel(); + + for _ in 0..n_readers { + let tx = tx.clone(); + spawn(move || { + loop { + if let Some(msg) = ONCE_CELL.get() { + tx.send(msg).unwrap(); + break; + } + } + }); + } + for _ in 0..n_writers { + spawn(move || { + let _ = ONCE_CELL.set(MSG.to_owned()); + }); + } + + for _ in 0..n_readers { + let msg = rx.recv().unwrap(); + assert_eq!(msg, MSG); + } + } +}