Skip to content

Commit

Permalink
Rollup merge of rust-lang#49727 - stjepang:cell-update, r=SimonSapin
Browse files Browse the repository at this point in the history
Add Cell::update

This commit adds a new method `Cell::update`, which applies a function to the value inside the cell.

Previously discussed in: rust-lang/rfcs#2171

### Motivation

Updating `Cell`s is currently a bit verbose. Here are several real examples (taken from rustc and crossbeam):

```rust
self.print_fuel.set(self.print_fuel.get() + 1);

self.diverges.set(self.diverges.get() | Diverges::Always);

let guard_count = self.guard_count.get();
self.guard_count.set(guard_count.checked_add(1).unwrap());
if guard_count == 0 {
    // ...
}
```

With the addition of the new method `Cell::update`, this code can be simplified to:

```rust
self.print_fuel.update(|x| x + 1);

self.diverges.update(|x| x | Diverges::Always);

if self.guard_count.update(|x| x.checked_add(1).unwrap()) == 1 {
    // ...
}
```

### Unresolved questions

1. Should we return the old value instead of the new value (like in `fetch_add` and `fetch_update`)?
2. Should the return type simply be `()`?
3. Naming: `update` vs `modify` vs `mutate` etc.

cc @SimonSapin
  • Loading branch information
kennytm committed Apr 24, 2018
2 parents cefdd6d + 29e9de8 commit 91cc872
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,33 @@ impl<T:Copy> Cell<T> {
pub fn get(&self) -> T {
unsafe{ *self.value.get() }
}

/// Updates the contained value using a function and returns the new value.
///
/// # Examples
///
/// ```
/// #![feature(cell_update)]
///
/// use std::cell::Cell;
///
/// let c = Cell::new(5);
/// let new = c.update(|x| x + 1);
///
/// assert_eq!(new, 6);
/// assert_eq!(c.get(), 6);
/// ```
#[inline]
#[unstable(feature = "cell_update", issue = "50186")]
pub fn update<F>(&self, f: F) -> T
where
F: FnOnce(T) -> T,
{
let old = self.get();
let new = f(old);
self.set(new);
new
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
11 changes: 11 additions & 0 deletions src/libcore/tests/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ fn smoketest_cell() {
assert!(y.get() == (30, 40));
}

#[test]
fn cell_update() {
let x = Cell::new(10);

assert_eq!(x.update(|x| x + 5), 15);
assert_eq!(x.get(), 15);

assert_eq!(x.update(|x| x / 3), 5);
assert_eq!(x.get(), 5);
}

#[test]
fn cell_has_sensible_show() {
let x = Cell::new("foo bar");
Expand Down
1 change: 1 addition & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#![feature(ascii_ctype)]
#![feature(box_syntax)]
#![feature(cell_update)]
#![feature(core_float)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
Expand Down

0 comments on commit 91cc872

Please sign in to comment.