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