rust/src/libcore/cell.rs

345 lines
8.7 KiB
Rust
Raw Normal View History

// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
2014-05-07 14:12:24 -05:00
//! Types that provide interior mutability.
2014-03-05 00:19:14 -06:00
use clone::Clone;
use cmp::Eq;
use kinds::{marker, Copy};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
2014-03-10 16:55:37 -05:00
use ty::Unsafe;
2013-11-21 23:30:34 -06:00
/// A mutable memory location that admits only `Copy` data.
2013-12-11 16:54:27 -06:00
pub struct Cell<T> {
2014-03-27 17:09:47 -05:00
value: Unsafe<T>,
noshare: marker::NoShare,
2013-12-11 16:54:27 -06:00
}
impl<T:Copy> Cell<T> {
2013-12-11 16:54:27 -06:00
/// Creates a new `Cell` containing the given value.
pub fn new(value: T) -> Cell<T> {
Cell {
value: Unsafe::new(value),
2014-03-21 17:48:39 -05:00
noshare: marker::NoShare,
2013-12-11 16:54:27 -06:00
}
}
/// Returns a copy of the contained value.
#[inline]
pub fn get(&self) -> T {
2014-03-10 16:55:37 -05:00
unsafe{ *self.value.get() }
2013-12-11 16:54:27 -06:00
}
/// Sets the contained value.
#[inline]
pub fn set(&self, value: T) {
unsafe {
2014-03-10 16:55:37 -05:00
*self.value.get() = value;
2013-12-11 16:54:27 -06:00
}
}
}
impl<T:Copy> Clone for Cell<T> {
fn clone(&self) -> Cell<T> {
Cell::new(self.get())
}
}
impl<T:Eq + Copy> Eq for Cell<T> {
2014-02-24 19:38:40 -06:00
fn eq(&self, other: &Cell<T>) -> bool {
self.get() == other.get()
}
}
2013-11-21 23:30:34 -06:00
/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
2014-03-27 17:09:47 -05:00
value: Unsafe<T>,
borrow: Cell<BorrowFlag>,
2014-03-27 17:09:47 -05:00
nocopy: marker::NoCopy,
noshare: marker::NoShare,
2013-11-21 23:30:34 -06:00
}
// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;
impl<T> RefCell<T> {
/// Create a new `RefCell` containing `value`
pub fn new(value: T) -> RefCell<T> {
RefCell {
value: Unsafe::new(value),
borrow: Cell::new(UNUSED),
nocopy: marker::NoCopy,
2014-03-21 17:48:39 -05:00
noshare: marker::NoShare,
2013-11-21 23:30:34 -06:00
}
}
/// Consumes the `RefCell`, returning the wrapped value.
pub fn unwrap(self) -> T {
debug_assert!(self.borrow.get() == UNUSED);
2014-03-10 16:55:37 -05:00
unsafe{self.value.unwrap()}
2013-11-21 23:30:34 -06:00
}
/// Attempts to immutably borrow the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
/// immutable borrows can be taken out at the same time.
///
/// Returns `None` if the value is currently mutably borrowed.
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
match self.borrow.get() {
2013-11-21 23:30:34 -06:00
WRITING => None,
borrow => {
self.borrow.set(borrow + 1);
2013-11-21 23:30:34 -06:00
Some(Ref { parent: self })
}
}
}
/// Immutably borrows the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
/// immutable borrows can be taken out at the same time.
///
/// # Failure
///
/// Fails if the value is currently mutably borrowed.
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
match self.try_borrow() {
Some(ptr) => ptr,
None => fail!("RefCell<T> already mutably borrowed")
}
}
/// Mutably borrows the wrapped value.
///
2013-12-14 23:26:09 -06:00
/// The borrow lasts until the returned `RefMut` exits scope. The value
2013-11-21 23:30:34 -06:00
/// cannot be borrowed while this borrow is active.
///
/// Returns `None` if the value is currently borrowed.
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
match self.borrow.get() {
UNUSED => {
self.borrow.set(WRITING);
Some(RefMut { parent: self })
2013-11-21 23:30:34 -06:00
},
_ => None
}
}
/// Mutably borrows the wrapped value.
///
2013-12-14 23:26:09 -06:00
/// The borrow lasts until the returned `RefMut` exits scope. The value
2013-11-21 23:30:34 -06:00
/// cannot be borrowed while this borrow is active.
///
/// # Failure
///
/// Fails if the value is currently borrowed.
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
match self.try_borrow_mut() {
Some(ptr) => ptr,
None => fail!("RefCell<T> already borrowed")
}
}
2013-12-11 16:54:27 -06:00
}
2013-11-21 23:30:34 -06:00
impl<T: Clone> Clone for RefCell<T> {
fn clone(&self) -> RefCell<T> {
RefCell::new(self.borrow().clone())
2013-11-21 23:30:34 -06:00
}
}
impl<T: Eq> Eq for RefCell<T> {
fn eq(&self, other: &RefCell<T>) -> bool {
*self.borrow() == *other.borrow()
2013-11-21 23:30:34 -06:00
}
}
/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'b, T> {
2014-03-27 17:09:47 -05:00
parent: &'b RefCell<T>
2013-11-21 23:30:34 -06:00
}
#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
2013-11-21 23:30:34 -06:00
fn drop(&mut self) {
let borrow = self.parent.borrow.get();
debug_assert!(borrow != WRITING && borrow != UNUSED);
self.parent.borrow.set(borrow - 1);
2013-11-21 23:30:34 -06:00
}
}
impl<'b, T> Deref<T> for Ref<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self.parent.value.get() }
}
}
/// Copy a `Ref`.
///
/// The `RefCell` is already immutably borrowed, so this cannot fail.
///
/// A `Clone` implementation would interfere with the widespread
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
#[experimental]
pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
// Since this Ref exists, we know the borrow flag
// is not set to WRITING.
let borrow = orig.parent.borrow.get();
debug_assert!(borrow != WRITING && borrow != UNUSED);
orig.parent.borrow.set(borrow + 1);
Ref {
parent: orig.parent,
}
}
2013-11-21 23:30:34 -06:00
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
parent: &'b RefCell<T>
2013-11-21 23:30:34 -06:00
}
#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
2013-11-21 23:30:34 -06:00
fn drop(&mut self) {
let borrow = self.parent.borrow.get();
debug_assert!(borrow == WRITING);
self.parent.borrow.set(UNUSED);
2013-11-21 23:30:34 -06:00
}
}
impl<'b, T> Deref<T> for RefMut<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self.parent.value.get() }
}
}
impl<'b, T> DerefMut<T> for RefMut<'b, T> {
#[inline]
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
unsafe { &mut *self.parent.value.get() }
}
}
2013-11-21 23:30:34 -06:00
#[cfg(test)]
mod test {
use super::*;
2013-12-11 16:54:27 -06:00
#[test]
fn smoketest_cell() {
let x = Cell::new(10);
assert!(x == Cell::new(10));
assert!(x.get() == 10);
2013-12-11 16:54:27 -06:00
x.set(20);
assert!(x == Cell::new(20));
assert!(x.get() == 20);
2013-12-11 16:54:27 -06:00
let y = Cell::new((30, 40));
assert!(y == Cell::new((30, 40)));
assert!(y.get() == (30, 40));
2013-12-11 16:54:27 -06:00
}
#[test]
fn cell_has_sensible_show() {
use str::StrSlice;
let x = Cell::new("foo bar");
assert!(format!("{}", x).contains(x.get()));
x.set("baz qux");
assert!(format!("{}", x).contains(x.get()));
}
2013-11-21 23:30:34 -06:00
#[test]
fn double_imm_borrow() {
let x = RefCell::new(0);
let _b1 = x.borrow();
x.borrow();
}
#[test]
fn no_mut_then_imm_borrow() {
let x = RefCell::new(0);
let _b1 = x.borrow_mut();
assert!(x.try_borrow().is_none());
}
#[test]
fn no_imm_then_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow();
assert!(x.try_borrow_mut().is_none());
}
#[test]
fn no_double_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow_mut();
assert!(x.try_borrow_mut().is_none());
}
#[test]
fn imm_release_borrow_mut() {
let x = RefCell::new(0);
{
let _b1 = x.borrow();
}
x.borrow_mut();
}
#[test]
fn mut_release_borrow_mut() {
let x = RefCell::new(0);
{
let _b1 = x.borrow_mut();
}
x.borrow();
}
#[test]
fn double_borrow_single_release_no_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow();
{
let _b2 = x.borrow();
}
assert!(x.try_borrow_mut().is_none());
}
#[test]
#[should_fail]
fn discard_doesnt_unborrow() {
let x = RefCell::new(0);
let _b = x.borrow();
let _ = _b;
let _b = x.borrow_mut();
}
#[test]
fn clone_ref_updates_flag() {
let x = RefCell::new(0);
{
let b1 = x.borrow();
assert!(x.try_borrow_mut().is_none());
{
let _b2 = clone_ref(&b1);
assert!(x.try_borrow_mut().is_none());
}
assert!(x.try_borrow_mut().is_none());
}
assert!(x.try_borrow_mut().is_some());
}
2013-11-21 23:30:34 -06:00
}