about summary refs log tree commit diff
path: root/src/libcore/mutable.rs
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-09-10 16:34:31 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-09-10 16:50:07 -0700
commit29003c799f41cce948bc043cdd1350ca4bee949e (patch)
tree0e879812117977b10d42558588f952b792fa5f99 /src/libcore/mutable.rs
parent20263595185590c8c2705b92bddbd00e3fc56713 (diff)
downloadrust-29003c799f41cce948bc043cdd1350ca4bee949e.tar.gz
rust-29003c799f41cce948bc043cdd1350ca4bee949e.zip
Rename the poorly named Managed<T> type to Mut<T>.
The Mut<T> type is intended to allow freezable data stuctures to be stored in
`@mut` boxes. Currently this causes borrowck to be very conserivative since it
cannot prove that you are not modifying such a structure while iterating over
it, for example.  But if you do `@Mut<T>` instead of `@mut T`, you will
effectively convert borrowck's static checks into dynamic ones.  This lets
you use the e.g. send_map just like a Java Map or something else.
Diffstat (limited to 'src/libcore/mutable.rs')
-rw-r--r--src/libcore/mutable.rs151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/libcore/mutable.rs b/src/libcore/mutable.rs
new file mode 100644
index 00000000000..eca9ff6fada
--- /dev/null
+++ b/src/libcore/mutable.rs
@@ -0,0 +1,151 @@
+/*!
+
+Module for wrapping freezable data structures in managed boxes.
+Normally freezable data structures require an unaliased reference,
+such as `T` or `~T`, so that the compiler can track when they are
+being mutated.  The `managed<T>` type converts these static checks into
+dynamic checks: your program will fail if you attempt to perform
+mutation when the data structure should be immutable.
+
+*/
+
+#[forbid(deprecated_mode)];
+#[forbid(deprecated_pattern)];
+
+use util::with;
+use unsafe::transmute_immut;
+
+export Mut;
+
+enum Mode { ReadOnly, Mutable, Immutable }
+
+struct Data<T> {
+    priv mut value: T,
+    priv mut mode: Mode
+}
+
+type Mut<T> = Data<T>;
+
+fn Mut<T>(+t: T) -> Mut<T> {
+    Data {value: t, mode: ReadOnly}
+}
+
+fn unwrap<T>(+m: Mut<T>) -> T {
+    // Borrowck should prevent us from calling unwrap while the value
+    // is in use, as that would be a move from a borrowed value.
+    assert (m.mode as uint) == (ReadOnly as uint);
+    let Data {value, mode: _} = m;
+    return move value;
+}
+
+impl<T> Data<T> {
+    fn borrow_mut<R>(op: &fn(t: &mut T) -> R) -> R {
+        match self.mode {
+            Immutable => fail fmt!("%? currently immutable",
+                                   self.value),
+            ReadOnly | Mutable => {}
+        }
+
+        do with(&mut self.mode, Mutable) {
+            op(&mut self.value)
+        }
+    }
+
+    fn borrow_const<R>(op: &fn(t: &const T) -> R) -> R {
+        op(&const self.value)
+    }
+
+    fn borrow_imm<R>(op: &fn(t: &T) -> R) -> R {
+        match self.mode {
+          Mutable => fail fmt!("%? currently mutable",
+                               self.value),
+          ReadOnly | Immutable => {}
+        }
+
+        do with(&mut self.mode, Immutable) {
+            op(unsafe{transmute_immut(&mut self.value)})
+        }
+    }
+}
+
+#[test]
+#[ignore(cfg(windows))]
+#[should_fail]
+fn test_mut_in_imm() {
+    let m = @Mut(1);
+    do m.borrow_imm |_p| {
+        do m.borrow_mut |_q| {
+            // should not be permitted
+        }
+    }
+}
+
+#[test]
+#[ignore(cfg(windows))]
+#[should_fail]
+fn test_imm_in_mut() {
+    let m = @Mut(1);
+    do m.borrow_mut |_p| {
+        do m.borrow_imm |_q| {
+            // should not be permitted
+        }
+    }
+}
+
+#[test]
+fn test_const_in_mut() {
+    let m = @Mut(1);
+    do m.borrow_mut |p| {
+        do m.borrow_const |q| {
+            assert *p == *q;
+            *p += 1;
+            assert *p == *q;
+        }
+    }
+}
+
+#[test]
+fn test_mut_in_const() {
+    let m = @Mut(1);
+    do m.borrow_const |p| {
+        do m.borrow_mut |q| {
+            assert *p == *q;
+            *q += 1;
+            assert *p == *q;
+        }
+    }
+}
+
+#[test]
+fn test_imm_in_const() {
+    let m = @Mut(1);
+    do m.borrow_const |p| {
+        do m.borrow_imm |q| {
+            assert *p == *q;
+        }
+    }
+}
+
+#[test]
+fn test_const_in_imm() {
+    let m = @Mut(1);
+    do m.borrow_imm |p| {
+        do m.borrow_const |q| {
+            assert *p == *q;
+        }
+    }
+}
+
+
+#[test]
+#[ignore(cfg(windows))]
+#[should_fail]
+fn test_mut_in_imm_in_const() {
+    let m = @Mut(1);
+    do m.borrow_const |_p| {
+        do m.borrow_imm |_q| {
+            do m.borrow_mut |_r| {
+            }
+        }
+    }
+}