core::rt: Add a very simple ref counted pointer
This commit is contained in:
parent
936fce5515
commit
40a9de5ebc
@ -65,6 +65,9 @@ pub mod logging;
|
||||
#[cfg(test)]
|
||||
pub mod test;
|
||||
|
||||
/// Reference counting
|
||||
pub mod rc;
|
||||
|
||||
/// Set up a default runtime configuration, given compiler-supplied arguments.
|
||||
///
|
||||
/// This is invoked by the `start` _language item_ (unstable::lang) to
|
||||
|
143
src/libcore/rt/rc.rs
Normal file
143
src/libcore/rt/rc.rs
Normal file
@ -0,0 +1,143 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 sys;
|
||||
use cast;
|
||||
|
||||
pub struct RC<T> {
|
||||
p: *c_void // ~(uint, T)
|
||||
}
|
||||
|
||||
impl<T> RC<T> {
|
||||
pub fn new(val: T) -> RC<T> {
|
||||
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<T> Drop for RC<T> {
|
||||
fn finalize(&self) {
|
||||
assert!(self.refcount() > 0);
|
||||
|
||||
unsafe {
|
||||
// XXX: Mutable finalizer
|
||||
let this: &mut RC<T> = cast::transmute_mut(self);
|
||||
|
||||
match *this.get_mut_state() {
|
||||
(ref mut count, _) => {
|
||||
*count = *count - 1
|
||||
}
|
||||
}
|
||||
|
||||
if this.refcount() == 0 {
|
||||
let _: ~(uint, T) = cast::transmute(this.p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for RC<T> {
|
||||
fn clone(&self) -> RC<T> {
|
||||
unsafe {
|
||||
// XXX: Mutable clone
|
||||
let this: &mut RC<T> = 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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user