Skip to content

Commit

Permalink
Merge #193
Browse files Browse the repository at this point in the history
193: `Lazy` mutable  API extension r=matklad a=danielSanchezQ

As requested in #113.  Also added explicit `get_mut`. 

Implement:

- [x] `async::Lazy::force_mut`
- [x] `async::Lazy::get_mut`
- [x] `sync::Lazy::force_mut`
- [x] `sync::Lazy::get_mut`



Co-authored-by: Daniel Sanchez Quiros <sanchez.quiros.daniel@gmail.com>
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
  • Loading branch information
3 people committed Sep 2, 2022
2 parents 932c3ec + ceff838 commit df34da6
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 1 deletion.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,13 @@

-

## 1.14.0

- Add extension to `unsync` and `sync` `Lazy` mut API:
- `force_mut`
- `get_mut`


## 1.13.1

- Make implementation compliant with [strict provenance](https://github.com/rust-lang/rust/issues/95228).
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "once_cell"
version = "1.13.1"
version = "1.14.0"
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2018"
Expand Down
70 changes: 70 additions & 0 deletions src/lib.rs
Expand Up @@ -742,6 +742,25 @@ pub mod unsync {
})
}

/// Forces the evaluation of this lazy value and returns a mutable reference to
/// the result.
///
/// This is equivalent to the `DerefMut` impl, but is explicit.
///
/// # Example
/// ```
/// use once_cell::unsync::Lazy;
///
/// let mut lazy = Lazy::new(|| 92);
///
/// assert_eq!(Lazy::force_mut(&mut lazy), &92);
/// assert_eq!(*lazy, 92);
/// ```
pub fn force_mut(this: &mut Lazy<T, F>) -> &mut T {
Self::force(this);
Self::get_mut(this).unwrap_or_else(|| unreachable!())
}

/// Gets the reference to the result of this lazy value if
/// it was initialized, otherwise returns `None`.
///
Expand All @@ -758,6 +777,23 @@ pub mod unsync {
pub fn get(this: &Lazy<T, F>) -> Option<&T> {
this.cell.get()
}

/// Gets the mutable reference to the result of this lazy value if
/// it was initialized, otherwise returns `None`.
///
/// # Example
/// ```
/// use once_cell::unsync::Lazy;
///
/// let mut lazy = Lazy::new(|| 92);
///
/// assert_eq!(Lazy::get_mut(&mut lazy), None);
/// assert_eq!(*lazy, 92);
/// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92));
/// ```
pub fn get_mut(this: &mut Lazy<T, F>) -> Option<&mut T> {
this.cell.get_mut()
}
}

impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
Expand Down Expand Up @@ -1232,6 +1268,23 @@ pub mod sync {
})
}

/// Forces the evaluation of this lazy value and
/// returns a mutable reference to the result. This is equivalent
/// to the `Deref` impl, but is explicit.
///
/// # Example
/// ```
/// use once_cell::sync::Lazy;
///
/// let mut lazy = Lazy::new(|| 92);
///
/// assert_eq!(Lazy::force_mut(&mut lazy), &mut 92);
/// ```
pub fn force_mut(this: &mut Lazy<T, F>) -> &mut T {
Self::force(this);
Self::get_mut(this).unwrap_or_else(|| unreachable!())
}

/// Gets the reference to the result of this lazy value if
/// it was initialized, otherwise returns `None`.
///
Expand All @@ -1248,6 +1301,23 @@ pub mod sync {
pub fn get(this: &Lazy<T, F>) -> Option<&T> {
this.cell.get()
}

/// Gets the reference to the result of this lazy value if
/// it was initialized, otherwise returns `None`.
///
/// # Example
/// ```
/// use once_cell::sync::Lazy;
///
/// let mut lazy = Lazy::new(|| 92);
///
/// assert_eq!(Lazy::get_mut(&mut lazy), None);
/// assert_eq!(&*lazy, &92);
/// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92));
/// ```
pub fn get_mut(this: &mut Lazy<T, F>) -> Option<&mut T> {
this.cell.get_mut()
}
}

impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
Expand Down
35 changes: 35 additions & 0 deletions tests/it.rs
Expand Up @@ -137,6 +137,41 @@ mod unsync {
assert_eq!(called.get(), 1);
}

#[test]
fn lazy_force_mut() {
let called = Cell::new(0);
let mut x = Lazy::new(|| {
called.set(called.get() + 1);
92
});
assert_eq!(called.get(), 0);
let v = Lazy::force_mut(&mut x);
assert_eq!(called.get(), 1);

*v /= 2;
assert_eq!(*x, 46);
assert_eq!(called.get(), 1);
}

#[test]
fn lazy_get_mut() {
let called = Cell::new(0);
let mut x: Lazy<u32, _> = Lazy::new(|| {
called.set(called.get() + 1);
92
});

assert_eq!(called.get(), 0);
assert_eq!(*x, 92);

let mut_ref: &mut u32 = Lazy::get_mut(&mut x).unwrap();
assert_eq!(called.get(), 1);

*mut_ref /= 2;
assert_eq!(*x, 46);
assert_eq!(called.get(), 1);
}

#[test]
fn lazy_default() {
static CALLED: AtomicUsize = AtomicUsize::new(0);
Expand Down

0 comments on commit df34da6

Please sign in to comment.