@@ -14,18 +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 :: NonManaged ;
28
+ use cmp :: { Eq , Ord } ;
23
29
use clone:: { Clone , DeepClone } ;
24
- 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 } ;
25
33
26
34
struct RcBox < T > {
27
35
value : T ,
28
- count : uint
36
+ strong : uint ,
37
+ weak : uint
29
38
}
30
39
31
40
/// Immutable reference counted pointer type
@@ -35,152 +44,149 @@ pub struct Rc<T> {
35
44
priv ptr: * mut RcBox < T >
36
45
}
37
46
38
- impl < T : NonManaged > Rc < T > {
47
+ impl < T > Rc < T > {
39
48
/// Construct a new reference-counted box
40
- #[ inline]
41
49
pub fn new ( value : T ) -> Rc < T > {
42
50
unsafe {
43
- Rc { ptr : transmute ( ~RcBox { value : value, count : 1 } ) }
51
+ Rc { ptr : transmute ( ~RcBox { value : value, strong : 1 , weak : 0 } ) }
44
52
}
45
53
}
46
54
}
47
55
48
56
impl < T > Rc < T > {
49
57
/// Borrow the value contained in the reference-counted box
50
- #[ inline]
51
- pub fn borrow < ' r > ( & ' r self ) -> & ' r T {
58
+ #[ inline( always ) ]
59
+ pub fn borrow < ' a > ( & ' a self ) -> & ' a T {
52
60
unsafe { & ( * self . ptr ) . value }
53
61
}
54
62
55
- /// Determine if two reference-counted pointers point to the same object
56
- #[ inline]
57
- pub fn ptr_eq ( & self , other : & Rc < T > ) -> bool {
58
- self . ptr == other. ptr
63
+ /// Downgrade the reference-counted pointer to a weak reference
64
+ pub fn downgrade ( & self ) -> Weak < T > {
65
+ unsafe {
66
+ ( * self . ptr ) . weak += 1 ;
67
+ Weak { ptr : self . ptr }
68
+ }
59
69
}
60
70
}
61
71
62
- impl < T : Eq > Eq for Rc < T > {
63
- #[ inline]
64
- fn eq ( & self , other : & Rc < T > ) -> bool {
65
- unsafe { ( * self . ptr ) . value == ( * other. ptr ) . value }
72
+ #[ unsafe_destructor]
73
+ impl < T > Drop for Rc < T > {
74
+ fn drop ( & mut self ) {
75
+ unsafe {
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
+ }
85
+ }
66
86
}
87
+ }
67
88
89
+ impl < T > Clone for Rc < T > {
68
90
#[ inline]
69
- fn ne ( & self , other : & Rc < T > ) -> bool {
70
- unsafe { ( * self . ptr ) . value != ( * other. ptr ) . value }
91
+ fn clone ( & self ) -> Rc < T > {
92
+ unsafe {
93
+ ( * self . ptr ) . strong += 1 ;
94
+ Rc { ptr : self . ptr }
95
+ }
71
96
}
72
97
}
73
98
74
- impl < T : TotalEq > TotalEq for Rc < T > {
99
+ impl < T : DeepClone > DeepClone for Rc < T > {
75
100
#[ inline]
76
- fn equals ( & self , other : & Rc < T > ) -> bool {
77
- unsafe { ( * self . ptr ) . value . equals ( & ( * other . ptr ) . value ) }
101
+ fn deep_clone ( & self ) -> Rc < T > {
102
+ Rc :: new ( self . borrow ( ) . deep_clone ( ) )
78
103
}
79
104
}
80
105
106
+ impl < T : Eq > Eq for Rc < T > {
107
+ #[ inline( always) ]
108
+ fn eq ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) == * other. borrow ( ) }
109
+
110
+ #[ inline( always) ]
111
+ fn ne ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) != * other. borrow ( ) }
112
+ }
113
+
81
114
impl < T : Ord > Ord for Rc < T > {
82
- #[ inline]
83
- fn lt ( & self , other : & Rc < T > ) -> bool {
84
- unsafe { ( * self . ptr ) . value < ( * other. ptr ) . value }
85
- }
115
+ #[ inline( always) ]
116
+ fn lt ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) < * other. borrow ( ) }
86
117
87
- #[ inline]
88
- fn le ( & self , other : & Rc < T > ) -> bool {
89
- unsafe { ( * self . ptr ) . value <= ( * other. ptr ) . value }
90
- }
118
+ #[ inline( always) ]
119
+ fn le ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) <= * other. borrow ( ) }
91
120
92
- #[ inline]
93
- fn ge ( & self , other : & Rc < T > ) -> bool {
94
- unsafe { ( * self . ptr ) . value >= ( * other. ptr ) . value }
95
- }
121
+ #[ inline( always) ]
122
+ fn gt ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) > * other. borrow ( ) }
96
123
97
- #[ inline]
98
- fn gt ( & self , other : & Rc < T > ) -> bool {
99
- unsafe { ( * self . ptr ) . value > ( * other. ptr ) . value }
100
- }
124
+ #[ inline( always) ]
125
+ fn ge ( & self , other : & Rc < T > ) -> bool { * self . borrow ( ) >= * other. borrow ( ) }
101
126
}
102
127
103
- impl < T : TotalOrd > TotalOrd for Rc < T > {
104
- # [ inline ]
105
- fn cmp ( & self , other : & Rc < T > ) -> Ordering {
106
- unsafe { ( * self . ptr ) . value . cmp ( & ( * other . ptr ) . value ) }
107
- }
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 >
108
133
}
109
134
110
- impl < T > Clone for Rc < T > {
111
- # [ inline ]
112
- 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 > > {
113
138
unsafe {
114
- ( * self . ptr ) . count += 1 ;
115
- 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
+ }
116
145
}
117
146
}
118
147
}
119
148
120
- impl < T : NonManaged + DeepClone > DeepClone for Rc < T > {
121
- #[ inline]
122
- fn deep_clone ( & self ) -> Rc < T > {
123
- Rc :: new ( self . borrow ( ) . deep_clone ( ) )
124
- }
125
- }
126
-
127
149
#[ unsafe_destructor]
128
- impl < T > Drop for Rc < T > {
150
+ impl < T > Drop for Weak < T > {
129
151
fn drop ( & mut self ) {
130
152
unsafe {
131
- if self . ptr . is_not_null ( ) {
132
- ( * self . ptr ) . count -= 1 ;
133
- if ( * self . ptr ) . count == 0 {
134
- 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 )
135
157
}
136
158
}
137
159
}
138
160
}
139
161
}
140
162
141
- #[ cfg( test) ]
142
- mod test_rc {
143
- use prelude:: * ;
144
- use super :: * ;
145
- use cell:: RefCell ;
146
-
147
- #[ test]
148
- fn test_clone ( ) {
149
- let x = Rc :: new ( RefCell :: new ( 5 ) ) ;
150
- let y = x. clone ( ) ;
151
- x. borrow ( ) . with_mut ( |inner| {
152
- * inner = 20 ;
153
- } ) ;
154
- assert_eq ! ( y. borrow( ) . with( |v| * v) , 20 ) ;
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
+ }
155
170
}
171
+ }
156
172
157
- #[ test]
158
- fn test_deep_clone ( ) {
159
- let x = Rc :: new ( RefCell :: new ( 5 ) ) ;
160
- let y = x. deep_clone ( ) ;
161
- x. borrow ( ) . with_mut ( |inner| {
162
- * inner = 20 ;
163
- } ) ;
164
- assert_eq ! ( y. borrow( ) . with( |v| * v) , 5 ) ;
165
- }
173
+ #[ cfg( test) ]
174
+ mod tests {
175
+ use super :: * ;
176
+ use prelude:: drop;
166
177
167
178
#[ test]
168
- fn test_simple ( ) {
179
+ fn test_live ( ) {
169
180
let x = Rc :: new ( 5 ) ;
170
- assert_eq ! ( * x. borrow( ) , 5 ) ;
181
+ let y = x. downgrade ( ) ;
182
+ assert ! ( y. upgrade( ) . is_some( ) ) ;
171
183
}
172
184
173
185
#[ test]
174
- fn test_simple_clone ( ) {
186
+ fn test_dead ( ) {
175
187
let x = Rc :: new ( 5 ) ;
176
- let y = x. clone ( ) ;
177
- assert_eq ! ( * x. borrow( ) , 5 ) ;
178
- assert_eq ! ( * y. borrow( ) , 5 ) ;
179
- }
180
-
181
- #[ test]
182
- fn test_destructor ( ) {
183
- let x = Rc :: new ( ~5 ) ;
184
- assert_eq ! ( * * x. borrow( ) , 5 ) ;
188
+ let y = x. downgrade ( ) ;
189
+ drop ( x) ;
190
+ assert ! ( y. upgrade( ) . is_none( ) ) ;
185
191
}
186
192
}
0 commit comments