Skip to content

Commit bdfaf04

Browse files
committed
Move mutable::Mut to cell::RefCell
1 parent c6ca9ab commit bdfaf04

11 files changed

+335
-350
lines changed

src/libstd/cell.rs

+298-4
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! Runtime move semantics
11+
//! Types dealing with dynamic mutability
1212
1313
#[missing_doc];
1414

15-
use cast::transmute_mut;
1615
use prelude::*;
16+
use cast;
17+
use util::NonCopyable;
18+
1719

1820
/*
1921
A dynamic, mutable location.
@@ -36,7 +38,7 @@ impl<T> Cell<T> {
3638

3739
/// Yields the value, failing if the cell is empty.
3840
pub fn take(&self) -> T {
39-
let this = unsafe { transmute_mut(self) };
41+
let this = unsafe { cast::transmute_mut(self) };
4042
if this.is_empty() {
4143
fail!("attempt to take an empty cell");
4244
}
@@ -46,7 +48,7 @@ impl<T> Cell<T> {
4648

4749
/// Yields the value if the cell is full, or `None` if it is empty.
4850
pub fn take_opt(&self) -> Option<T> {
49-
let this = unsafe { transmute_mut(self) };
51+
let this = unsafe { cast::transmute_mut(self) };
5052
this.value.take()
5153
}
5254

@@ -72,3 +74,295 @@ fn test_take_empty() {
7274
value_cell.take();
7375
value_cell.take();
7476
}
77+
78+
79+
/// A mutable memory location with dynamically checked borrow rules
80+
#[no_freeze]
81+
pub struct RefCell<T> {
82+
priv value: T,
83+
priv borrow: BorrowFlag,
84+
priv nc: NonCopyable
85+
}
86+
87+
// Values [1, MAX-1] represent the number of `Ref` active
88+
// (will not outgrow its range since `uint` is the size of the address space)
89+
type BorrowFlag = uint;
90+
static UNUSED: BorrowFlag = 0;
91+
static WRITING: BorrowFlag = -1;
92+
93+
impl<T> RefCell<T> {
94+
/// Create a new `RefCell` containing `value`
95+
pub fn new(value: T) -> RefCell<T> {
96+
RefCell {
97+
value: value,
98+
borrow: UNUSED,
99+
nc: NonCopyable
100+
}
101+
}
102+
103+
/// Consumes the `RefCell`, returning the wrapped value.
104+
pub fn unwrap(self) -> T {
105+
assert!(self.borrow == UNUSED);
106+
self.value
107+
}
108+
109+
unsafe fn as_mut<'a>(&'a self) -> &'a mut RefCell<T> {
110+
cast::transmute_mut(self)
111+
}
112+
113+
/// Attempts to immutably borrow the wrapped value.
114+
///
115+
/// The borrow lasts until the returned `Ref` exits scope. Multiple
116+
/// immutable borrows can be taken out at the same time.
117+
///
118+
/// Returns `None` if the value is currently mutably borrowed.
119+
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
120+
match self.borrow {
121+
WRITING => None,
122+
_ => {
123+
unsafe { self.as_mut().borrow += 1; }
124+
Some(Ref { parent: self })
125+
}
126+
}
127+
}
128+
129+
/// Immutably borrows the wrapped value.
130+
///
131+
/// The borrow lasts until the returned `Ref` exits scope. Multiple
132+
/// immutable borrows can be taken out at the same time.
133+
///
134+
/// # Failure
135+
///
136+
/// Fails if the value is currently mutably borrowed.
137+
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
138+
match self.try_borrow() {
139+
Some(ptr) => ptr,
140+
None => fail!("RefCell<T> already mutably borrowed")
141+
}
142+
}
143+
144+
/// Mutably borrows the wrapped value.
145+
///
146+
/// The borrow lasts untile the returned `RefMut` exits scope. The value
147+
/// cannot be borrowed while this borrow is active.
148+
///
149+
/// Returns `None` if the value is currently borrowed.
150+
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
151+
match self.borrow {
152+
UNUSED => unsafe {
153+
let mut_self = self.as_mut();
154+
mut_self.borrow = WRITING;
155+
Some(RefMut { parent: mut_self })
156+
},
157+
_ => None
158+
}
159+
}
160+
161+
/// Mutably borrows the wrapped value.
162+
///
163+
/// The borrow lasts untile the returned `RefMut` exits scope. The value
164+
/// cannot be borrowed while this borrow is active.
165+
///
166+
/// # Failure
167+
///
168+
/// Fails if the value is currently borrowed.
169+
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
170+
match self.try_borrow_mut() {
171+
Some(ptr) => ptr,
172+
None => fail!("RefCell<T> already borrowed")
173+
}
174+
}
175+
176+
/// Immutably borrows the wrapped value and applies `blk` to it.
177+
///
178+
/// # Failure
179+
///
180+
/// Fails if the value is currently mutably borrowed.
181+
#[inline]
182+
pub fn with<U>(&self, blk: |&T| -> U) -> U {
183+
let ptr = self.borrow();
184+
blk(ptr.get())
185+
}
186+
187+
/// Mutably borrows the wrapped value and applies `blk` to it.
188+
///
189+
/// # Failure
190+
///
191+
/// Fails if the value is currently borrowed.
192+
#[inline]
193+
pub fn with_mut<U>(&self, blk: |&mut T| -> U) -> U {
194+
let mut ptr = self.borrow_mut();
195+
blk(ptr.get())
196+
}
197+
}
198+
199+
impl<T: Clone> Clone for RefCell<T> {
200+
fn clone(&self) -> RefCell<T> {
201+
let x = self.borrow();
202+
RefCell::new(x.get().clone())
203+
}
204+
}
205+
206+
impl<T: DeepClone> DeepClone for RefCell<T> {
207+
fn deep_clone(&self) -> RefCell<T> {
208+
let x = self.borrow();
209+
RefCell::new(x.get().deep_clone())
210+
}
211+
}
212+
213+
impl<T: Eq> Eq for RefCell<T> {
214+
fn eq(&self, other: &RefCell<T>) -> bool {
215+
let a = self.borrow();
216+
let b = other.borrow();
217+
a.get() == b.get()
218+
}
219+
}
220+
221+
/// Wraps a borrowed reference to a value in a `RefCell` box.
222+
pub struct Ref<'box, T> {
223+
priv parent: &'box RefCell<T>
224+
}
225+
226+
#[unsafe_destructor]
227+
impl<'box, T> Drop for Ref<'box, T> {
228+
fn drop(&mut self) {
229+
assert!(self.parent.borrow != WRITING && self.parent.borrow != UNUSED);
230+
unsafe { self.parent.as_mut().borrow -= 1; }
231+
}
232+
}
233+
234+
impl<'box, T> Ref<'box, T> {
235+
/// Retrieve an immutable reference to the stored value.
236+
#[inline]
237+
pub fn get<'a>(&'a self) -> &'a T {
238+
&self.parent.value
239+
}
240+
}
241+
242+
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
243+
pub struct RefMut<'box, T> {
244+
priv parent: &'box mut RefCell<T>
245+
}
246+
247+
#[unsafe_destructor]
248+
impl<'box, T> Drop for RefMut<'box, T> {
249+
fn drop(&mut self) {
250+
assert!(self.parent.borrow == WRITING);
251+
self.parent.borrow = UNUSED;
252+
}
253+
}
254+
255+
impl<'box, T> RefMut<'box, T> {
256+
/// Retrieve a mutable reference to the stored value.
257+
#[inline]
258+
pub fn get<'a>(&'a mut self) -> &'a mut T {
259+
&mut self.parent.value
260+
}
261+
}
262+
263+
#[cfg(test)]
264+
mod test {
265+
use super::*;
266+
267+
#[test]
268+
fn double_imm_borrow() {
269+
let x = RefCell::new(0);
270+
let _b1 = x.borrow();
271+
x.borrow();
272+
}
273+
274+
#[test]
275+
fn no_mut_then_imm_borrow() {
276+
let x = RefCell::new(0);
277+
let _b1 = x.borrow_mut();
278+
assert!(x.try_borrow().is_none());
279+
}
280+
281+
#[test]
282+
fn no_imm_then_borrow_mut() {
283+
let x = RefCell::new(0);
284+
let _b1 = x.borrow();
285+
assert!(x.try_borrow_mut().is_none());
286+
}
287+
288+
#[test]
289+
fn no_double_borrow_mut() {
290+
let x = RefCell::new(0);
291+
let _b1 = x.borrow_mut();
292+
assert!(x.try_borrow_mut().is_none());
293+
}
294+
295+
#[test]
296+
fn imm_release_borrow_mut() {
297+
let x = RefCell::new(0);
298+
{
299+
let _b1 = x.borrow();
300+
}
301+
x.borrow_mut();
302+
}
303+
304+
#[test]
305+
fn mut_release_borrow_mut() {
306+
let x = RefCell::new(0);
307+
{
308+
let _b1 = x.borrow_mut();
309+
}
310+
x.borrow();
311+
}
312+
313+
#[test]
314+
fn double_borrow_single_release_no_borrow_mut() {
315+
let x = RefCell::new(0);
316+
let _b1 = x.borrow();
317+
{
318+
let _b2 = x.borrow();
319+
}
320+
assert!(x.try_borrow_mut().is_none());
321+
}
322+
323+
#[test]
324+
fn with_ok() {
325+
let x = RefCell::new(0);
326+
assert_eq!(1, x.with(|x| *x+1));
327+
}
328+
329+
#[test]
330+
#[should_fail]
331+
fn mut_borrow_with() {
332+
let x = RefCell::new(0);
333+
let _b1 = x.borrow_mut();
334+
x.with(|x| *x+1);
335+
}
336+
337+
#[test]
338+
fn borrow_with() {
339+
let x = RefCell::new(0);
340+
let _b1 = x.borrow();
341+
assert_eq!(1, x.with(|x| *x+1));
342+
}
343+
344+
#[test]
345+
fn with_mut_ok() {
346+
let x = RefCell::new(0);
347+
x.with_mut(|x| *x += 1);
348+
let b = x.borrow();
349+
assert_eq!(1, *b.get());
350+
}
351+
352+
#[test]
353+
#[should_fail]
354+
fn borrow_with_mut() {
355+
let x = RefCell::new(0);
356+
let _b = x.borrow();
357+
x.with_mut(|x| *x += 1);
358+
}
359+
360+
#[test]
361+
#[should_fail]
362+
fn discard_doesnt_unborrow() {
363+
let x = RefCell::new(0);
364+
let _b = x.borrow();
365+
let _ = _b;
366+
let _b = x.borrow_mut();
367+
}
368+
}

src/libstd/gc.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,26 @@ impl<T: DeepClone + Send + 'static> DeepClone for Gc<T> {
5555
#[cfg(test)]
5656
mod tests {
5757
use super::*;
58-
use cell::Cell;
58+
use cell::RefCell;
5959

6060
#[test]
6161
fn test_clone() {
62-
let x = Gc::new(Cell::new(5));
62+
let x = Gc::new(RefCell::new(5));
6363
let y = x.clone();
64-
do x.borrow().with_mut_ref |inner| {
64+
do x.borrow().with_mut |inner| {
6565
*inner = 20;
6666
}
67-
assert_eq!(y.borrow().take(), 20);
67+
assert_eq!(y.borrow().with(|x| *x), 20);
6868
}
6969

7070
#[test]
7171
fn test_deep_clone() {
72-
let x = Gc::new(Cell::new(5));
72+
let x = Gc::new(RefCell::new(5));
7373
let y = x.deep_clone();
74-
do x.borrow().with_mut_ref |inner| {
74+
do x.borrow().with_mut |inner| {
7575
*inner = 20;
7676
}
77-
assert_eq!(y.borrow().take(), 5);
77+
assert_eq!(y.borrow().with(|x| *x), 5);
7878
}
7979

8080
#[test]

src/libstd/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ pub mod result;
164164
pub mod either;
165165
pub mod hashmap;
166166
pub mod cell;
167-
pub mod mutable;
168167
pub mod trie;
169168

170169

0 commit comments

Comments
 (0)