From d9256f94a987a008484caab5acf5a6e06c24ecd3 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Mon, 26 Dec 2022 00:52:58 -0800 Subject: [PATCH] Add Lazy{Cell,Lock}::into_inner Signed-off-by: Alex Saveau --- library/core/src/cell/lazy.rs | 28 +++++++++++++++++++++++ library/std/src/sync/lazy_lock.rs | 38 ++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 44adcfa1a9463..1b213f6a2941b 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -63,6 +63,34 @@ impl T> LazyCell { 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 { + 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 8e9ea293ce4e9..a6bc468b09281 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> LazyLock { 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 { + 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.