diff options
| author | kennytm <kennytm@gmail.com> | 2018-04-24 11:57:00 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-04-24 11:57:00 +0800 |
| commit | 91cc872987da776874021d985f08a4262ac07396 (patch) | |
| tree | ef1155a6ed17d4c4df03df892e102c6974d0ac36 /src/libcore | |
| parent | cefdd6d5e99618f193c1cd3365aa18b786731d97 (diff) | |
| parent | 29e9de85d6ae185d7d66c7ba0f2c418082d2df5f (diff) | |
| download | rust-91cc872987da776874021d985f08a4262ac07396.tar.gz rust-91cc872987da776874021d985f08a4262ac07396.zip | |
Rollup merge of #49727 - stjepang:cell-update, r=SimonSapin
Add Cell::update
This commit adds a new method `Cell::update`, which applies a function to the value inside the cell.
Previously discussed in: https://github.com/rust-lang/rfcs/issues/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
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/cell.rs | 27 | ||||
| -rw-r--r-- | src/libcore/tests/cell.rs | 11 | ||||
| -rw-r--r-- | src/libcore/tests/lib.rs | 1 |
3 files changed, 39 insertions, 0 deletions
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c8ee166fee3..1ff187ed3f1 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -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")] diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index cc0ef6a6f17..962fb2f0e02 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -27,6 +27,17 @@ fn smoketest_cell() { } #[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"); assert!(format!("{:?}", x).contains(x.get())); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7d3852d2f2a..2b69f04013d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -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)] |
