about summary refs log tree commit diff
path: root/src/libcore/cell.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcore/cell.rs')
-rw-r--r--src/libcore/cell.rs90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
new file mode 100644
index 00000000000..5887df6802f
--- /dev/null
+++ b/src/libcore/cell.rs
@@ -0,0 +1,90 @@
+// Copyright 2012 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.
+
+use option;
+use prelude::*;
+
+/// A dynamic, mutable location.
+///
+/// Similar to a mutable option type, but friendlier.
+
+pub struct Cell<T> {
+    mut value: Option<T>
+}
+
+/// Creates a new full cell with the given value.
+pub fn Cell<T>(value: T) -> Cell<T> {
+    Cell { value: Some(value) }
+}
+
+pub pure fn empty_cell<T>() -> Cell<T> {
+    Cell { value: None }
+}
+
+impl<T> Cell<T> {
+    /// Yields the value, failing if the cell is empty.
+    fn take() -> T {
+        if self.is_empty() {
+            fail!(~"attempt to take an empty cell");
+        }
+
+        let mut value = None;
+        value <-> self.value;
+        return option::unwrap(value);
+    }
+
+    /// Returns the value, failing if the cell is full.
+    fn put_back(value: T) {
+        if !self.is_empty() {
+            fail!(~"attempt to put a value back into a full cell");
+        }
+        self.value = Some(value);
+    }
+
+    /// Returns true if the cell is empty and false if the cell is full.
+    pure fn is_empty() -> bool {
+        self.value.is_none()
+    }
+
+    // Calls a closure with a reference to the value.
+    fn with_ref<R>(op: fn(v: &T) -> R) -> R {
+        let v = self.take();
+        let r = op(&v);
+        self.put_back(v);
+        r
+    }
+}
+
+#[test]
+fn test_basic() {
+    let value_cell = Cell(~10);
+    assert !value_cell.is_empty();
+    let value = value_cell.take();
+    assert value == ~10;
+    assert value_cell.is_empty();
+    value_cell.put_back(value);
+    assert !value_cell.is_empty();
+}
+
+#[test]
+#[should_fail]
+#[ignore(cfg(windows))]
+fn test_take_empty() {
+    let value_cell = empty_cell::<~int>();
+    value_cell.take();
+}
+
+#[test]
+#[should_fail]
+#[ignore(cfg(windows))]
+fn test_put_back_non_empty() {
+    let value_cell = Cell(~10);
+    value_cell.put_back(~20);
+}