rust/library/core/src/cell/once.rs

403 lines
12 KiB
Rust

use crate::cell::UnsafeCell;
use crate::fmt;
use crate::mem;
/// A cell which can be written to only once.
///
/// This allows obtaining a shared `&T` reference to its inner value without copying or replacing
/// it (unlike [`Cell`]), and without runtime borrow checks (unlike [`RefCell`]). However,
/// only immutable references can be obtained unless one has a mutable reference to the cell
/// itself.
///
/// For a thread-safe version of this struct, see [`std::sync::OnceLock`].
///
/// [`RefCell`]: crate::cell::RefCell
/// [`Cell`]: crate::cell::Cell
/// [`std::sync::OnceLock`]: ../../std/sync/struct.OnceLock.html
///
/// # Examples
///
/// ```
/// 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());
/// ```
#[stable(feature = "once_cell", since = "1.70.0")]
pub struct OnceCell<T> {
// Invariant: written to at most once.
inner: UnsafeCell<Option<T>>,
}
impl<T> OnceCell<T> {
/// Creates a new empty cell.
#[inline]
#[must_use]
#[stable(feature = "once_cell", since = "1.70.0")]
#[rustc_const_stable(feature = "once_cell", since = "1.70.0")]
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.
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
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.
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
pub fn get_mut(&mut self) -> Option<&mut T> {
self.inner.get_mut().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
///
/// ```
/// 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());
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
pub fn set(&self, value: T) -> Result<(), T> {
match self.try_insert(value) {
Ok(_) => Ok(()),
Err((_, value)) => Err(value),
}
}
/// Sets the contents of the cell to `value` if the cell was empty, then
/// returns a reference to it.
///
/// # Errors
///
/// This method returns `Ok(&value)` if the cell was empty and
/// `Err(&current_value, value)` if it was full.
///
/// # Examples
///
/// ```
/// #![feature(once_cell_try_insert)]
///
/// use std::cell::OnceCell;
///
/// let cell = OnceCell::new();
/// assert!(cell.get().is_none());
///
/// assert_eq!(cell.try_insert(92), Ok(&92));
/// assert_eq!(cell.try_insert(62), Err((&92, 62)));
///
/// assert!(cell.get().is_some());
/// ```
#[inline]
#[unstable(feature = "once_cell_try_insert", issue = "116693")]
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
if let Some(old) = self.get() {
return Err((old, 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() };
Ok(slot.insert(value))
}
/// 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
///
/// ```
/// 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);
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
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 mutable reference of 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.
///
/// # Examples
///
/// ```
/// #![feature(once_cell_get_mut)]
///
/// use std::cell::OnceCell;
///
/// let mut cell = OnceCell::new();
/// let value = cell.get_mut_or_init(|| 92);
/// assert_eq!(*value, 92);
///
/// *value += 2;
/// assert_eq!(*value, 94);
///
/// let value = cell.get_mut_or_init(|| unreachable!());
/// assert_eq!(*value, 94);
/// ```
#[inline]
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T
where
F: FnOnce() -> T,
{
match self.get_mut_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_try)]
///
/// 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_try", issue = "109737")]
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);
}
self.try_init(f)
}
/// Gets the mutable reference of 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.
///
/// # Examples
///
/// ```
/// #![feature(once_cell_get_mut)]
///
/// use std::cell::OnceCell;
///
/// let mut cell: OnceCell<u32> = OnceCell::new();
///
/// // Failed initializers do not change the value
/// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err());
/// assert!(cell.get().is_none());
///
/// let value = cell.get_mut_or_try_init(|| "1234".parse());
/// assert_eq!(value, Ok(&mut 1234));
/// *value.unwrap() += 2;
/// assert_eq!(cell.get(), Some(&1236))
/// ```
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E>
where
F: FnOnce() -> Result<T, E>,
{
if self.get().is_none() {
self.try_init(f)?;
}
Ok(self.get_mut().unwrap())
}
// Avoid inlining the initialization closure into the common path that fetches
// the already initialized value
#[cold]
fn try_init<F, E>(&self, f: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>,
{
let val = f()?;
// Note that *some* forms of reentrant initialization might lead to
// UB (see `reentrant_init` test). I believe that just removing this
// `panic`, while keeping `try_insert` would be sound, but it seems
// better to panic, rather than to silently use an old value.
if let Ok(val) = self.try_insert(val) { Ok(val) } else { panic!("reentrant init") }
}
/// Consumes the cell, returning the wrapped value.
///
/// Returns `None` if the cell was empty.
///
/// # Examples
///
/// ```
/// 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()));
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
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()
}
/// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
///
/// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
///
/// Safety is guaranteed by requiring a mutable reference.
///
/// # Examples
///
/// ```
/// use std::cell::OnceCell;
///
/// let mut cell: OnceCell<String> = OnceCell::new();
/// assert_eq!(cell.take(), None);
///
/// let mut cell = OnceCell::new();
/// cell.set("hello".to_string()).unwrap();
/// assert_eq!(cell.take(), Some("hello".to_string()));
/// assert_eq!(cell.get(), None);
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
pub fn take(&mut self) -> Option<T> {
mem::take(self).into_inner()
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T> Default for OnceCell<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("OnceCell");
match self.get() {
Some(v) => d.field(v),
None => d.field(&format_args!("<uninit>")),
};
d.finish()
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: Clone> Clone for OnceCell<T> {
#[inline]
fn clone(&self) -> OnceCell<T> {
let res = OnceCell::new();
if let Some(value) = self.get() {
match res.set(value.clone()) {
Ok(()) => (),
Err(_) => unreachable!(),
}
}
res
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: PartialEq> PartialEq for OnceCell<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: Eq> Eq for OnceCell<T> {}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T> From<T> for OnceCell<T> {
/// Creates a new `OnceCell<T>` which already contains the given `value`.
#[inline]
fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) }
}
}
// Just like for `Cell<T>` this isn't needed, but results in nicer error messages.
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T> !Sync for OnceCell<T> {}