Rollup merge of #144872 - connortsui20:once-poison-docs, r=Amanieu
Document Poisoning in `LazyCell` and `LazyLock` Currently, there is no documentation of poisoning behavior in either `LazyCell` or `LazyLock`, even though both of them can be observed as poisoned by users. `LazyCell` [plagyround example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=9cf38b8dc56db100848f54085c2c697d) `LazyLock` [playground example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f1cd6f9fe16636e347ebb695a0ce30c0) # Open Questions - [x] Is it worth making the implementation of `LazyLock` more complicated to ensure that the the panic message is `"LazyLock instance has previously been poisoned"` instead of `"Once instance has previously been poisoned"`? See the `LazyLock` playground link above for more context. - [x] Does it make sense to move `LazyLock` into the `poison` module? It is certainly a poison-able type, but at the same time it is slightly different from the 4 other types currently in the `poison` module in that it is unrecoverable. I think this is more of a libs-api question. ``@rustbot`` label +T-libs-api Please let me know if these open questions deserve a separate issue / PR!
This commit is contained in:
commit
1724af9f1e
3 changed files with 118 additions and 5 deletions
|
|
@ -15,6 +15,22 @@ enum State<T, F> {
|
|||
///
|
||||
/// [`std::sync::LazyLock`]: ../../std/sync/struct.LazyLock.html
|
||||
///
|
||||
/// # Poisoning
|
||||
///
|
||||
/// If the initialization closure passed to [`LazyCell::new`] panics, the cell will be poisoned.
|
||||
/// Once the cell is poisoned, any threads that attempt to access this cell (via a dereference
|
||||
/// or via an explicit call to [`force()`]) will panic.
|
||||
///
|
||||
/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
|
||||
/// difference, however, is that poisoning in `LazyCell` is _unrecoverable_. All future accesses of
|
||||
/// the cell from other threads will panic, whereas a type in [`std::sync::poison`] like
|
||||
/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
|
||||
///
|
||||
/// [`force()`]: LazyCell::force
|
||||
/// [`std::sync::poison`]: ../../std/sync/poison/index.html
|
||||
/// [`std::sync::poison::Mutex`]: ../../std/sync/poison/struct.Mutex.html
|
||||
/// [`PoisonError::into_inner()`]: ../../std/sync/poison/struct.PoisonError.html#method.into_inner
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -64,6 +80,10 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
|
|||
///
|
||||
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the cell is poisoned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -93,6 +113,15 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
|
|||
///
|
||||
/// This is equivalent to the `Deref` impl, but is explicit.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
|
||||
/// accesses of the cell (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyCell::new
|
||||
/// [`force()`]: LazyCell::force
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -123,6 +152,15 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
|
|||
/// Forces the evaluation of this lazy value and returns a mutable reference to
|
||||
/// the result.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
|
||||
/// accesses of the cell (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyCell::new
|
||||
/// [`force()`]: LazyCell::force
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -219,7 +257,8 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
|
|||
}
|
||||
|
||||
impl<T, F> LazyCell<T, F> {
|
||||
/// Returns a mutable reference to the value if initialized, or `None` if not.
|
||||
/// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
|
||||
/// poisoned), returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -245,7 +284,8 @@ impl<T, F> LazyCell<T, F> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the value if initialized, or `None` if not.
|
||||
/// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
|
||||
/// returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -278,6 +318,15 @@ impl<T, F> LazyCell<T, F> {
|
|||
#[stable(feature = "lazy_cell", since = "1.80.0")]
|
||||
impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
|
||||
type Target = T;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
|
||||
/// accesses of the cell (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyCell::new
|
||||
/// [`force()`]: LazyCell::force
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
LazyCell::force(self)
|
||||
|
|
@ -286,6 +335,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
|
|||
|
||||
#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
|
||||
impl<T, F: FnOnce() -> T> DerefMut for LazyCell<T, F> {
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
|
||||
/// accesses of the cell (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyCell::new
|
||||
/// [`force()`]: LazyCell::force
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
LazyCell::force_mut(self)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,22 @@ union Data<T, F> {
|
|||
///
|
||||
/// [`LazyCell`]: crate::cell::LazyCell
|
||||
///
|
||||
/// # Poisoning
|
||||
///
|
||||
/// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned.
|
||||
/// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference
|
||||
/// or via an explicit call to [`force()`]) will panic.
|
||||
///
|
||||
/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
|
||||
/// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of
|
||||
/// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like
|
||||
/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
|
||||
///
|
||||
/// [`force()`]: LazyLock::force
|
||||
/// [`std::sync::poison`]: crate::sync::poison
|
||||
/// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex
|
||||
/// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Initialize static variables with `LazyLock`.
|
||||
|
|
@ -102,6 +118,10 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
|
|||
///
|
||||
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the lock is poisoned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -136,6 +156,15 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
|
|||
/// Forces the evaluation of this lazy value and returns a mutable reference to
|
||||
/// the result.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
|
||||
/// accesses of the lock (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyLock::new
|
||||
/// [`force()`]: LazyLock::force
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -193,6 +222,15 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
|
|||
/// This method will block the calling thread if another initialization
|
||||
/// routine is currently running.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
|
||||
/// accesses of the lock (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyLock::new
|
||||
/// [`force()`]: LazyLock::force
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -227,7 +265,8 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
|
|||
}
|
||||
|
||||
impl<T, F> LazyLock<T, F> {
|
||||
/// Returns a mutable reference to the value if initialized, or `None` if not.
|
||||
/// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
|
||||
/// poisoned), returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -256,7 +295,8 @@ impl<T, F> LazyLock<T, F> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the value if initialized, or `None` if not.
|
||||
/// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
|
||||
/// returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -307,6 +347,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
|
|||
/// This method will block the calling thread if another initialization
|
||||
/// routine is currently running.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
|
||||
/// accesses of the lock (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyLock::new
|
||||
/// [`force()`]: LazyLock::force
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
LazyLock::force(self)
|
||||
|
|
@ -315,6 +363,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
|
|||
|
||||
#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
|
||||
impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F> {
|
||||
/// # Panics
|
||||
///
|
||||
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
|
||||
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
|
||||
/// accesses of the lock (via [`force()`] or a dereference) to panic.
|
||||
///
|
||||
/// [`new()`]: LazyLock::new
|
||||
/// [`force()`]: LazyLock::force
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
LazyLock::force_mut(self)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
//!
|
||||
//! The specifics of how this "poisoned" state affects other threads and whether
|
||||
//! the panics are recognized reliably or on a best-effort basis depend on the
|
||||
//! primitive. See [#Overview] below.
|
||||
//! primitive. See [Overview](#overview) below.
|
||||
//!
|
||||
//! For the alternative implementations that do not employ poisoning,
|
||||
//! see [`std::sync::nonpoison`].
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue