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)
}
}