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}