@@ -14,19 +14,27 @@ The `Rc` type provides shared ownership of an immutable value. Destruction is de
14
14
will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the
15
15
overhead of atomic reference counting.
16
16
17
+ The `downgrade` method can be used to create a non-owning `Weak` pointer to the box. A `Weak`
18
+ pointer can be upgraded to an `Rc` pointer, but will return `None` if the value has already been
19
+ freed.
20
+
21
+ For example, a tree with parent pointers can be represented by putting the nodes behind `Strong`
22
+ pointers, and then storing the parent pointers as `Weak` pointers.
23
+
17
24
*/
18
25
19
- use ptr:: RawPtr ;
20
- use unstable:: intrinsics:: transmute;
26
+ use cast:: transmute;
21
27
use ops:: Drop ;
22
- use kinds :: { Freeze , Send } ;
28
+ use cmp :: { Eq , Ord } ;
23
29
use clone:: { Clone , DeepClone } ;
24
- use cell:: RefCell ;
25
- use cmp:: { Eq , TotalEq , Ord , TotalOrd , Ordering } ;
30
+ use rt:: global_heap:: exchange_free;
31
+ use ptr:: read_ptr;
32
+ use option:: { Option , Some , None } ;
26
33
27
34
struct RcBox < T > {
28
35
value : T ,
29
- count : uint
36
+ strong : uint ,
37
+ weak : uint
30
38
}
31
39
32
40
/// Immutable reference counted pointer type
@@ -36,147 +44,141 @@ pub struct Rc<T> {
36
44
priv ptr: * mut RcBox < T >
37
45
}
38
46
39
- impl < T : Freeze > Rc < T > {
40
- /// Construct a new reference-counted box from a `Freeze` value
41
- #[ inline]
47
+ impl < T > Rc < T > {
48
+ /// Construct a new reference-counted box
42
49
pub fn new ( value : T ) -> Rc < T > {
43
50
unsafe {
44
- Rc :: new_unchecked ( value)
51
+ Rc { ptr : transmute ( ~ RcBox { value : value , strong : 1 , weak : 0 } ) }
45
52
}
46
53
}
47
54
}
48
55
49
- impl < T : Send > Rc < T > {
50
- /// Construct a new reference-counted box from a `Send` value
51
- #[ inline]
52
- pub fn from_send ( value : T ) -> Rc < T > {
56
+ impl < T > Rc < T > {
57
+ /// Borrow the value contained in the reference-counted box
58
+ #[ inline( always) ]
59
+ pub fn borrow < ' a > ( & ' a self ) -> & ' a T {
60
+ unsafe { & ( * self . ptr ) . value }
61
+ }
62
+
63
+ /// Downgrade the reference-counted pointer to a weak reference
64
+ pub fn downgrade ( & self ) -> Weak < T > {
53
65
unsafe {
54
- Rc :: new_unchecked ( value)
66
+ ( * self . ptr ) . weak += 1 ;
67
+ Weak { ptr : self . ptr }
55
68
}
56
69
}
57
70
}
58
71
59
- impl < T : Freeze > Rc < RefCell < T > > {
60
- /// Construct a new reference-counted box from a `RefCell`-wrapped `Freeze` value
61
- #[ inline]
62
- pub fn from_mut ( value : RefCell < T > ) -> Rc < RefCell < T > > {
72
+ #[ unsafe_destructor]
73
+ impl < T > Drop for Rc < T > {
74
+ fn drop ( & mut self ) {
63
75
unsafe {
64
- Rc :: new_unchecked ( value)
76
+ if self . ptr != 0 as * mut RcBox < T > {
77
+ ( * self . ptr ) . strong -= 1 ;
78
+ if ( * self . ptr ) . strong == 0 {
79
+ read_ptr ( self . borrow ( ) ) ; // destroy the contained object
80
+ if ( * self . ptr ) . weak == 0 {
81
+ exchange_free ( self . ptr as * mut u8 as * i8 )
82
+ }
83
+ }
84
+ }
65
85
}
66
86
}
67
87
}
68
88
69
- impl < T > Rc < T > {
70
- /// Unsafety construct a new reference-counted box from any value.
71
- ///
72
- /// It is possible to create cycles, which will leak, and may interact
73
- /// poorly with managed pointers.
74
- #[ inline]
75
- pub unsafe fn new_unchecked ( value : T ) -> Rc < T > {
76
- Rc { ptr : transmute ( ~RcBox { value : value, count : 1 } ) }
77
- }
78
-
79
- /// Borrow the value contained in the reference-counted box
89
+ impl < T > Clone for Rc < T > {
80
90
#[ inline]
81
- pub fn borrow < ' r > ( & ' r self ) -> & ' r T {
82
- unsafe { & ( * self . ptr ) . value }
91
+ fn clone ( & self ) -> Rc < T > {
92
+ unsafe {
93
+ ( * self . ptr ) . strong += 1 ;
94
+ Rc { ptr : self . ptr }
95
+ }
83
96
}
97
+ }
84
98
85
- /// Determine if two reference-counted pointers point to the same object
99
+ impl < T : DeepClone > DeepClone for Rc < T > {
86
100
#[ inline]
87
- pub fn ptr_eq ( & self , other : & Rc < T > ) -> bool {
88
- self . ptr == other . ptr
101
+ fn deep_clone ( & self ) -> Rc < T > {
102
+ Rc :: new ( self . borrow ( ) . deep_clone ( ) )
89
103
}
90
104
}
91
105
92
106
impl < T : Eq > Eq for Rc < T > {
93
- #[ inline]
94
- fn eq ( & self , other : & Rc < T > ) -> bool {
95
- unsafe { ( * self . ptr ) . value == ( * other. ptr ) . value }
96
- }
107
+ #[ inline( always) ]
108
+ fn eq ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) == * other. borrow ( ) }
97
109
98
- #[ inline]
99
- fn ne ( & self , other : & Rc < T > ) -> bool {
100
- unsafe { ( * self . ptr ) . value != ( * other. ptr ) . value }
101
- }
102
- }
103
-
104
- impl < T : TotalEq > TotalEq for Rc < T > {
105
- #[ inline]
106
- fn equals ( & self , other : & Rc < T > ) -> bool {
107
- unsafe { ( * self . ptr ) . value . equals ( & ( * other. ptr ) . value ) }
108
- }
110
+ #[ inline( always) ]
111
+ fn ne ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) != * other. borrow ( ) }
109
112
}
110
113
111
114
impl < T : Ord > Ord for Rc < T > {
112
- #[ inline]
113
- fn lt ( & self , other : & Rc < T > ) -> bool {
114
- unsafe { ( * self . ptr ) . value < ( * other. ptr ) . value }
115
- }
115
+ #[ inline( always) ]
116
+ fn lt ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) < * other. borrow ( ) }
116
117
117
- #[ inline]
118
- fn le ( & self , other : & Rc < T > ) -> bool {
119
- unsafe { ( * self . ptr ) . value <= ( * other. ptr ) . value }
120
- }
118
+ #[ inline( always) ]
119
+ fn le ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) <= * other. borrow ( ) }
121
120
122
- #[ inline]
123
- fn ge ( & self , other : & Rc < T > ) -> bool {
124
- unsafe { ( * self . ptr ) . value >= ( * other. ptr ) . value }
125
- }
121
+ #[ inline( always) ]
122
+ fn gt ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) > * other. borrow ( ) }
126
123
127
- #[ inline]
128
- fn gt ( & self , other : & Rc < T > ) -> bool {
129
- unsafe { ( * self . ptr ) . value > ( * other. ptr ) . value }
130
- }
124
+ #[ inline( always) ]
125
+ fn ge ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) >= * other. borrow ( ) }
131
126
}
132
127
133
- impl < T : TotalOrd > TotalOrd for Rc < T > {
134
- # [ inline ]
135
- fn cmp ( & self , other : & Rc < T > ) -> Ordering {
136
- unsafe { ( * self . ptr ) . value . cmp ( & ( * other . ptr ) . value ) }
137
- }
128
+ /// Weak reference to a reference-counted box
129
+ # [ unsafe_no_drop_flag ]
130
+ # [ no_send ]
131
+ pub struct Weak < T > {
132
+ priv ptr : * mut RcBox < T >
138
133
}
139
134
140
- impl < T > Clone for Rc < T > {
141
- # [ inline ]
142
- fn clone ( & self ) -> Rc < T > {
135
+ impl < T > Weak < T > {
136
+ /// Upgrade a weak reference to a strong reference
137
+ pub fn upgrade ( & self ) -> Option < Rc < T > > {
143
138
unsafe {
144
- ( * self . ptr ) . count += 1 ;
145
- Rc { ptr : self . ptr }
139
+ if ( * self . ptr ) . strong == 0 {
140
+ None
141
+ } else {
142
+ ( * self . ptr ) . strong += 1 ;
143
+ Some ( Rc { ptr : self . ptr } )
144
+ }
146
145
}
147
146
}
148
147
}
149
148
150
- impl < T : DeepClone > DeepClone for Rc < T > {
151
- #[ inline]
152
- fn deep_clone ( & self ) -> Rc < T > {
153
- unsafe { Rc :: new_unchecked ( self . borrow ( ) . deep_clone ( ) ) }
154
- }
155
- }
156
-
157
149
#[ unsafe_destructor]
158
- impl < T > Drop for Rc < T > {
150
+ impl < T > Drop for Weak < T > {
159
151
fn drop ( & mut self ) {
160
152
unsafe {
161
- if self . ptr . is_not_null ( ) {
162
- ( * self . ptr ) . count -= 1 ;
163
- if ( * self . ptr ) . count == 0 {
164
- let _ : ~ RcBox < T > = transmute ( self . ptr ) ;
153
+ if self . ptr != 0 as * mut RcBox < T > {
154
+ ( * self . ptr ) . weak -= 1 ;
155
+ if ( * self . ptr ) . weak == 0 && ( * self . ptr ) . strong == 0 {
156
+ exchange_free ( self . ptr as * mut u8 as * i8 )
165
157
}
166
158
}
167
159
}
168
160
}
169
161
}
170
162
163
+ impl < T > Clone for Weak < T > {
164
+ #[ inline]
165
+ fn clone ( & self ) -> Weak < T > {
166
+ unsafe {
167
+ ( * self . ptr ) . weak += 1 ;
168
+ Weak { ptr : self . ptr }
169
+ }
170
+ }
171
+ }
172
+
171
173
#[ cfg( test) ]
172
- mod test_rc {
174
+ mod tests {
173
175
use prelude:: * ;
174
176
use super :: * ;
175
177
use cell:: RefCell ;
176
178
177
179
#[ test]
178
180
fn test_clone ( ) {
179
- let x = Rc :: from_send ( RefCell :: new ( 5 ) ) ;
181
+ let x = Rc :: new ( RefCell :: new ( 5 ) ) ;
180
182
let y = x. clone ( ) ;
181
183
x. borrow ( ) . with_mut ( |inner| {
182
184
* inner = 20 ;
@@ -186,7 +188,7 @@ mod test_rc {
186
188
187
189
#[ test]
188
190
fn test_deep_clone ( ) {
189
- let x = Rc :: from_send ( RefCell :: new ( 5 ) ) ;
191
+ let x = Rc :: new ( RefCell :: new ( 5 ) ) ;
190
192
let y = x. deep_clone ( ) ;
191
193
x. borrow ( ) . with_mut ( |inner| {
192
194
* inner = 20 ;
@@ -210,13 +212,22 @@ mod test_rc {
210
212
211
213
#[ test]
212
214
fn test_destructor ( ) {
213
- let x = Rc :: from_send ( ~5 ) ;
215
+ let x = Rc :: new ( ~5 ) ;
214
216
assert_eq ! ( * * x. borrow( ) , 5 ) ;
215
217
}
216
218
217
219
#[ test]
218
- fn test_from_mut ( ) {
219
- let a = 10 ;
220
- let _x = Rc :: from_mut ( RefCell :: new ( & a) ) ;
220
+ fn test_live ( ) {
221
+ let x = Rc :: new ( 5 ) ;
222
+ let y = x. downgrade ( ) ;
223
+ assert ! ( y. upgrade( ) . is_some( ) ) ;
224
+ }
225
+
226
+ #[ test]
227
+ fn test_dead ( ) {
228
+ let x = Rc :: new ( 5 ) ;
229
+ let y = x. downgrade ( ) ;
230
+ drop ( x) ;
231
+ assert ! ( y. upgrade( ) . is_none( ) ) ;
221
232
}
222
233
}
0 commit comments