accountable_refcell/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5extern crate backtrace;
6
7use backtrace::Backtrace;
8use std::cell::{
9    BorrowError, BorrowMutError, Ref as StdRef, RefCell as StdRefCell, RefMut as StdRefMut,
10};
11use std::fmt::{Debug, Display, Error, Formatter};
12use std::ops::{Deref, DerefMut};
13use std::{env, mem};
14
15/// A RefCell that tracks outstanding borrows and reports stack traces for dynamic borrow failures.
16#[derive(Debug)]
17pub struct RefCell<T: ?Sized> {
18    borrows: StdRefCell<BorrowData>,
19    inner: StdRefCell<T>,
20}
21
22#[derive(Debug)]
23struct BorrowData {
24    next_id: usize,
25    borrows: Vec<BorrowRecord>,
26}
27
28#[derive(Debug)]
29struct BorrowRecord {
30    id: usize,
31    backtrace: Backtrace,
32}
33
34impl BorrowData {
35    fn record(&mut self) -> usize {
36        let id = self.next_id();
37        self.borrows.push(BorrowRecord {
38            id: id,
39            backtrace: Backtrace::new(),
40        });
41        id
42    }
43
44    fn next_id(&mut self) -> usize {
45        let id = self.next_id;
46        self.next_id = id.wrapping_add(1);
47        id
48    }
49
50    fn remove_matching_record(&mut self, id: usize) {
51        let idx = self.borrows.iter().position(|record| record.id == id);
52        self.borrows.remove(idx.expect("missing borrow record"));
53    }
54}
55
56impl<T> RefCell<T> {
57    /// Create a new RefCell value.
58    pub fn new(value: T) -> RefCell<T> {
59        RefCell {
60            inner: StdRefCell::new(value),
61            borrows: StdRefCell::new(BorrowData {
62                borrows: vec![],
63                next_id: 0,
64            }),
65        }
66    }
67
68    /// Discard this RefCell and return the value stored inside of it.
69    pub fn into_inner(self) -> T {
70        self.inner.into_inner()
71    }
72}
73
74/// An immutable reference to the value stored in a RefCell.
75pub struct Ref<'a, T: ?Sized + 'a> {
76    inner: StdRef<'a, T>,
77    data: RefBorrowData<'a>,
78}
79
80impl<'a, T: ?Sized> Ref<'a, T> {
81    /// Clone the provided Ref value. This is treated as a separate borrow record from
82    /// the original cloned reference.
83    pub fn clone(orig: &Ref<'a, T>) -> Ref<'a, T> {
84        let id = orig.data.cell.borrow_mut().record();
85        Ref {
86            inner: StdRef::clone(&orig.inner),
87            data: RefBorrowData {
88                cell: orig.data.cell,
89                id: id,
90            },
91        }
92    }
93
94    pub fn map<U: ?Sized, F>(orig: Ref<'a, T>, f: F) -> Ref<'a, U>
95    where
96        F: FnOnce(&T) -> &U,
97    {
98        Ref {
99            inner: StdRef::map(StdRef::clone(&orig.inner), f),
100            data: orig.data,
101        }
102    }
103
104    pub fn filter_map<U: ?Sized, F>(orig: Ref<'a, T>, f: F) -> Result<Ref<'a, U>, Self>
105    where
106        F: FnOnce(&T) -> Option<&U>,
107    {
108        match f(&orig).map(|new| new as *const U) {
109            Some(raw) => Ok(Ref::map(orig, |_| unsafe { &*raw })),
110            None => Err(orig),
111        }
112    }
113}
114
115impl<'a, T: ?Sized + Display> Display for Ref<'a, T> {
116    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
117        self.inner.fmt(f)
118    }
119}
120
121impl<'b, T: ?Sized + Debug> Debug for Ref<'b, T> {
122    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
123        self.inner.fmt(f)
124    }
125}
126
127impl<'a, T: ?Sized> Deref for Ref<'a, T> {
128    type Target = T;
129
130    fn deref(&self) -> &T {
131        &*self.inner
132    }
133}
134
135/// A mutable reference to the value stored in the associated RefCell.
136pub struct RefMut<'a, T: ?Sized + 'a> {
137    inner: StdRefMut<'a, T>,
138    data: RefBorrowData<'a>,
139}
140
141struct RefBorrowData<'a> {
142    cell: &'a StdRefCell<BorrowData>,
143    id: usize,
144}
145
146impl<'a> Drop for RefBorrowData<'a> {
147    fn drop(&mut self) {
148        self.cell.borrow_mut().remove_matching_record(self.id);
149    }
150}
151
152impl<'a, T: ?Sized> RefMut<'a, T> {
153    pub fn map<U: ?Sized, F>(orig: RefMut<'a, T>, f: F) -> RefMut<'a, U>
154    where
155        F: FnOnce(&mut T) -> &mut U,
156    {
157        let RefMut { inner, data } = orig;
158        RefMut {
159            inner: StdRefMut::map(inner, f),
160            data,
161        }
162    }
163
164    pub fn filter_map<U: ?Sized, F>(mut orig: RefMut<'a, T>, f: F) -> Result<RefMut<'a, U>, Self>
165    where
166        F: FnOnce(&mut T) -> Option<&mut U>,
167    {
168        match f(&mut orig).map(|new| new as *mut U) {
169            Some(raw) => Ok(RefMut::map(orig, |_| unsafe { &mut *raw })),
170            None => Err(orig),
171        }
172    }
173}
174
175impl<'a, T: ?Sized> Deref for RefMut<'a, T> {
176    type Target = T;
177
178    fn deref(&self) -> &T {
179        &*self.inner
180    }
181}
182
183impl<'a, T: ?Sized> DerefMut for RefMut<'a, T> {
184    fn deref_mut(&mut self) -> &mut T {
185        &mut *self.inner
186    }
187}
188
189impl<T: ?Sized> RefCell<T> {
190    /// Borrow the value stored in this cell immutably. Panics if any outstanding mutable
191    /// borrows of the same cell exist.
192    pub fn borrow(&self) -> Ref<'_, T> {
193        if let Ok(r) = self.inner.try_borrow() {
194            let id = self.borrows.borrow_mut().record();
195            Ref {
196                inner: r,
197                data: RefBorrowData {
198                    cell: &self.borrows,
199                    id: id,
200                },
201            }
202        } else {
203            if let Ok(var) = env::var("RUST_BACKTRACE") {
204                if !var.is_empty() {
205                    eprintln!("Outstanding borrow:");
206                    print_filtered_backtrace(&self.borrows.borrow().borrows[0].backtrace);
207                }
208            }
209            panic!("RefCell is already mutably borrowed.");
210        }
211    }
212
213    pub fn try_borrow(&self) -> Result<Ref<T>, BorrowError> {
214        self.inner.try_borrow().map(|r| {
215            let id = self.borrows.borrow_mut().record();
216            Ref {
217                inner: r,
218                data: RefBorrowData {
219                    cell: &self.borrows,
220                    id: id,
221                },
222            }
223        })
224    }
225
226    /// Borrow the value stored in this cell mutably. Panics if there are any other outstanding
227    /// borrows of this cell (mutable borrows are unique, i.e. there can only be one).
228    pub fn borrow_mut(&self) -> RefMut<T> {
229        if let Ok(r) = self.inner.try_borrow_mut() {
230            let id = self.borrows.borrow_mut().record();
231            RefMut {
232                inner: r,
233                data: RefBorrowData {
234                    cell: &self.borrows,
235                    id: id,
236                },
237            }
238        } else {
239            if let Ok(var) = env::var("RUST_BACKTRACE") {
240                if !var.is_empty() {
241                    eprintln!("Outstanding borrows:");
242                    for borrow in &*self.borrows.borrow().borrows {
243                        print_filtered_backtrace(&borrow.backtrace);
244                        eprintln!("");
245                    }
246                }
247            }
248            panic!("RefCell is already borrowed.");
249        }
250    }
251
252    pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
253        self.inner.try_borrow_mut().map(|r| {
254            let id = self.borrows.borrow_mut().record();
255            RefMut {
256                inner: r,
257                data: RefBorrowData {
258                    cell: &self.borrows,
259                    id: id,
260                },
261            }
262        })
263    }
264
265    pub fn as_ptr(&self) -> *mut T {
266        self.inner.as_ptr()
267    }
268
269    pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
270        self.inner.try_borrow_unguarded()
271    }
272}
273
274impl<T> RefCell<T> {
275    /// Corresponds to https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace.
276    pub fn replace(&self, t: T) -> T {
277        mem::replace(&mut *self.borrow_mut(), t)
278    }
279
280    /// Corresponds to https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace_with.
281    pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
282        let mut_borrow = &mut *self.borrow_mut();
283        let replacement = f(mut_borrow);
284        mem::replace(mut_borrow, replacement)
285    }
286}
287
288/// Print a backtrace without any frames from the backtrace library.
289fn print_filtered_backtrace(backtrace: &Backtrace) {
290    let mut idx = 1;
291    for frame in backtrace.frames().iter() {
292        let symbol = frame.symbols().first();
293        let repr = match symbol {
294            None => "<no-info>".to_owned(),
295            Some(symbol) => {
296                let mut repr = if let Some(name) = symbol.name() {
297                    if name.as_str().unwrap_or("").starts_with("backtrace::") {
298                        continue;
299                    }
300                    name.as_str().unwrap_or("").to_owned()
301                } else {
302                    "<unknown>".to_owned()
303                };
304                if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) {
305                    repr.push_str(&format!(" at {:?}:{}", file, line));
306                }
307                repr
308            }
309        };
310        eprintln!("{:4}: {}", idx, repr);
311        idx += 1;
312    }
313}
314
315impl<T: Clone> Clone for RefCell<T> {
316    fn clone(&self) -> RefCell<T> {
317        RefCell::new(self.borrow().clone())
318    }
319}
320
321impl<T: Default> RefCell<T> {
322    /// Corresponds to https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.take.
323    pub fn take(&self) -> T {
324        self.replace(Default::default())
325    }
326}
327
328impl<T: Default> Default for RefCell<T> {
329    fn default() -> RefCell<T> {
330        RefCell::new(Default::default())
331    }
332}
333
334impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
335    fn eq(&self, other: &RefCell<T>) -> bool {
336        *self.borrow() == *other.borrow()
337    }
338}
339
340#[deprecated(since = "0.2.2", note = "Users should instead use Ref::filter_map")]
341pub fn ref_filter_map<T: ?Sized, U: ?Sized, F: FnOnce(&T) -> Option<&U>>(
342    orig: Ref<T>,
343    f: F,
344) -> Option<Ref<U>> {
345    f(&orig)
346        .map(|new| new as *const U)
347        .map(|raw| Ref::map(orig, |_| unsafe { &*raw }))
348}
349
350#[deprecated(since = "0.2.2", note = "Users should instead use RefMut::filter_map")]
351pub fn ref_mut_filter_map<T: ?Sized, U: ?Sized, F: FnOnce(&mut T) -> Option<&mut U>>(
352    mut orig: RefMut<T>,
353    f: F,
354) -> Option<RefMut<U>> {
355    f(&mut orig)
356        .map(|new| new as *mut U)
357        .map(|raw| RefMut::map(orig, |_| unsafe { &mut *raw }))
358}
359
360#[cfg(test)]
361mod tests {
362    use super::{Ref, RefCell};
363
364    #[test]
365    #[should_panic(expected = "RefCell is already borrowed")]
366    fn cannot_borrow_mutably() {
367        let c = RefCell::new(5);
368        let _b = c.borrow();
369        let _b2 = c.borrow_mut();
370    }
371
372    #[test]
373    #[should_panic(expected = "RefCell is already mutably borrowed")]
374    fn cannot_borrow_immutably() {
375        let c = RefCell::new(5);
376        let _b = c.borrow_mut();
377        let _b2 = c.borrow();
378    }
379
380    #[test]
381    #[should_panic(expected = "RefCell is already borrowed")]
382    fn cannot_double_borrow_mut() {
383        let c = RefCell::new(5);
384        let _b = c.borrow_mut();
385        let _b2 = c.borrow_mut();
386    }
387
388    #[inline(never)]
389    fn borrow_immutably<T>(cell: &RefCell<T>) -> Ref<T> {
390        cell.borrow()
391    }
392
393    #[test]
394    #[should_panic]
395    fn cannot_borrow_mutably_multi_borrow() {
396        let c = RefCell::new(5);
397        let _b = borrow_immutably(&c);
398        let _b2 = borrow_immutably(&c);
399        let _b2 = c.borrow_mut();
400    }
401
402    #[test]
403    #[should_panic]
404    fn clone_records_borrow() {
405        let c = RefCell::new(5);
406        let _b2 = {
407            let _b = borrow_immutably(&c);
408            Ref::clone(&_b)
409        };
410        let _b2 = c.borrow_mut();
411    }
412
413    #[test]
414    fn take_refcell_returns_correct_value() {
415        let c: RefCell<i32> = RefCell::new(5);
416        assert_eq!(5, c.take());
417        assert_eq!(i32::default(), *c.borrow());
418    }
419
420    #[test]
421    #[should_panic(expected = "RefCell is already borrowed")]
422    fn cannot_take_borrowed_refcell() {
423        let c = RefCell::new(5);
424        let _b = c.borrow();
425        c.take();
426    }
427
428    #[test]
429    #[should_panic(expected = "RefCell is already borrowed")]
430    fn cannot_take_mut_borrowed_refcell() {
431        let c = RefCell::new(5);
432        let _b = c.borrow_mut();
433        c.take();
434    }
435
436    #[test]
437    fn replace_refcell_properly_replaces_contents() {
438        let c = RefCell::new(5);
439        c.replace(12);
440        assert_eq!(12, *c.borrow());
441    }
442
443    #[test]
444    #[should_panic(expected = "RefCell is already borrowed")]
445    fn cannot_replace_borrowed_refcell() {
446        let c = RefCell::new(5);
447        let _b = c.borrow();
448        c.replace(12);
449    }
450
451    #[test]
452    #[should_panic(expected = "RefCell is already borrowed")]
453    fn cannot_replace_mut_borrowed_refcell() {
454        let c = RefCell::new(5);
455        let _b = c.borrow_mut();
456        c.replace(12);
457    }
458
459    #[test]
460    fn replace_with_refcell_properly_replaces_contents() {
461        let c = RefCell::new(5);
462        c.replace_with(|&mut old_value| old_value + 1);
463        assert_eq!(6, *c.borrow());
464    }
465
466    #[test]
467    #[should_panic(expected = "RefCell is already borrowed")]
468    fn cannot_replace_with_borrowed_refcell() {
469        let c = RefCell::new(5);
470        let _b = c.borrow();
471        c.replace_with(|&mut old_val| old_val + 1);
472    }
473
474    #[test]
475    #[should_panic(expected = "RefCell is already borrowed")]
476    fn cannot_replace_with_mut_borrowed_refcell() {
477        let c = RefCell::new(5);
478        let _b = c.borrow_mut();
479        c.replace_with(|&mut old_val| old_val + 1);
480    }
481}