Skip to content

Commit fdeef3e

Browse files
committed
Auto merge of rust-lang#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.
2 parents f5559e3 + d9256f9 commit fdeef3e

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

library/core/src/cell/lazy.rs

+28
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,34 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
6363
LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
6464
}
6565

66+
/// Consumes this `LazyCell` returning the stored value.
67+
///
68+
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
69+
///
70+
/// # Examples
71+
///
72+
/// ```
73+
/// #![feature(lazy_cell)]
74+
/// #![feature(lazy_cell_consume)]
75+
///
76+
/// use std::cell::LazyCell;
77+
///
78+
/// let hello = "Hello, World!".to_string();
79+
///
80+
/// let lazy = LazyCell::new(|| hello.to_uppercase());
81+
///
82+
/// assert_eq!(&*lazy, "HELLO, WORLD!");
83+
/// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
84+
/// ```
85+
#[unstable(feature = "lazy_cell_consume", issue = "109736")]
86+
pub fn into_inner(this: Self) -> Result<T, F> {
87+
match this.state.into_inner() {
88+
State::Init(data) => Ok(data),
89+
State::Uninit(f) => Err(f),
90+
State::Poisoned => panic!("LazyCell instance has previously been poisoned"),
91+
}
92+
}
93+
6694
/// Forces the evaluation of this lazy value and returns a reference to
6795
/// the result.
6896
///

library/std/src/sync/lazy_lock.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::cell::UnsafeCell;
2-
use crate::fmt;
32
use crate::mem::ManuallyDrop;
43
use crate::ops::Deref;
54
use crate::panic::{RefUnwindSafe, UnwindSafe};
65
use crate::sync::Once;
6+
use crate::{fmt, ptr};
77

88
use super::once::ExclusiveState;
99

@@ -69,6 +69,42 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
6969
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
7070
}
7171

72+
/// Consumes this `LazyLock` returning the stored value.
73+
///
74+
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
75+
///
76+
/// # Examples
77+
///
78+
/// ```
79+
/// #![feature(lazy_cell)]
80+
/// #![feature(lazy_cell_consume)]
81+
///
82+
/// use std::sync::LazyLock;
83+
///
84+
/// let hello = "Hello, World!".to_string();
85+
///
86+
/// let lazy = LazyLock::new(|| hello.to_uppercase());
87+
///
88+
/// assert_eq!(&*lazy, "HELLO, WORLD!");
89+
/// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
90+
/// ```
91+
#[unstable(feature = "lazy_cell_consume", issue = "109736")]
92+
pub fn into_inner(mut this: Self) -> Result<T, F> {
93+
let state = this.once.state();
94+
match state {
95+
ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned"),
96+
state => {
97+
let this = ManuallyDrop::new(this);
98+
let data = unsafe { ptr::read(&this.data) }.into_inner();
99+
match state {
100+
ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })),
101+
ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })),
102+
ExclusiveState::Poisoned => unreachable!(),
103+
}
104+
}
105+
}
106+
}
107+
72108
/// Forces the evaluation of this lazy value and
73109
/// returns a reference to result. This is equivalent
74110
/// to the `Deref` impl, but is explicit.

0 commit comments

Comments
 (0)