]> git.lizzy.rs Git - rust.git/blob - src/libstd/weak.rs
add a strong/weak reference counted pointer type
[rust.git] / src / libstd / weak.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 /*! Task-local reference counted boxes with weak pointer support
12
13 The `Strong` type is an extension of `std::rc::Rc` with a `downgrade` method returning a `Weak`
14 pointer type. Ownership of the contained value is shared amongst the `Strong` pointers, and the
15 value will be destroyed as soon as the last one is gone. A `Weak` pointer can be upgraded to a
16 `Strong` pointer, but will return `None` if the value has already been freed. It can be used to
17 avoid creating reference cycles.
18
19 For example, a tree with parent pointers can be represented by putting the nodes behind `Strong`
20 pointers, and then storing the parent pointers as `Weak` pointers.
21
22 */
23
24 use cast::transmute;
25 use ops::Drop;
26 use cmp::{Eq, Ord};
27 use clone::{Clone, DeepClone};
28 use rt::global_heap::exchange_free;
29 use ptr::read_ptr;
30 use option::{Option, Some, None};
31
32 struct RcBox<T> {
33     value: T,
34     strong: uint,
35     weak: uint
36 }
37
38 /// Immutable reference counted pointer type
39 #[unsafe_no_drop_flag]
40 #[no_send]
41 pub struct Strong<T> {
42     priv ptr: *mut RcBox<T>
43 }
44
45 impl<T> Strong<T> {
46     /// Construct a new reference-counted box
47     pub fn new(value: T) -> Strong<T> {
48         unsafe {
49             Strong { ptr: transmute(~RcBox { value: value, strong: 1, weak: 0 }) }
50         }
51     }
52 }
53
54 impl<T> Strong<T> {
55     /// Borrow the value contained in the reference-counted box
56     #[inline(always)]
57     pub fn borrow<'a>(&'a self) -> &'a T {
58         unsafe { &(*self.ptr).value }
59     }
60
61     /// Downgrade the reference-counted pointer to a weak reference
62     pub fn downgrade(&self) -> Weak<T> {
63         unsafe {
64             (*self.ptr).weak += 1;
65             Weak { ptr: self.ptr }
66         }
67     }
68 }
69
70 #[unsafe_destructor]
71 impl<T> Drop for Strong<T> {
72     fn drop(&mut self) {
73         unsafe {
74             if self.ptr != 0 as *mut RcBox<T> {
75                 (*self.ptr).strong -= 1;
76                 if (*self.ptr).strong == 0 {
77                     read_ptr(self.borrow()); // destroy the contained object
78                     if (*self.ptr).weak == 0 {
79                         exchange_free(self.ptr as *mut u8 as *i8)
80                     }
81                 }
82             }
83         }
84     }
85 }
86
87 impl<T> Clone for Strong<T> {
88     #[inline]
89     fn clone(&self) -> Strong<T> {
90         unsafe {
91             (*self.ptr).strong += 1;
92             Strong { ptr: self.ptr }
93         }
94     }
95 }
96
97 impl<T: DeepClone> DeepClone for Strong<T> {
98     #[inline]
99     fn deep_clone(&self) -> Strong<T> {
100         Strong::new(self.borrow().deep_clone())
101     }
102 }
103
104 impl<T: Eq> Eq for Strong<T> {
105     #[inline(always)]
106     fn eq(&self, other: &Strong<T>) -> bool { *self.borrow() == *other.borrow() }
107
108     #[inline(always)]
109     fn ne(&self, other: &Strong<T>) -> bool { *self.borrow() != *other.borrow() }
110 }
111
112 impl<T: Ord> Ord for Strong<T> {
113     #[inline(always)]
114     fn lt(&self, other: &Strong<T>) -> bool { *self.borrow() < *other.borrow() }
115
116     #[inline(always)]
117     fn le(&self, other: &Strong<T>) -> bool { *self.borrow() <= *other.borrow() }
118
119     #[inline(always)]
120     fn gt(&self, other: &Strong<T>) -> bool { *self.borrow() > *other.borrow() }
121
122     #[inline(always)]
123     fn ge(&self, other: &Strong<T>) -> bool { *self.borrow() >= *other.borrow() }
124 }
125
126 /// Weak reference to a reference-counted box
127 #[unsafe_no_drop_flag]
128 #[no_send]
129 pub struct Weak<T> {
130     priv ptr: *mut RcBox<T>
131 }
132
133 impl<T> Weak<T> {
134     /// Upgrade a weak reference to a strong reference
135     pub fn upgrade(&self) -> Option<Strong<T>> {
136         unsafe {
137             if (*self.ptr).strong == 0 {
138                 None
139             } else {
140                 (*self.ptr).strong += 1;
141                 Some(Strong { ptr: self.ptr })
142             }
143         }
144     }
145 }
146
147 #[unsafe_destructor]
148 impl<T> Drop for Weak<T> {
149     fn drop(&mut self) {
150         unsafe {
151             if self.ptr != 0 as *mut RcBox<T> {
152                 (*self.ptr).weak -= 1;
153                 if (*self.ptr).weak == 0 && (*self.ptr).strong == 0 {
154                     exchange_free(self.ptr as *mut u8 as *i8)
155                 }
156             }
157         }
158     }
159 }
160
161 impl<T> Clone for Weak<T> {
162     #[inline]
163     fn clone(&self) -> Weak<T> {
164         unsafe {
165             (*self.ptr).weak += 1;
166             Weak { ptr: self.ptr }
167         }
168     }
169 }
170
171 #[cfg(test)]
172 mod tests {
173     use super::*;
174     use prelude::drop;
175
176     #[test]
177     fn test_live() {
178         let x = Strong::new(5);
179         let y = x.downgrade();
180         assert!(y.upgrade().is_some());
181     }
182
183     #[test]
184     fn test_dead() {
185         let x = Strong::new(5);
186         let y = x.downgrade();
187         drop(x);
188         assert!(y.upgrade().is_none());
189     }
190 }