dioxus_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#![deny(missing_docs)]
31
32/// Error kind ported from nightly std
33pub mod error {
34    #[cfg(debug_assertions)]
35    fn locations_display(locations: &[super::Location]) -> String {
36        locations
37            .iter()
38            .map(|location| format!("  ---------------\n  {location}"))
39            .collect::<Vec<_>>()
40            .join("\n")
41    }
42    /// An error returned by [`RefCell::try_borrow`].
43    #[non_exhaustive]
44    #[derive(Debug)]
45    pub struct BorrowError {
46        /// Debug-only location of attempted borrow
47        #[cfg(debug_assertions)]
48        pub attempted_at: super::Location,
49        /// Debug-only location of all current locations
50        #[cfg(debug_assertions)]
51        pub already_borrowed_at: Vec<super::Location>,
52    }
53
54    impl std::error::Error for BorrowError {}
55
56    impl std::fmt::Display for BorrowError {
57        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58            #[cfg(debug_assertions)]
59            {
60                write!(
61                    f,
62                    "Value is already borrowed mutably, current active borrows: \n{}\n\n",
63                    locations_display(&self.already_borrowed_at)
64                )
65            }
66            #[cfg(not(debug_assertions))]
67            {
68                write!(f, "Value is already borrowed mutably")
69            }
70        }
71    }
72
73    impl std::error::Error for BorrowMutError {}
74
75    /// An error returned by [`RefCell::try_borrow_mut`].
76    #[derive(Debug)]
77    #[non_exhaustive]
78    pub struct BorrowMutError {
79        /// Debug-only location of attempted borrow
80        #[cfg(debug_assertions)]
81        pub attempted_at: super::Location,
82        /// Debug-only locations of all current borrows
83        #[cfg(debug_assertions)]
84        pub already_borrowed_at: Vec<super::Location>,
85    }
86
87    impl std::fmt::Display for BorrowMutError {
88        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89            #[cfg(debug_assertions)]
90            {
91                write!(
92                    f,
93                    "Value is already borrowed, current active borrows:\n{}\n\n",
94                    locations_display(&self.already_borrowed_at)
95                )
96            }
97            #[cfg(not(debug_assertions))]
98            {
99                write!(f, "Value is already borrowed")
100            }
101        }
102    }
103}
104
105#[cfg(debug_assertions)]
106use std::cell::RefCell as StdRefCell;
107use std::cell::{Cell, UnsafeCell};
108use std::ops::{Deref, DerefMut};
109
110/// A clone of the standard library's `RefCell` type.
111pub struct RefCell<T: ?Sized> {
112    borrow: BorrowFlag,
113    value: UnsafeCell<T>,
114}
115
116#[cfg(not(debug_assertions))]
117type Location = ();
118
119#[cfg(debug_assertions)]
120type Location = &'static std::panic::Location<'static>;
121
122/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
123#[derive(Copy, Clone, PartialEq, Eq, Debug)]
124pub enum BorrowState {
125    /// The cell is currently being read, there is at least one active `borrow`.
126    Reading,
127    /// The cell is currently being written to, there is an active `borrow_mut`.
128    Writing,
129    /// There are no outstanding borrows on this cell.
130    Unused,
131}
132
133// Values [1, MAX-1] represent the number of `Ref` active
134// (will not outgrow its range since `usize` is the size of the address space)
135struct BorrowFlag {
136    flag: Cell<usize>,
137
138    #[cfg(debug_assertions)]
139    locations: StdRefCell<Vec<Location>>,
140}
141
142const UNUSED: usize = 0;
143const WRITING: usize = !0;
144
145impl<T> RefCell<T> {
146    /// Creates a new `RefCell` containing `value`.
147    pub fn new(value: T) -> RefCell<T> {
148        RefCell {
149            borrow: BorrowFlag::new(),
150            value: UnsafeCell::new(value),
151        }
152    }
153
154    /// Consumes the `RefCell`, returning the wrapped value.
155    #[cfg_attr(debug_assertions, track_caller)]
156    pub fn into_inner(self) -> T {
157        debug_assert!(self.borrow.flag.get() == UNUSED);
158        self.value.into_inner()
159    }
160}
161
162impl<T: ?Sized> RefCell<T> {
163    /// Immutably borrows the wrapped value.
164    ///
165    /// The borrow lasts until the returned `Ref` exits scope. Multiple
166    /// immutable borrows can be taken out at the same time.
167    ///
168    /// # Panics
169    ///
170    /// Panics if the value is currently mutably borrowed.
171    #[cfg_attr(debug_assertions, inline(never))]
172    #[cfg_attr(debug_assertions, track_caller)]
173    pub fn borrow(&self) -> Ref<'_, T> {
174        match self.try_borrow() {
175            Ok(value) => value,
176            Err(message) => panic!(
177                "Borrowing {} immutably failed: {}",
178                std::any::type_name::<Self>(),
179                message
180            ),
181        }
182    }
183    /// Immutably borrows the wrapped value.
184    ///
185    /// The borrow lasts until the returned `Ref` exits scope. Multiple
186    /// immutable borrows can be taken out at the same time.
187    ///
188    /// # Panics
189    ///
190    /// Panics if the value is currently mutably borrowed.
191    #[cfg_attr(debug_assertions, inline(never))]
192    #[cfg_attr(debug_assertions, track_caller)]
193    pub fn try_borrow(&self) -> Result<Ref<'_, T>, crate::error::BorrowError> {
194        match BorrowRef::new(&self.borrow) {
195            Some(b) => Ok(Ref {
196                _value: unsafe { &*self.value.get() },
197                _borrow: b,
198            }),
199            None => {
200                #[cfg(debug_assertions)]
201                {
202                    Err(crate::error::BorrowError {
203                        attempted_at: get_caller(),
204                        already_borrowed_at: self.borrow.locations.borrow().clone(),
205                    })
206                }
207                #[cfg(not(debug_assertions))]
208                {
209                    Err(crate::error::BorrowError {})
210                }
211            }
212        }
213    }
214
215    /// Mutably borrows the wrapped value.
216    ///
217    /// The borrow lasts until the returned `RefMut` exits scope. The value
218    /// cannot be borrowed while this borrow is active.
219    ///
220    /// # Panics
221    ///
222    /// Panics if the value is currently borrowed.
223    #[cfg_attr(debug_assertions, inline(never))]
224    #[cfg_attr(debug_assertions, track_caller)]
225    pub fn borrow_mut(&self) -> RefMut<'_, T> {
226        match self.try_borrow_mut() {
227            Ok(value) => value,
228            Err(message) => panic!(
229                "Borrowing {} mutably failed: {}",
230                std::any::type_name::<Self>(),
231                message
232            ),
233        }
234    }
235
236    /// Tries borrowing the wrapped value mutably.
237    ///
238    /// The borrow lasts until the returned `RefMut` exits scope. The value
239    /// cannot be borrowed while this borrow is active.
240    ///
241    #[cfg_attr(debug_assertions, inline(never))]
242    #[cfg_attr(debug_assertions, track_caller)]
243    pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, error::BorrowMutError> {
244        match BorrowRefMut::new(&self.borrow) {
245            Some(b) => Ok(RefMut {
246                _value: unsafe { &mut *self.value.get() },
247                _borrow: b,
248            }),
249            None => {
250                #[cfg(debug_assertions)]
251                {
252                    Err(error::BorrowMutError {
253                        attempted_at: get_caller(),
254                        already_borrowed_at: self.borrow.locations.borrow().clone(),
255                    })
256                }
257                #[cfg(not(debug_assertions))]
258                {
259                    Err(error::BorrowMutError {})
260                }
261            }
262        }
263    }
264}
265
266#[cfg(not(debug_assertions))]
267impl BorrowFlag {
268    #[inline]
269    fn new() -> BorrowFlag {
270        BorrowFlag {
271            flag: Cell::new(UNUSED),
272        }
273    }
274
275    #[inline]
276    fn push(&self, _caller: Location) {}
277
278    #[inline]
279    fn pop(&self) {}
280}
281
282#[cfg(debug_assertions)]
283impl BorrowFlag {
284    fn new() -> BorrowFlag {
285        BorrowFlag {
286            flag: Cell::new(UNUSED),
287            locations: StdRefCell::new(Vec::new()),
288        }
289    }
290
291    fn push(&self, caller: Location) {
292        self.locations.borrow_mut().push(caller);
293    }
294
295    fn pop(&self) {
296        self.locations.borrow_mut().pop();
297    }
298}
299
300#[cfg(not(debug_assertions))]
301#[inline]
302fn get_caller() -> Location {}
303
304#[cfg(debug_assertions)]
305#[inline(never)]
306#[track_caller]
307fn get_caller() -> Location {
308    std::panic::Location::caller()
309}
310
311unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}
312
313impl<T: Clone> Clone for RefCell<T> {
314    #[inline]
315    fn clone(&self) -> RefCell<T> {
316        RefCell::new(self.borrow().clone())
317    }
318}
319
320impl<T: Default> Default for RefCell<T> {
321    #[inline]
322    fn default() -> RefCell<T> {
323        RefCell::new(Default::default())
324    }
325}
326
327impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
328    #[inline]
329    fn eq(&self, other: &RefCell<T>) -> bool {
330        *self.borrow() == *other.borrow()
331    }
332}
333
334impl<T: ?Sized + Eq> Eq for RefCell<T> {}
335
336struct BorrowRef<'b> {
337    borrow: &'b BorrowFlag,
338}
339
340impl<'b> BorrowRef<'b> {
341    #[cfg_attr(not(debug_assertions), inline)]
342    #[cfg_attr(debug_assertions, inline(never))]
343    #[cfg_attr(debug_assertions, track_caller)]
344    fn new(borrow: &'b BorrowFlag) -> Option<BorrowRef<'b>> {
345        let flag = borrow.flag.get();
346        if flag == WRITING {
347            return None;
348        }
349        borrow.flag.set(flag + 1);
350        borrow.push(get_caller());
351        Some(BorrowRef { borrow })
352    }
353}
354
355impl<'b> Drop for BorrowRef<'b> {
356    #[inline]
357    fn drop(&mut self) {
358        let flag = self.borrow.flag.get();
359        debug_assert!(flag != WRITING && flag != UNUSED);
360        self.borrow.flag.set(flag - 1);
361        self.borrow.pop();
362    }
363}
364
365/// Wraps a borrowed reference to a value in a `RefCell` box.
366/// A wrapper type for an immutably borrowed value from a `RefCell<T>`.
367///
368/// See the [module-level documentation](index.html) for more.
369
370pub struct Ref<'b, T: ?Sized + 'b> {
371    // FIXME #12808: strange name to try to avoid interfering with
372    // field accesses of the contained type via Deref
373    _value: &'b T,
374    _borrow: BorrowRef<'b>,
375}
376
377impl<'b, T: ?Sized + 'b> Ref<'b, T> {
378    /// Makes a new `Ref` for a component of the borrowed data.
379    ///
380    /// The `RefCell` is already immutably borrowed, so this cannot fail.
381    ///
382    /// This is an associated function that needs to be used as `Ref::map(...)`.
383    /// A method would interfere with methods of the same name on the contents
384    /// of a `RefCell` used through `Deref`.
385    ///
386    /// # Examples
387    ///
388    /// ```
389    /// use std::cell::{RefCell, Ref};
390    ///
391    /// let c = RefCell::new((5, 'b'));
392    /// let b1: Ref<'_, (u32, char)> = c.borrow();
393    /// let b2: Ref<'_, u32> = Ref::map(b1, |t| &t.0);
394    /// assert_eq!(*b2, 5)
395    /// ```
396    #[inline]
397    pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
398    where
399        F: FnOnce(&T) -> &U,
400    {
401        Ref {
402            _value: f(&*orig._value),
403            _borrow: orig._borrow,
404        }
405    }
406}
407
408impl<'b, T: ?Sized> Deref for Ref<'b, T> {
409    type Target = T;
410    fn deref(&self) -> &T {
411        self._value
412    }
413}
414
415struct BorrowRefMut<'b> {
416    borrow: &'b BorrowFlag,
417}
418
419impl<'b> BorrowRefMut<'b> {
420    #[cfg_attr(not(debug_assertions), inline)]
421    #[cfg_attr(debug_assertions, inline(never))]
422    #[cfg_attr(debug_assertions, track_caller)]
423    fn new(borrow: &'b BorrowFlag) -> Option<BorrowRefMut<'b>> {
424        if borrow.flag.get() != UNUSED {
425            return None;
426        }
427        borrow.flag.set(WRITING);
428        borrow.push(get_caller());
429        Some(BorrowRefMut { borrow })
430    }
431}
432
433impl<'b> Drop for BorrowRefMut<'b> {
434    #[inline]
435    fn drop(&mut self) {
436        debug_assert!(self.borrow.flag.get() == WRITING);
437        self.borrow.flag.set(UNUSED);
438        self.borrow.pop();
439    }
440}
441
442/// A wrapper type for a mutably borrowed value from a `RefCell<T>`.
443pub struct RefMut<'b, T: ?Sized + 'b> {
444    // FIXME #12808: strange name to try to avoid interfering with
445    // field accesses of the contained type via Deref
446    _value: &'b mut T,
447    _borrow: BorrowRefMut<'b>,
448}
449
450impl<'b, T: ?Sized + 'b> RefMut<'b, T> {
451    /// Makes a new `RefMut` for a component of the borrowed data, e.g., an enum
452    /// variant.
453    ///
454    /// The `RefCell` is already mutably borrowed, so this cannot fail.
455    ///
456    /// This is an associated function that needs to be used as
457    /// `RefMut::map(...)`. A method would interfere with methods of the same
458    /// name on the contents of a `RefCell` used through `Deref`.
459    ///
460    /// # Examples
461    ///
462    /// ```
463    /// use std::cell::{RefCell, RefMut};
464    ///
465    /// let c = RefCell::new((5, 'b'));
466    /// {
467    ///     let b1: RefMut<'_, (u32, char)> = c.borrow_mut();
468    ///     let mut b2: RefMut<'_, u32> = RefMut::map(b1, |t| &mut t.0);
469    ///     assert_eq!(*b2, 5);
470    ///     *b2 = 42;
471    /// }
472    /// assert_eq!(*c.borrow(), (42, 'b'));
473    /// ```
474    pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
475    where
476        F: FnOnce(&mut T) -> &mut U,
477    {
478        RefMut {
479            _value: f(&mut *orig._value),
480            _borrow: orig._borrow,
481        }
482    }
483}
484
485impl<'b, T: ?Sized> Deref for RefMut<'b, T> {
486    type Target = T;
487    fn deref(&self) -> &T {
488        self._value
489    }
490}
491
492impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> {
493    fn deref_mut(&mut self) -> &mut T {
494        self._value
495    }
496}
497
498#[cfg(test)]
499mod tests {
500    use super::RefCell;
501
502    #[test]
503    fn ok_borrows() {
504        let a = RefCell::new(2);
505        let b = a.borrow();
506        let c = a.borrow();
507        assert_eq!(*b, 2);
508        assert_eq!(*c, 2);
509        drop((b, c));
510
511        let mut b = a.borrow_mut();
512        assert_eq!(*b, 2);
513        *b = 4;
514        drop(b);
515
516        assert_eq!(*a.borrow(), 4);
517    }
518
519    #[test]
520    fn ok_borrows_map() {
521        let a = RefCell::new((0, 1));
522        let b = a.borrow();
523        let c = super::Ref::map(b, |v| &v.0);
524        assert_eq!(*c, 0);
525        assert!(a.try_borrow().is_ok());
526        assert!(a.try_borrow_mut().is_err());
527        drop(c);
528        assert!(a.try_borrow().is_ok());
529        assert!(a.try_borrow_mut().is_ok());
530
531        let mut b = a.borrow_mut();
532        assert_eq!(b.0, 0);
533        b.0 = 999;
534        drop(b);
535
536        assert_eq!(a.borrow().0, 999);
537    }
538
539    #[test]
540    fn ok_borrow_mut_map() {
541        let a = RefCell::new((0, 1));
542        let b = a.borrow_mut();
543        let mut c = super::RefMut::map(b, |v| &mut v.0);
544        assert_eq!(*c, 0);
545        *c = 999;
546        drop(c);
547        assert_eq!(a.try_borrow().unwrap().0, 999);
548    }
549
550    #[should_panic]
551    #[test]
552    fn bad_borrow_mut() {
553        let a = RefCell::new(2);
554        let _a = a.borrow();
555        a.borrow_mut();
556    }
557
558    #[should_panic]
559    #[test]
560    fn bad_borrow() {
561        let a = RefCell::new(2);
562        let _a = a.borrow_mut();
563        a.borrow();
564    }
565}