summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-24 23:47:32 +0000
committerbors <bors@rust-lang.org>2023-04-24 23:47:32 +0000
commitfdeef3ed1809aa9bd4ea9ff0fad92010c6de669c (patch)
tree33f1f5418a86f5c85e7f7486abd0f32703305df0
parentf5559e338256f17ada6d82b429acc2dbd8facc9c (diff)
parentd9256f94a987a008484caab5acf5a6e06c24ecd3 (diff)
downloadrust-fdeef3ed1809aa9bd4ea9ff0fad92010c6de669c.tar.gz
Auto merge of #106152 - SUPERCILEX:lazycell, r=Amanieu
Add LazyCell::into_inner This enables uses cases that need to extract the evaluated value and do something owned with it.
-rw-r--r--library/core/src/cell/lazy.rs28
-rw-r--r--library/std/src/sync/lazy_lock.rs38
2 files changed, 65 insertions, 1 deletions
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index 44adcfa1a94..1b213f6a294 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -63,6 +63,34 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
}
+ /// Consumes this `LazyCell` returning the stored value.
+ ///
+ /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(lazy_cell)]
+ /// #![feature(lazy_cell_consume)]
+ ///
+ /// use std::cell::LazyCell;
+ ///
+ /// let hello = "Hello, World!".to_string();
+ ///
+ /// let lazy = LazyCell::new(|| hello.to_uppercase());
+ ///
+ /// assert_eq!(&*lazy, "HELLO, WORLD!");
+ /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
+ /// ```
+ #[unstable(feature = "lazy_cell_consume", issue = "109736")]
+ pub fn into_inner(this: Self) -> Result<T, F> {
+ match this.state.into_inner() {
+ State::Init(data) => Ok(data),
+ State::Uninit(f) => Err(f),
+ State::Poisoned => panic!("LazyCell instance has previously been poisoned"),
+ }
+ }
+
/// Forces the evaluation of this lazy value and returns a reference to
/// the result.
///
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 8e9ea293ce4..a6bc468b092 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -1,9 +1,9 @@
use crate::cell::UnsafeCell;
-use crate::fmt;
use crate::mem::ManuallyDrop;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sync::Once;
+use crate::{fmt, ptr};
use super::once::ExclusiveState;
@@ -69,6 +69,42 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
}
+ /// Consumes this `LazyLock` returning the stored value.
+ ///
+ /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(lazy_cell)]
+ /// #![feature(lazy_cell_consume)]
+ ///
+ /// use std::sync::LazyLock;
+ ///
+ /// let hello = "Hello, World!".to_string();
+ ///
+ /// let lazy = LazyLock::new(|| hello.to_uppercase());
+ ///
+ /// assert_eq!(&*lazy, "HELLO, WORLD!");
+ /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
+ /// ```
+ #[unstable(feature = "lazy_cell_consume", issue = "109736")]
+ pub fn into_inner(mut this: Self) -> Result<T, F> {
+ let state = this.once.state();
+ match state {
+ ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned"),
+ state => {
+ let this = ManuallyDrop::new(this);
+ let data = unsafe { ptr::read(&this.data) }.into_inner();
+ match state {
+ ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })),
+ ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })),
+ ExclusiveState::Poisoned => unreachable!(),
+ }
+ }
+ }
+ }
+
/// Forces the evaluation of this lazy value and
/// returns a reference to result. This is equivalent
/// to the `Deref` impl, but is explicit.