Skip to content

Commit

Permalink
Stop using transmute_mut in RefCell
Browse files Browse the repository at this point in the history
This is supposedly undefined behavior now that Unsafe exists, so we'll
use Cell instead.
  • Loading branch information
sfackler authored and alexcrichton committed Apr 10, 2014
1 parent 6e63b12 commit b994828
Showing 1 changed file with 17 additions and 21 deletions.
38 changes: 17 additions & 21 deletions src/libstd/cell.rs
Expand Up @@ -10,7 +10,6 @@

//! Types dealing with dynamic mutability

use cast;
use clone::Clone;
use cmp::Eq;
use fmt;
Expand Down Expand Up @@ -70,7 +69,7 @@ impl<T: Copy + fmt::Show> fmt::Show for Cell<T> {
/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
value: Unsafe<T>,
borrow: BorrowFlag,
borrow: Cell<BorrowFlag>,
nocopy: marker::NoCopy,
noshare: marker::NoShare,
}
Expand All @@ -86,33 +85,29 @@ impl<T> RefCell<T> {
pub fn new(value: T) -> RefCell<T> {
RefCell {
value: Unsafe::new(value),
borrow: Cell::new(UNUSED),
nocopy: marker::NoCopy,
noshare: marker::NoShare,
borrow: UNUSED,
}
}

/// Consumes the `RefCell`, returning the wrapped value.
pub fn unwrap(self) -> T {
assert!(self.borrow == UNUSED);
assert!(self.borrow.get() == UNUSED);
unsafe{self.value.unwrap()}
}

unsafe fn as_mut<'a>(&'a self) -> &'a mut RefCell<T> {
cast::transmute_mut(self)
}

/// 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 {
match self.borrow.get() {
WRITING => None,
_ => {
unsafe { self.as_mut().borrow += 1; }
borrow => {
self.borrow.set(borrow + 1);
Some(Ref { parent: self })
}
}
Expand Down Expand Up @@ -140,11 +135,10 @@ impl<T> RefCell<T> {
///
/// Returns `None` if the value is currently borrowed.
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
match self.borrow {
UNUSED => unsafe {
let mut_self = self.as_mut();
mut_self.borrow = WRITING;
Some(RefMut { parent: mut_self })
match self.borrow.get() {
UNUSED => {
self.borrow.set(WRITING);
Some(RefMut { parent: self })
},
_ => None
}
Expand Down Expand Up @@ -186,8 +180,9 @@ pub struct Ref<'b, T> {
#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
fn drop(&mut self) {
assert!(self.parent.borrow != WRITING && self.parent.borrow != UNUSED);
unsafe { self.parent.as_mut().borrow -= 1; }
let borrow = self.parent.borrow.get();
assert!(borrow != WRITING && borrow != UNUSED);
self.parent.borrow.set(borrow - 1);
}
}

Expand All @@ -200,14 +195,15 @@ impl<'b, T> Deref<T> for Ref<'b, T> {

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
parent: &'b mut RefCell<T>
parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
fn drop(&mut self) {
assert!(self.parent.borrow == WRITING);
self.parent.borrow = UNUSED;
let borrow = self.parent.borrow.get();
assert!(borrow == WRITING);
self.parent.borrow.set(UNUSED);
}
}

Expand Down

0 comments on commit b994828

Please sign in to comment.