1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use std::{
    mem,
    ops::{Deref, DerefMut},
    sync::atomic::{AtomicUsize, Ordering},
};

/// A mutable reference to data in a `Cell`.
///
/// Access the value via `std::ops::DerefMut` (e.g. `*val`)
#[derive(Debug)]
pub struct CellRefMut<'a, T>
where
    T: ?Sized + 'a,
{
    pub(crate) flag: &'a AtomicUsize,
    pub(crate) value: &'a mut T,
}

impl<'a, T> CellRefMut<'a, T>
where
    T: ?Sized,
{
    /// Makes a new `CellRefMut` for a component of the borrowed data which
    /// preserves the existing borrow.
    ///
    /// The `Cell` is already mutably borrowed, so this cannot fail.
    ///
    /// This is an associated function that needs to be used as
    /// `CellRefMut::map(..)`. A method would interfere with methods of the
    /// same name on the contents of a `CellRefMut` used through `DerefMut`.
    /// Further this preserves the borrow of the value and hence does the
    /// proper cleanup when it's dropped.
    ///
    /// # Examples
    ///
    /// This can also be used to avoid pointer indirection when a boxed item is
    /// stored in the `Cell`.
    ///
    /// ```rust
    /// use rt_ref::{Cell, CellRefMut};
    ///
    /// let cb = Cell::new(Box::new(5));
    ///
    /// // Borrowing the cell causes the `CellRefMut` to store a reference to the `Box`, which is a
    /// // pointer to the value on the heap, and not a reference directly to the value.
    /// let boxed_ref: CellRefMut<'_, Box<usize>> = cb.borrow_mut();
    /// assert_eq!(**boxed_ref, 5); // Notice the double deref to get the actual value.
    ///
    /// // By using `map` we can let `CellRefMut` store a reference directly to the value on the heap.
    /// let pure_ref: CellRefMut<'_, usize> = CellRefMut::map(boxed_ref, Box::as_mut);
    ///
    /// assert_eq!(*pure_ref, 5);
    /// ```
    ///
    /// We can also use `map` to get a reference to a sub-part of the borrowed
    /// value.
    ///
    /// ```rust
    /// # use rt_ref::{Cell, CellRefMut};
    ///
    /// let c = Cell::new((5, 'b'));
    ///
    /// let b1: CellRefMut<'_, (u32, char)> = c.borrow_mut();
    /// let b2: CellRefMut<'_, u32> = CellRefMut::map(b1, |t| &mut t.0);
    /// assert_eq!(*b2, 5);
    /// ```
    pub fn map<U, F>(self, f: F) -> CellRefMut<'a, U>
    where
        F: FnOnce(&mut T) -> &mut U,
        U: ?Sized,
    {
        let flag = unsafe { &*(self.flag as *const _) };
        let value = unsafe { &mut *(self.value as *mut _) };

        mem::forget(self);

        CellRefMut {
            flag,
            value: f(value),
        }
    }
}

impl<'a, T> Deref for CellRefMut<'a, T>
where
    T: ?Sized,
{
    type Target = T;

    fn deref(&self) -> &T {
        self.value
    }
}

impl<'a, T> DerefMut for CellRefMut<'a, T>
where
    T: ?Sized,
{
    fn deref_mut(&mut self) -> &mut T {
        self.value
    }
}

impl<'a, T> Drop for CellRefMut<'a, T>
where
    T: ?Sized,
{
    fn drop(&mut self) {
        self.flag.store(0, Ordering::Release)
    }
}