// 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. /*! 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` 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 cast::transmute_immut; enum Mode { ReadOnly, Mutable, Immutable } struct Data { priv mut value: T, priv mut mode: Mode } pub type Mut = Data; pub fn Mut(t: T) -> Mut { Data {value: move t, mode: ReadOnly} } pub fn unwrap(m: Mut) -> 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: move value, mode: _} = move m; move value } impl Data { fn borrow_mut(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) } } pure fn borrow_const(op: &fn(t: &const T) -> R) -> R { op(&const self.value) } fn borrow_imm(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] pub 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] pub fn test_imm_in_mut() { let m = @Mut(1); do m.borrow_mut |_p| { do m.borrow_imm |_q| { // should not be permitted } } } #[test] pub 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] pub 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] pub fn test_imm_in_const() { let m = @Mut(1); do m.borrow_const |p| { do m.borrow_imm |q| { assert *p == *q; } } } #[test] pub 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] pub 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| { } } } }