@@ -0,0 +1,212 @@
#[ cfg( test) ]
extern mod extra;
use std:: cast:: transmute_mut;
#[ no_freeze]
pub struct Mut < T > {
priv value : T ,
priv status : BorrowStatus ,
}
#[ deriving( Eq ) ]
enum BorrowStatus {
/// the Reading count increases with each ReadPtr,
/// starting with 0 for the first one so that all values are used.
Reading ( uint ) ,
Writing ,
Unused ,
}
impl < T > Mut < T > {
pub fn new ( x : T ) -> Mut < T > {
Mut { value : x, status : Unused }
}
pub fn unwrap ( self ) -> T {
match self . status {
Unused => self . value ,
// debug assert?
_ => fail ! ( "borrow inconsistency in Mut<T>" ) ,
}
}
pub fn borrow < ' a > ( & ' a self ) -> ReadPtr < ' a , T > {
unsafe {
let mut_self = transmute_mut ( self ) ;
mut_self. status = match mut_self. status {
Unused => Reading ( 0 ) ,
Reading ( x) => Reading ( x + 1 ) ,
_ => fail ! ( "borrow: Cannot borrow while writing" )
} ;
}
ReadPtr { parent : self }
}
pub fn borrow_mut < ' a > ( & ' a self ) -> WritePtr < ' a , T > {
unsafe {
let mut_self = transmute_mut ( self ) ;
mut_self. status = match mut_self. status {
Unused => Writing ,
_ => fail ! ( "borrow_mut: Mut already in use" ) ,
} ;
WritePtr { parent : mut_self}
}
}
pub fn map < U > ( & self , f : & fn ( & T ) -> U ) -> U {
let r_ptr = self . borrow ( ) ;
f ( r_ptr. get ( ) )
}
pub fn map_mut < U > ( & self , f : & fn ( & mut T ) -> U ) -> U {
let mut m_ptr = self . borrow_mut ( ) ;
f ( m_ptr. get ( ) )
}
}
impl < T : Clone > Clone for Mut < T > {
fn clone ( & self ) -> Mut < T > {
self . map ( |x| Mut :: new ( ( * x) . clone ( ) ) )
}
}
pub struct ReadPtr < ' self , T > {
priv parent : & ' self Mut < T >
}
impl < ' self , T > ReadPtr < ' self , T > {
pub fn get < ' a > ( & ' a self ) -> & ' a T {
& self . parent . value
}
pub fn release ( self ) { }
}
#[ unsafe_destructor]
impl < ' self , T > Drop for ReadPtr < ' self , T > {
fn drop ( & mut self ) {
unsafe {
let mut_par = transmute_mut ( self . parent ) ;
match mut_par. status {
Reading ( 0 ) => mut_par. status = Unused ,
Reading ( x) => mut_par. status = Reading ( x-1 ) ,
// FIXME: should be debug assert?
_ => error ! ( "ReadPtr::drop: borrow inconsistency in Mut<T>" )
}
}
}
}
pub struct WritePtr < ' self , T > {
priv parent : & ' self mut Mut < T >
}
impl < ' self , T > WritePtr < ' self , T > {
pub fn get < ' a > ( & ' a mut self ) -> & ' a mut T {
& mut self . parent . value
}
pub fn release ( self ) { }
}
#[ unsafe_destructor]
impl < ' self , T > Drop for WritePtr < ' self , T > {
fn drop ( & mut self ) {
unsafe {
let mut_par = transmute_mut ( self . parent ) ;
match mut_par. status {
Writing => mut_par. status = Unused ,
// FIXME: should debug assert?
_ => error ! ( "WritePtr::drop: borrow inconsistency in Mut<T>" )
}
}
}
}
#[ test]
fn test_read_then_read ( ) {
let obj = Mut :: new ( 1 ) ;
let r = obj. borrow ( ) ;
let q = obj. borrow ( ) ;
assert_eq ! ( r. get( ) , q. get( ) ) ;
assert_eq ! ( obj. status, Reading ( 1 ) ) ;
r. release ( ) ;
assert_eq ! ( obj. status, Reading ( 0 ) ) ;
q. release ( ) ;
assert_eq ! ( obj. status, Unused ) ;
}
#[ test]
#[ should_fail]
fn test_read_release_partial_then_write ( ) {
let obj = Mut :: new ( 1 ) ;
let r = obj. borrow ( ) ;
let q = obj. borrow ( ) ;
assert_eq ! ( r. get( ) , q. get( ) ) ;
r. release ( ) ;
let _ = obj. borrow_mut ( ) ;
}
#[ test]
#[ should_fail]
fn test_write_then_write ( ) {
let obj = Mut :: new ( 1 ) ;
let mptr = obj. borrow_mut ( ) ;
let nptr = obj. borrow_mut ( ) ;
mptr. release ( ) ;
nptr. release ( ) ;
}
#[ test]
fn test_read_release_then_write ( ) {
let obj = Mut :: new ( 1 ) ;
let r = obj. borrow ( ) ;
let q = obj. borrow ( ) ;
assert_eq ! ( r. get( ) , q. get( ) ) ;
r. release ( ) ;
q. release ( ) ;
let mut m = obj. borrow_mut ( ) ;
* m. get ( ) = 99 ;
m. release ( ) ;
let r = obj. borrow ( ) ;
assert_eq ! ( * r. get( ) , 99 ) ;
}
#[ test]
#[ should_fail]
fn test_read_then_write ( ) {
let obj = Mut :: new ( 1 ) ;
let r = obj. borrow ( ) ;
let _ = obj. borrow_mut ( ) ;
r. release ( ) ;
}
#[ test]
fn test_inside_opt ( ) {
let obj = Some ( Mut :: new ( 1 ) ) ;
let mut r = obj. map ( |y| y. borrow_mut ( ) ) ;
match r {
Some ( ref mut token) => * token. get ( ) = 99 ,
None => ( )
}
std:: util:: ignore ( r) ;
let token = obj. get_ref ( ) . borrow ( ) ;
assert_eq ! ( * token. get( ) , 99 ) ;
}
#[ test]
fn test_inside_rc( ) {
use extra:: rc:: Rc ;
let rc = Rc :: from_send ( Mut :: new ( 1 ) ) ;
let rc2 = rc. clone ( ) ;
let rtoken = rc2. borrow ( ) . borrow ( ) ;
assert_eq ! ( * rtoken. get( ) , 1 ) ;
rtoken. release ( ) ;
do rc2. borrow ( ) . map_mut |t| {
* t = 3 ;
}
assert_eq ! ( 3 , rc. borrow( ) . map( |t| * t) ) ;
}