Skip to content

Commit

Permalink
Merge #131
Browse files Browse the repository at this point in the history
131: Add Lazy::into_value r=matklad a=matklad

This API allows to move a T out of `Lazy<T>`.
Note that it requires an owned access to a `Lazy` -- there's no way to
reset a lazy to uninit state via `&mut Lazy<T>`, as the init function
is gone. In other words, `fn take(this: &mut Lazy<T>)` is an
impossible object.

Co-authored-by: Aleksey Kladov <[email protected]>
  • Loading branch information
bors[bot] and matklad authored Feb 22, 2021
2 parents 1d2ddbb + ca1bfa1 commit 97027d5
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 1.6.0

- Add `Lazy::into_value`
- Stabilize `once_cell::race` module for "first one wins" no_std-compatible initialization flavor.
- Migrate from deprecated `compare_and_swap` to `compare_exchange`.

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "once_cell"
version = "1.5.2"
version = "1.6.0"
authors = ["Aleksey Kladov <[email protected]>"]
license = "MIT OR Apache-2.0"
edition = "2018"
Expand Down
22 changes: 22 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,17 @@ pub mod unsync {
pub const fn new(init: F) -> Lazy<T, F> {
Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) }
}

/// Consumes this `Lazy` returning the stored value.
///
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
pub fn into_value(this: Lazy<T, F>) -> Result<T, F> {
let cell = this.cell;
let init = this.init;
cell.into_inner().ok_or_else(|| {
init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
})
}
}

impl<T, F: FnOnce() -> T> Lazy<T, F> {
Expand Down Expand Up @@ -980,6 +991,17 @@ pub mod sync {
pub const fn new(f: F) -> Lazy<T, F> {
Lazy { cell: OnceCell::new(), init: Cell::new(Some(f)) }
}

/// Consumes this `Lazy` returning the stored value.
///
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
pub fn into_value(this: Lazy<T, F>) -> Result<T, F> {
let cell = this.cell;
let init = this.init;
cell.into_inner().ok_or_else(|| {
init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
})
}
}

impl<T, F: FnOnce() -> T> Lazy<T, F> {
Expand Down
18 changes: 18 additions & 0 deletions tests/it.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ mod unsync {
assert_eq!(CALLED.load(SeqCst), 1);
}

#[test]
fn lazy_into_value() {
let l: Lazy<i32, _> = Lazy::new(|| panic!());
assert!(matches!(Lazy::into_value(l), Err(_)));
let l = Lazy::new(|| -> i32 { 92 });
Lazy::force(&l);
assert!(matches!(Lazy::into_value(l), Ok(92)));
}

#[test]
#[cfg(feature = "std")]
fn lazy_poisoning() {
Expand Down Expand Up @@ -467,6 +476,15 @@ mod sync {
assert_eq!(xs(), &vec![1, 2, 3]);
}

#[test]
fn lazy_into_value() {
let l: Lazy<i32, _> = Lazy::new(|| panic!());
assert!(matches!(Lazy::into_value(l), Err(_)));
let l = Lazy::new(|| -> i32 { 92 });
Lazy::force(&l);
assert!(matches!(Lazy::into_value(l), Ok(92)));
}

#[test]
fn lazy_poisoning() {
let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
Expand Down

0 comments on commit 97027d5

Please sign in to comment.