// Copyright 2013 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. //! An owned, task-local, reference counted type //! //! # Safety note //! //! XXX There is currently no type-system mechanism for enforcing that //! reference counted types are both allocated on the exchange heap //! and also non-sendable //! //! This doesn't prevent borrowing multiple aliasable mutable pointers use ops::Drop; use clone::Clone; use libc::c_void; use cast; pub struct RC { priv p: *c_void // ~(uint, T) } impl RC { pub fn new(val: T) -> RC { unsafe { let v = ~(1, val); let p: *c_void = cast::transmute(v); RC { p: p } } } fn get_mut_state(&mut self) -> *mut (uint, T) { unsafe { let p: &mut ~(uint, T) = cast::transmute(&mut self.p); let p: *mut (uint, T) = &mut **p; return p; } } fn get_state(&self) -> *(uint, T) { unsafe { let p: &~(uint, T) = cast::transmute(&self.p); let p: *(uint, T) = &**p; return p; } } pub fn unsafe_borrow_mut(&mut self) -> *mut T { unsafe { match *self.get_mut_state() { (_, ref mut p) => { let p: *mut T = p; return p; } } } } pub fn refcount(&self) -> uint { unsafe { match *self.get_state() { (count, _) => count } } } } #[unsafe_destructor] impl Drop for RC { fn drop(&mut self) { assert!(self.refcount() > 0); unsafe { match *self.get_mut_state() { (ref mut count, _) => { *count = *count - 1 } } if self.refcount() == 0 { let _: ~(uint, T) = cast::transmute(self.p); } } } } impl Clone for RC { fn clone(&self) -> RC { unsafe { // XXX: Mutable clone let this: &mut RC = cast::transmute_mut(self); match *this.get_mut_state() { (ref mut count, _) => { *count = *count + 1; } } } RC { p: self.p } } } #[cfg(test)] mod test { use super::RC; #[test] fn smoke_test() { unsafe { let mut v1 = RC::new(100); assert!(*v1.unsafe_borrow_mut() == 100); assert!(v1.refcount() == 1); let mut v2 = v1.clone(); assert!(*v2.unsafe_borrow_mut() == 100); assert!(v2.refcount() == 2); *v2.unsafe_borrow_mut() = 200; assert!(*v2.unsafe_borrow_mut() == 200); assert!(*v1.unsafe_borrow_mut() == 200); let v3 = v2.clone(); assert!(v3.refcount() == 3); { let _v1 = v1; let _v2 = v2; } assert!(v3.refcount() == 1); } } }