rt_ref/
cell_ref_mut.rs

1use std::{
2    mem,
3    ops::{Deref, DerefMut},
4    sync::atomic::{AtomicUsize, Ordering},
5};
6
7/// A mutable reference to data in a `Cell`.
8///
9/// Access the value via `std::ops::DerefMut` (e.g. `*val`)
10#[derive(Debug)]
11pub struct CellRefMut<'a, T>
12where
13    T: ?Sized + 'a,
14{
15    pub(crate) flag: &'a AtomicUsize,
16    pub(crate) value: &'a mut T,
17}
18
19impl<'a, T> CellRefMut<'a, T>
20where
21    T: ?Sized,
22{
23    /// Makes a new `CellRefMut` for a component of the borrowed data which
24    /// preserves the existing borrow.
25    ///
26    /// The `Cell` is already mutably borrowed, so this cannot fail.
27    ///
28    /// This is an associated function that needs to be used as
29    /// `CellRefMut::map(..)`. A method would interfere with methods of the
30    /// same name on the contents of a `CellRefMut` used through `DerefMut`.
31    /// Further this preserves the borrow of the value and hence does the
32    /// proper cleanup when it's dropped.
33    ///
34    /// # Examples
35    ///
36    /// This can also be used to avoid pointer indirection when a boxed item is
37    /// stored in the `Cell`.
38    ///
39    /// ```rust
40    /// use rt_ref::{Cell, CellRefMut};
41    ///
42    /// let cb = Cell::new(Box::new(5));
43    ///
44    /// // Borrowing the cell causes the `CellRefMut` to store a reference to the `Box`, which is a
45    /// // pointer to the value on the heap, and not a reference directly to the value.
46    /// let boxed_ref: CellRefMut<'_, Box<usize>> = cb.borrow_mut();
47    /// assert_eq!(**boxed_ref, 5); // Notice the double deref to get the actual value.
48    ///
49    /// // By using `map` we can let `CellRefMut` store a reference directly to the value on the heap.
50    /// let pure_ref: CellRefMut<'_, usize> = CellRefMut::map(boxed_ref, Box::as_mut);
51    ///
52    /// assert_eq!(*pure_ref, 5);
53    /// ```
54    ///
55    /// We can also use `map` to get a reference to a sub-part of the borrowed
56    /// value.
57    ///
58    /// ```rust
59    /// # use rt_ref::{Cell, CellRefMut};
60    ///
61    /// let c = Cell::new((5, 'b'));
62    ///
63    /// let b1: CellRefMut<'_, (u32, char)> = c.borrow_mut();
64    /// let b2: CellRefMut<'_, u32> = CellRefMut::map(b1, |t| &mut t.0);
65    /// assert_eq!(*b2, 5);
66    /// ```
67    pub fn map<U, F>(self, f: F) -> CellRefMut<'a, U>
68    where
69        F: FnOnce(&mut T) -> &mut U,
70        U: ?Sized,
71    {
72        let flag = unsafe { &*(self.flag as *const _) };
73        let value = unsafe { &mut *(self.value as *mut _) };
74
75        mem::forget(self);
76
77        CellRefMut {
78            flag,
79            value: f(value),
80        }
81    }
82}
83
84impl<'a, T> Deref for CellRefMut<'a, T>
85where
86    T: ?Sized,
87{
88    type Target = T;
89
90    fn deref(&self) -> &T {
91        self.value
92    }
93}
94
95impl<'a, T> DerefMut for CellRefMut<'a, T>
96where
97    T: ?Sized,
98{
99    fn deref_mut(&mut self) -> &mut T {
100        self.value
101    }
102}
103
104impl<'a, T> Drop for CellRefMut<'a, T>
105where
106    T: ?Sized,
107{
108    fn drop(&mut self) {
109        self.flag.store(0, Ordering::Release)
110    }
111}