// 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 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A mutable, nullable memory location use cast::transmute; use option; use prelude::*; /* A dynamic, mutable location. Similar to a mutable option type, but friendlier. */ pub struct Cell { mut value: Option } impl cmp::Eq for Cell { fn eq(&self, other: &Cell) -> bool { unsafe { let frozen_self: &Option = transmute(&mut self.value); let frozen_other: &Option = transmute(&mut other.value); frozen_self == frozen_other } } fn ne(&self, other: &Cell) -> bool { !self.eq(other) } } /// Creates a new full cell with the given value. pub fn Cell(value: T) -> Cell { Cell { value: Some(value) } } pub fn empty_cell() -> Cell { Cell { value: None } } pub impl Cell { /// Yields the value, failing if the cell is empty. fn take(&self) -> 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(&self, 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. fn is_empty(&self) -> bool { self.value.is_none() } // Calls a closure with a reference to the value. fn with_ref(&self, 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); fail_unless!(!value_cell.is_empty()); let value = value_cell.take(); fail_unless!(value == ~10); fail_unless!(value_cell.is_empty()); value_cell.put_back(value); fail_unless!(!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); }