(index<- )        ./libstd/rt/rc.rs

   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! An owned, task-local, reference counted type
  12  //!
  13  //! # Safety note
  14  //!
  15  //! XXX There is currently no type-system mechanism for enforcing that
  16  //! reference counted types are both allocated on the exchange heap
  17  //! and also non-sendable
  18  //!
  19  //! This doesn't prevent borrowing multiple aliasable mutable pointers
  20  
  21  use ops::Drop;
  22  use clone::Clone;
  23  use libc::c_void;
  24  use cast;
  25  
  26  pub struct RC<T> {
  27      p: *c_void // ~(uint, T)
  28  }
  29  
  30  impl<T> RC<T> {
  31      pub fn new(valT) -> RC<T> {
  32          unsafe {
  33              let v = ~(1, val);
  34              let p*c_void = cast::transmute(v);
  35              RC { p: p }
  36          }
  37      }
  38  
  39      fn get_mut_state(&mut self) -> *mut (uint, T) {
  40          unsafe {
  41              let p&mut ~(uint, T) = cast::transmute(&mut self.p);
  42              let p*mut (uint, T) = &mut **p;
  43              return p;
  44          }
  45      }
  46  
  47      fn get_state(&self) -> *(uint, T) {
  48          unsafe {
  49              let p&~(uint, T) = cast::transmute(&self.p);
  50              let p*(uint, T) = &**p;
  51              return p;
  52          }
  53      }
  54  
  55      pub fn unsafe_borrow_mut(&mut self) -> *mut T {
  56          unsafe {
  57              match *self.get_mut_state() {
  58                  (_, ref mut p) => {
  59                      let p*mut T = p;
  60                      return p;
  61                  }
  62              }
  63          }
  64      }
  65  
  66      pub fn refcount(&self) -> uint {
  67          unsafe {
  68              match *self.get_state() {
  69                  (count, _) => count
  70              }
  71          }
  72      }
  73  }
  74  
  75  #[unsafe_destructor]
  76  impl<T> Drop for RC<T> {
  77      fn drop(&mut self) {
  78          assert!(self.refcount() > 0);
  79  
  80          unsafe {
  81              match *self.get_mut_state() {
  82                  (ref mut count, _) => {
  83                      *count = *count - 1
  84                  }
  85              }
  86  
  87              if self.refcount() == 0 {
  88                  let _~(uint, T) = cast::transmute(self.p);
  89              }
  90          }
  91      }
  92  }
  93  
  94  impl<T> Clone for RC<T> {
  95      fn clone(&self) -> RC<T> {
  96          unsafe {
  97              // XXX: Mutable clone
  98              let this&mut RC<T> = cast::transmute_mut(self);
  99  
 100              match *this.get_mut_state() {
 101                  (ref mut count, _) => {
 102                      *count = *count + 1;
 103                  }
 104              }
 105          }
 106  
 107          RC { p: self.p }
 108      }
 109  }
 110  
 111  #[cfg(test)]
 112  mod test {
 113      use super::RC;
 114  
 115      #[test]
 116      fn smoke_test() {
 117          unsafe {
 118              let mut v1 = RC::new(100);
 119              assert!(*v1.unsafe_borrow_mut() == 100);
 120              assert!(v1.refcount() == 1);
 121  
 122              let mut v2 = v1.clone();
 123              assert!(*v2.unsafe_borrow_mut() == 100);
 124              assert!(v2.refcount() == 2);
 125  
 126              *v2.unsafe_borrow_mut() = 200;
 127              assert!(*v2.unsafe_borrow_mut() == 200);
 128              assert!(*v1.unsafe_borrow_mut() == 200);
 129  
 130              let v3 = v2.clone();
 131              assert!(v3.refcount() == 3);
 132              {
 133                  let _v1 = v1;
 134                  let _v2 = v2;
 135              }
 136              assert!(v3.refcount() == 1);
 137          }
 138      }
 139  }