debug_cell/
lib.rs

1// Copyright 2012-2014 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//! A clone of the standard library's `RefCell` type with extra debugging
12//! support in non-release builds.
13//!
14//! Whenever a borrow error happens the current
15//! locations of where known borrows were created will be printed out as well.
16//!
17//! # Examples
18//!
19//! ```no_run
20//! use debug_cell::RefCell;
21//!
22//! let r = RefCell::new(3);
23//! let a = r.borrow();
24//!
25//! // In debug builds this will print that the cell is currently borrowed
26//! // above, and in release builds it will behave the same as the standard
27//! // library's `RefCell`
28//! let b = r.borrow_mut();
29//! ```
30
31#![deny(missing_docs)]
32
33#[cfg(debug_assertions)]
34extern crate backtrace;
35
36#[cfg(debug_assertions)]
37use std::cell::RefCell as StdRefCell;
38use std::cell::{Cell, UnsafeCell};
39use std::ops::{Deref, DerefMut};
40
41/// A clone of the standard library's `RefCell` type.
42pub struct RefCell<T: ?Sized> {
43    borrow: BorrowFlag,
44    value: UnsafeCell<T>,
45}
46
47#[cfg(not(debug_assertions))]
48type Location = ();
49
50#[cfg(debug_assertions)]
51type Location = backtrace::Backtrace;
52
53/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
54#[derive(Copy, Clone, PartialEq, Eq, Debug)]
55pub enum BorrowState {
56    /// The cell is currently being read, there is at least one active `borrow`.
57    Reading,
58    /// The cell is currently being written to, there is an active `borrow_mut`.
59    Writing,
60    /// There are no outstanding borrows on this cell.
61    Unused,
62}
63
64// Values [1, MAX-1] represent the number of `Ref` active
65// (will not outgrow its range since `usize` is the size of the address space)
66struct BorrowFlag {
67    flag: Cell<usize>,
68
69    #[cfg(debug_assertions)]
70    locations: StdRefCell<Vec<Location>>,
71}
72
73const UNUSED: usize = 0;
74const WRITING: usize = !0;
75
76impl<T> RefCell<T> {
77    /// Creates a new `RefCell` containing `value`.
78    pub fn new(value: T) -> RefCell<T> {
79        RefCell {
80            borrow: BorrowFlag::new(),
81            value: UnsafeCell::new(value),
82        }
83    }
84
85    /// Consumes the `RefCell`, returning the wrapped value.
86    pub fn into_inner(self) -> T {
87        debug_assert!(self.borrow.flag.get() == UNUSED);
88        unsafe { self.value.into_inner() }
89    }
90}
91
92impl<T: ?Sized> RefCell<T> {
93    /// Immutably borrows the wrapped value.
94    ///
95    /// The borrow lasts until the returned `Ref` exits scope. Multiple
96    /// immutable borrows can be taken out at the same time.
97    ///
98    /// # Panics
99    ///
100    /// Panics if the value is currently mutably borrowed.
101    #[cfg_attr(debug_assertions, inline(never))]
102    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
103        match BorrowRef::new(&self.borrow) {
104            Some(b) => Ref {
105                _value: unsafe { &*self.value.get() },
106                _borrow: b,
107            },
108            None => self.panic("mutably borrowed"),
109        }
110    }
111
112    /// Mutably borrows the wrapped value.
113    ///
114    /// The borrow lasts until the returned `RefMut` exits scope. The value
115    /// cannot be borrowed while this borrow is active.
116    ///
117    /// # Panics
118    ///
119    /// Panics if the value is currently borrowed.
120    #[cfg_attr(debug_assertions, inline(never))]
121    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
122        match BorrowRefMut::new(&self.borrow) {
123            Some(b) => RefMut {
124                _value: unsafe { &mut *self.value.get() },
125                _borrow: b,
126            },
127            None => self.panic("borrowed"),
128        }
129    }
130
131    #[cfg(not(debug_assertions))]
132    fn panic(&self, msg: &str) -> ! {
133        panic!("RefCell<T> already {}", msg)
134    }
135
136    #[cfg(debug_assertions)]
137    #[allow(unused_must_use)]
138    fn panic(&self, msg: &str) -> ! {
139        let mut msg = format!("RefCell<T> already {}", msg);
140        let locations = self.borrow.locations.borrow();
141        if locations.len() > 0 {
142            msg.push_str("\ncurrent active borrows: \n");
143            for b in locations.iter() {
144                msg.push_str(&format!("-------------------------\n{:?}\n", b));
145            }
146            msg.push_str("\n\n");
147        }
148        panic!(msg)
149    }
150}
151
152#[cfg(not(debug_assertions))]
153impl BorrowFlag {
154    #[inline]
155    fn new() -> BorrowFlag {
156        BorrowFlag { flag: Cell::new(UNUSED) }
157    }
158
159    #[inline]
160    fn push(&self, _caller: Location) {}
161
162    #[inline]
163    fn pop(&self) {}
164}
165
166#[cfg(debug_assertions)]
167impl BorrowFlag {
168    fn new() -> BorrowFlag {
169        BorrowFlag {
170            flag: Cell::new(UNUSED),
171            locations: StdRefCell::new(Vec::new()),
172        }
173    }
174
175    fn push(&self, caller: Location) {
176        self.locations.borrow_mut().push(caller);
177    }
178
179    fn pop(&self) {
180        self.locations.borrow_mut().pop();
181    }
182}
183
184#[cfg(not(debug_assertions))]
185#[inline]
186fn get_caller() -> Location {}
187
188#[inline(never)]
189#[cfg(debug_assertions)]
190fn get_caller() -> Location {
191    backtrace::Backtrace::new()
192}
193
194unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}
195
196impl<T: Clone> Clone for RefCell<T> {
197    #[inline]
198    fn clone(&self) -> RefCell<T> {
199        RefCell::new(self.borrow().clone())
200    }
201}
202
203impl<T:Default> Default for RefCell<T> {
204    #[inline]
205    fn default() -> RefCell<T> {
206        RefCell::new(Default::default())
207    }
208}
209
210
211impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
212    #[inline]
213    fn eq(&self, other: &RefCell<T>) -> bool {
214        *self.borrow() == *other.borrow()
215    }
216}
217
218impl<T: ?Sized + Eq> Eq for RefCell<T> {}
219
220struct BorrowRef<'b> {
221    borrow: &'b BorrowFlag,
222}
223
224impl<'b> BorrowRef<'b> {
225    #[cfg_attr(debug_assertions, inline(never))]
226    #[cfg_attr(not(debug_assertions), inline)]
227    fn new(borrow: &'b BorrowFlag) -> Option<BorrowRef<'b>> {
228        let flag = borrow.flag.get();
229        if flag == WRITING { return None }
230        borrow.flag.set(flag + 1);
231        borrow.push(get_caller());
232        Some(BorrowRef { borrow: borrow })
233    }
234}
235
236impl<'b> Drop for BorrowRef<'b> {
237    #[inline]
238    fn drop(&mut self) {
239        let flag = self.borrow.flag.get();
240        debug_assert!(flag != WRITING && flag != UNUSED);
241        self.borrow.flag.set(flag - 1);
242        self.borrow.pop();
243    }
244}
245
246/// Wraps a borrowed reference to a value in a `RefCell` box.
247/// A wrapper type for an immutably borrowed value from a `RefCell<T>`.
248///
249/// See the [module-level documentation](index.html) for more.
250
251pub struct Ref<'b, T: ?Sized + 'b> {
252    // FIXME #12808: strange name to try to avoid interfering with
253    // field accesses of the contained type via Deref
254    _value: &'b T,
255    _borrow: BorrowRef<'b>,
256}
257
258
259impl<'b, T: ?Sized> Deref for Ref<'b, T> {
260    type Target = T;
261    fn deref(&self) -> &T {
262        self._value
263    }
264}
265
266struct BorrowRefMut<'b> {
267    borrow: &'b BorrowFlag,
268}
269
270impl<'b> BorrowRefMut<'b> {
271    #[cfg_attr(debug_assertions, inline(never))]
272    #[cfg_attr(not(debug_assertions), inline)]
273    fn new(borrow: &'b BorrowFlag) -> Option<BorrowRefMut<'b>> {
274        if borrow.flag.get() != UNUSED { return None }
275        borrow.flag.set(WRITING);
276        borrow.push(get_caller());
277        Some(BorrowRefMut { borrow: borrow })
278    }
279}
280
281impl<'b> Drop for BorrowRefMut<'b> {
282    #[inline]
283    fn drop(&mut self) {
284        debug_assert!(self.borrow.flag.get() == WRITING);
285        self.borrow.flag.set(UNUSED);
286        self.borrow.pop();
287    }
288}
289
290/// A wrapper type for a mutably borrowed value from a `RefCell<T>`.
291pub struct RefMut<'b, T: ?Sized + 'b> {
292    // FIXME #12808: strange name to try to avoid interfering with
293    // field accesses of the contained type via Deref
294    _value: &'b mut T,
295    _borrow: BorrowRefMut<'b>,
296}
297
298
299impl<'b, T: ?Sized> Deref for RefMut<'b, T> {
300    type Target = T;
301    fn deref(&self) -> &T {
302        self._value
303    }
304}
305
306impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> {
307    fn deref_mut(&mut self) -> &mut T {
308        self._value
309    }
310}
311
312#[cfg(test)]
313mod tests {
314    use super::RefCell;
315
316    #[test]
317    fn ok_borrows() {
318        let a = RefCell::new(2);
319        let b = a.borrow();
320        let c = a.borrow();
321        assert_eq!(*b, 2);
322        assert_eq!(*c, 2);
323        drop((b, c));
324
325        let mut b = a.borrow_mut();
326        assert_eq!(*b, 2);
327        *b = 4;
328        drop(b);
329
330        assert_eq!(*a.borrow(), 4);
331    }
332
333    #[should_panic]
334    #[test]
335    fn bad_borrow_mut() {
336        let a = RefCell::new(2);
337        let _a = a.borrow();
338        a.borrow_mut();
339    }
340
341    #[should_panic]
342    #[test]
343    fn bad_borrow() {
344        let a = RefCell::new(2);
345        let _a = a.borrow_mut();
346        a.borrow();
347    }
348}