Skip to content

Commit 40a9de5

Browse files
committed
core::rt: Add a very simple ref counted pointer
1 parent 936fce5 commit 40a9de5

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

src/libcore/rt/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ pub mod logging;
6565
#[cfg(test)]
6666
pub mod test;
6767

68+
/// Reference counting
69+
pub mod rc;
70+
6871
/// Set up a default runtime configuration, given compiler-supplied arguments.
6972
///
7073
/// This is invoked by the `start` _language item_ (unstable::lang) to

src/libcore/rt/rc.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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 sys;
25+
use cast;
26+
27+
pub struct RC<T> {
28+
p: *c_void // ~(uint, T)
29+
}
30+
31+
impl<T> RC<T> {
32+
pub fn new(val: T) -> RC<T> {
33+
unsafe {
34+
let v = ~(1, val);
35+
let p: *c_void = cast::transmute(v);
36+
RC { p: p }
37+
}
38+
}
39+
40+
fn get_mut_state(&mut self) -> *mut (uint, T) {
41+
unsafe {
42+
let p: &mut ~(uint, T) = cast::transmute(&mut self.p);
43+
let p: *mut (uint, T) = &mut **p;
44+
return p;
45+
}
46+
}
47+
48+
fn get_state(&self) -> *(uint, T) {
49+
unsafe {
50+
let p: &~(uint, T) = cast::transmute(&self.p);
51+
let p: *(uint, T) = &**p;
52+
return p;
53+
}
54+
}
55+
56+
pub fn unsafe_borrow_mut(&mut self) -> *mut T {
57+
unsafe {
58+
match *self.get_mut_state() {
59+
(_, ref mut p) => {
60+
let p: *mut T = p;
61+
return p;
62+
}
63+
}
64+
}
65+
}
66+
67+
pub fn refcount(&self) -> uint {
68+
unsafe {
69+
match *self.get_state() {
70+
(count, _) => count
71+
}
72+
}
73+
}
74+
}
75+
76+
#[unsafe_destructor]
77+
impl<T> Drop for RC<T> {
78+
fn finalize(&self) {
79+
assert!(self.refcount() > 0);
80+
81+
unsafe {
82+
// XXX: Mutable finalizer
83+
let this: &mut RC<T> = cast::transmute_mut(self);
84+
85+
match *this.get_mut_state() {
86+
(ref mut count, _) => {
87+
*count = *count - 1
88+
}
89+
}
90+
91+
if this.refcount() == 0 {
92+
let _: ~(uint, T) = cast::transmute(this.p);
93+
}
94+
}
95+
}
96+
}
97+
98+
impl<T> Clone for RC<T> {
99+
fn clone(&self) -> RC<T> {
100+
unsafe {
101+
// XXX: Mutable clone
102+
let this: &mut RC<T> = cast::transmute_mut(self);
103+
104+
match *this.get_mut_state() {
105+
(ref mut count, _) => {
106+
*count = *count + 1;
107+
}
108+
}
109+
}
110+
111+
RC { p: self.p }
112+
}
113+
}
114+
115+
#[cfg(test)]
116+
mod test {
117+
use super::RC;
118+
119+
#[test]
120+
fn smoke_test() {
121+
unsafe {
122+
let mut v1 = RC::new(100);
123+
assert!(*v1.unsafe_borrow_mut() == 100);
124+
assert!(v1.refcount() == 1);
125+
126+
let mut v2 = v1.clone();
127+
assert!(*v2.unsafe_borrow_mut() == 100);
128+
assert!(v2.refcount() == 2);
129+
130+
*v2.unsafe_borrow_mut() = 200;
131+
assert!(*v2.unsafe_borrow_mut() == 200);
132+
assert!(*v1.unsafe_borrow_mut() == 200);
133+
134+
let v3 = v2.clone();
135+
assert!(v3.refcount() == 3);
136+
{
137+
let _v1 = v1;
138+
let _v2 = v2;
139+
}
140+
assert!(v3.refcount() == 1);
141+
}
142+
}
143+
}

0 commit comments

Comments
 (0)