8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- //! Runtime move semantics
11
+ //! Types dealing with dynamic mutability
12
12
13
13
#[ missing_doc] ;
14
14
15
- use cast:: transmute_mut;
16
15
use prelude:: * ;
16
+ use cast;
17
+ use util:: NonCopyable ;
18
+
17
19
18
20
/*
19
21
A dynamic, mutable location.
@@ -36,7 +38,7 @@ impl<T> Cell<T> {
36
38
37
39
/// Yields the value, failing if the cell is empty.
38
40
pub fn take ( & self ) -> T {
39
- let this = unsafe { transmute_mut ( self ) } ;
41
+ let this = unsafe { cast :: transmute_mut ( self ) } ;
40
42
if this. is_empty ( ) {
41
43
fail ! ( "attempt to take an empty cell" ) ;
42
44
}
@@ -46,7 +48,7 @@ impl<T> Cell<T> {
46
48
47
49
/// Yields the value if the cell is full, or `None` if it is empty.
48
50
pub fn take_opt ( & self ) -> Option < T > {
49
- let this = unsafe { transmute_mut ( self ) } ;
51
+ let this = unsafe { cast :: transmute_mut ( self ) } ;
50
52
this. value . take ( )
51
53
}
52
54
@@ -72,3 +74,295 @@ fn test_take_empty() {
72
74
value_cell. take ( ) ;
73
75
value_cell. take ( ) ;
74
76
}
77
+
78
+
79
+ /// A mutable memory location with dynamically checked borrow rules
80
+ #[ no_freeze]
81
+ pub struct RefCell < T > {
82
+ priv value : T ,
83
+ priv borrow : BorrowFlag ,
84
+ priv nc: NonCopyable
85
+ }
86
+
87
+ // Values [1, MAX-1] represent the number of `Ref` active
88
+ // (will not outgrow its range since `uint` is the size of the address space)
89
+ type BorrowFlag = uint ;
90
+ static UNUSED : BorrowFlag = 0 ;
91
+ static WRITING : BorrowFlag = -1 ;
92
+
93
+ impl < T > RefCell < T > {
94
+ /// Create a new `RefCell` containing `value`
95
+ pub fn new ( value : T ) -> RefCell < T > {
96
+ RefCell {
97
+ value : value,
98
+ borrow : UNUSED ,
99
+ nc : NonCopyable
100
+ }
101
+ }
102
+
103
+ /// Consumes the `RefCell`, returning the wrapped value.
104
+ pub fn unwrap ( self ) -> T {
105
+ assert ! ( self . borrow == UNUSED ) ;
106
+ self . value
107
+ }
108
+
109
+ unsafe fn as_mut < ' a > ( & ' a self ) -> & ' a mut RefCell < T > {
110
+ cast:: transmute_mut ( self )
111
+ }
112
+
113
+ /// Attempts to immutably borrow the wrapped value.
114
+ ///
115
+ /// The borrow lasts until the returned `Ref` exits scope. Multiple
116
+ /// immutable borrows can be taken out at the same time.
117
+ ///
118
+ /// Returns `None` if the value is currently mutably borrowed.
119
+ pub fn try_borrow < ' a > ( & ' a self ) -> Option < Ref < ' a , T > > {
120
+ match self . borrow {
121
+ WRITING => None ,
122
+ _ => {
123
+ unsafe { self . as_mut ( ) . borrow += 1 ; }
124
+ Some ( Ref { parent : self } )
125
+ }
126
+ }
127
+ }
128
+
129
+ /// Immutably borrows the wrapped value.
130
+ ///
131
+ /// The borrow lasts until the returned `Ref` exits scope. Multiple
132
+ /// immutable borrows can be taken out at the same time.
133
+ ///
134
+ /// # Failure
135
+ ///
136
+ /// Fails if the value is currently mutably borrowed.
137
+ pub fn borrow < ' a > ( & ' a self ) -> Ref < ' a , T > {
138
+ match self . try_borrow ( ) {
139
+ Some ( ptr) => ptr,
140
+ None => fail ! ( "RefCell<T> already mutably borrowed" )
141
+ }
142
+ }
143
+
144
+ /// Mutably borrows the wrapped value.
145
+ ///
146
+ /// The borrow lasts untile the returned `RefMut` exits scope. The value
147
+ /// cannot be borrowed while this borrow is active.
148
+ ///
149
+ /// Returns `None` if the value is currently borrowed.
150
+ pub fn try_borrow_mut < ' a > ( & ' a self ) -> Option < RefMut < ' a , T > > {
151
+ match self . borrow {
152
+ UNUSED => unsafe {
153
+ let mut_self = self . as_mut ( ) ;
154
+ mut_self. borrow = WRITING ;
155
+ Some ( RefMut { parent : mut_self } )
156
+ } ,
157
+ _ => None
158
+ }
159
+ }
160
+
161
+ /// Mutably borrows the wrapped value.
162
+ ///
163
+ /// The borrow lasts untile the returned `RefMut` exits scope. The value
164
+ /// cannot be borrowed while this borrow is active.
165
+ ///
166
+ /// # Failure
167
+ ///
168
+ /// Fails if the value is currently borrowed.
169
+ pub fn borrow_mut < ' a > ( & ' a self ) -> RefMut < ' a , T > {
170
+ match self . try_borrow_mut ( ) {
171
+ Some ( ptr) => ptr,
172
+ None => fail ! ( "RefCell<T> already borrowed" )
173
+ }
174
+ }
175
+
176
+ /// Immutably borrows the wrapped value and applies `blk` to it.
177
+ ///
178
+ /// # Failure
179
+ ///
180
+ /// Fails if the value is currently mutably borrowed.
181
+ #[ inline]
182
+ pub fn with < U > ( & self , blk: |& T | -> U ) -> U {
183
+ let ptr = self . borrow ( ) ;
184
+ blk ( ptr. get ( ) )
185
+ }
186
+
187
+ /// Mutably borrows the wrapped value and applies `blk` to it.
188
+ ///
189
+ /// # Failure
190
+ ///
191
+ /// Fails if the value is currently borrowed.
192
+ #[ inline]
193
+ pub fn with_mut < U > ( & self , blk: |& mut T | -> U ) -> U {
194
+ let mut ptr = self . borrow_mut ( ) ;
195
+ blk ( ptr. get ( ) )
196
+ }
197
+ }
198
+
199
+ impl < T : Clone > Clone for RefCell < T > {
200
+ fn clone ( & self ) -> RefCell < T > {
201
+ let x = self . borrow ( ) ;
202
+ RefCell :: new ( x. get ( ) . clone ( ) )
203
+ }
204
+ }
205
+
206
+ impl < T : DeepClone > DeepClone for RefCell < T > {
207
+ fn deep_clone ( & self ) -> RefCell < T > {
208
+ let x = self . borrow ( ) ;
209
+ RefCell :: new ( x. get ( ) . deep_clone ( ) )
210
+ }
211
+ }
212
+
213
+ impl < T : Eq > Eq for RefCell < T > {
214
+ fn eq ( & self , other : & RefCell < T > ) -> bool {
215
+ let a = self . borrow ( ) ;
216
+ let b = other. borrow ( ) ;
217
+ a. get ( ) == b. get ( )
218
+ }
219
+ }
220
+
221
+ /// Wraps a borrowed reference to a value in a `RefCell` box.
222
+ pub struct Ref < ' box , T > {
223
+ priv parent : & ' box RefCell < T >
224
+ }
225
+
226
+ #[ unsafe_destructor]
227
+ impl < ' box , T > Drop for Ref < ' box , T > {
228
+ fn drop ( & mut self ) {
229
+ assert ! ( self . parent. borrow != WRITING && self . parent. borrow != UNUSED ) ;
230
+ unsafe { self . parent . as_mut ( ) . borrow -= 1 ; }
231
+ }
232
+ }
233
+
234
+ impl < ' box , T > Ref < ' box , T > {
235
+ /// Retrieve an immutable reference to the stored value.
236
+ #[ inline]
237
+ pub fn get < ' a > ( & ' a self ) -> & ' a T {
238
+ & self . parent . value
239
+ }
240
+ }
241
+
242
+ /// Wraps a mutable borrowed reference to a value in a `RefCell` box.
243
+ pub struct RefMut < ' box , T > {
244
+ priv parent : & ' box mut RefCell < T >
245
+ }
246
+
247
+ #[ unsafe_destructor]
248
+ impl < ' box , T > Drop for RefMut < ' box , T > {
249
+ fn drop ( & mut self ) {
250
+ assert ! ( self . parent. borrow == WRITING ) ;
251
+ self . parent . borrow = UNUSED ;
252
+ }
253
+ }
254
+
255
+ impl < ' box , T > RefMut < ' box , T > {
256
+ /// Retrieve a mutable reference to the stored value.
257
+ #[ inline]
258
+ pub fn get < ' a > ( & ' a mut self ) -> & ' a mut T {
259
+ & mut self . parent . value
260
+ }
261
+ }
262
+
263
+ #[ cfg( test) ]
264
+ mod test {
265
+ use super :: * ;
266
+
267
+ #[ test]
268
+ fn double_imm_borrow ( ) {
269
+ let x = RefCell :: new ( 0 ) ;
270
+ let _b1 = x. borrow ( ) ;
271
+ x. borrow ( ) ;
272
+ }
273
+
274
+ #[ test]
275
+ fn no_mut_then_imm_borrow ( ) {
276
+ let x = RefCell :: new ( 0 ) ;
277
+ let _b1 = x. borrow_mut ( ) ;
278
+ assert ! ( x. try_borrow( ) . is_none( ) ) ;
279
+ }
280
+
281
+ #[ test]
282
+ fn no_imm_then_borrow_mut ( ) {
283
+ let x = RefCell :: new ( 0 ) ;
284
+ let _b1 = x. borrow ( ) ;
285
+ assert ! ( x. try_borrow_mut( ) . is_none( ) ) ;
286
+ }
287
+
288
+ #[ test]
289
+ fn no_double_borrow_mut ( ) {
290
+ let x = RefCell :: new ( 0 ) ;
291
+ let _b1 = x. borrow_mut ( ) ;
292
+ assert ! ( x. try_borrow_mut( ) . is_none( ) ) ;
293
+ }
294
+
295
+ #[ test]
296
+ fn imm_release_borrow_mut ( ) {
297
+ let x = RefCell :: new ( 0 ) ;
298
+ {
299
+ let _b1 = x. borrow ( ) ;
300
+ }
301
+ x. borrow_mut ( ) ;
302
+ }
303
+
304
+ #[ test]
305
+ fn mut_release_borrow_mut ( ) {
306
+ let x = RefCell :: new ( 0 ) ;
307
+ {
308
+ let _b1 = x. borrow_mut ( ) ;
309
+ }
310
+ x. borrow ( ) ;
311
+ }
312
+
313
+ #[ test]
314
+ fn double_borrow_single_release_no_borrow_mut ( ) {
315
+ let x = RefCell :: new ( 0 ) ;
316
+ let _b1 = x. borrow ( ) ;
317
+ {
318
+ let _b2 = x. borrow ( ) ;
319
+ }
320
+ assert ! ( x. try_borrow_mut( ) . is_none( ) ) ;
321
+ }
322
+
323
+ #[ test]
324
+ fn with_ok ( ) {
325
+ let x = RefCell :: new ( 0 ) ;
326
+ assert_eq ! ( 1 , x. with( |x| * x+1 ) ) ;
327
+ }
328
+
329
+ #[ test]
330
+ #[ should_fail]
331
+ fn mut_borrow_with ( ) {
332
+ let x = RefCell :: new ( 0 ) ;
333
+ let _b1 = x. borrow_mut ( ) ;
334
+ x. with ( |x| * x+1 ) ;
335
+ }
336
+
337
+ #[ test]
338
+ fn borrow_with ( ) {
339
+ let x = RefCell :: new ( 0 ) ;
340
+ let _b1 = x. borrow ( ) ;
341
+ assert_eq ! ( 1 , x. with( |x| * x+1 ) ) ;
342
+ }
343
+
344
+ #[ test]
345
+ fn with_mut_ok ( ) {
346
+ let x = RefCell :: new ( 0 ) ;
347
+ x. with_mut ( |x| * x += 1 ) ;
348
+ let b = x. borrow ( ) ;
349
+ assert_eq ! ( 1 , * b. get( ) ) ;
350
+ }
351
+
352
+ #[ test]
353
+ #[ should_fail]
354
+ fn borrow_with_mut ( ) {
355
+ let x = RefCell :: new ( 0 ) ;
356
+ let _b = x. borrow ( ) ;
357
+ x. with_mut ( |x| * x += 1 ) ;
358
+ }
359
+
360
+ #[ test]
361
+ #[ should_fail]
362
+ fn discard_doesnt_unborrow ( ) {
363
+ let x = RefCell :: new ( 0 ) ;
364
+ let _b = x. borrow ( ) ;
365
+ let _ = _b;
366
+ let _b = x. borrow_mut ( ) ;
367
+ }
368
+ }
0 commit comments