Skip to content

Commit

Permalink
feat: add LazyCell::replace for infallible access
Browse files Browse the repository at this point in the history
This differs from other functions that it requires `&mut self` but if you've
locally got access to `&mut self` in code it's often quite handy to take
advantage of such privileged access!
  • Loading branch information
alexcrichton authored and indiv0 committed Sep 19, 2018
1 parent a66d592 commit a63ffb9
Showing 1 changed file with 54 additions and 0 deletions.
54 changes: 54 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
extern crate core as std;

use std::cell::UnsafeCell;
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};

/// A lazily filled `Cell`, with mutable contents.
Expand Down Expand Up @@ -81,6 +82,20 @@ impl<T> LazyCell<T> {
Ok(())
}

/// Put a value into this cell.
///
/// Note that this function is infallible but requires `&mut self`. By
/// requiring `&mut self` we're guaranteed that no active borrows to this
/// cell can exist so we can always fill in the value. This may not always
/// be usable, however, as `&mut self` may not be possible to borrow.
///
/// # Return value
///
/// This function returns the previous value, if any.
pub fn replace(&mut self, value: T) -> Option<T> {
mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
}

/// Test whether this cell has been previously filled.
pub fn filled(&self) -> bool {
self.borrow().is_some()
Expand Down Expand Up @@ -241,6 +256,24 @@ impl<T> AtomicLazyCell<T> {
Ok(())
}

/// Put a value into this cell.
///
/// Note that this function is infallible but requires `&mut self`. By
/// requiring `&mut self` we're guaranteed that no active borrows to this
/// cell can exist so we can always fill in the value. This may not always
/// be usable, however, as `&mut self` may not be possible to borrow.
///
/// # Return value
///
/// This function returns the previous value, if any.
pub fn replace(&mut self, value: T) -> Option<T> {
match mem::replace(self.state.get_mut(), SOME) {
NONE | SOME => {}
_ => panic!("cell in inconsistent state"),
}
mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
}

/// Test whether this cell has been previously filled.
pub fn filled(&self) -> bool {
self.state.load(Ordering::Acquire) == SOME
Expand Down Expand Up @@ -526,4 +559,25 @@ mod tests {
let value = lazycell.into_inner();
assert_eq!(value, Some(1));
}

#[test]
fn normal_replace() {
let mut cell = LazyCell::new();
assert_eq!(cell.fill(1), Ok(()));
assert_eq!(cell.replace(2), Some(1));
assert_eq!(cell.replace(3), Some(2));
assert_eq!(cell.borrow(), Some(&3));

let mut cell = LazyCell::new();
assert_eq!(cell.replace(2), None);
}

#[test]
fn atomic_replace() {
let mut cell = AtomicLazyCell::new();
assert_eq!(cell.fill(1), Ok(()));
assert_eq!(cell.replace(2), Some(1));
assert_eq!(cell.replace(3), Some(2));
assert_eq!(cell.borrow(), Some(&3));
}
}

0 comments on commit a63ffb9

Please sign in to comment.