Pointers_Study_With_Core_Concepts/refcell.rs
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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
//! # Basic implementation of a RefCell mutable memory location
//! With most essential info about it
use crate::cell::MyCell;
use std::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
};
/// # Required to wrap value T in UnsafeCell
/// Because you are never allowed to cast a shared ref to an exclusive ref
/// in other way than by going through the unsafe cell.
/// # Wrapping our RefState in Cell
/// Will give us ability to mutate Enum's reference count through a shared reference
/// # Info
/// RefCell will enforce borrow rules at runtime.
/// # Common Usage
/// A fairly safe way to dynamically borrow data
/// e.g Node in a graph/tree.
pub struct MyRefCell<T> {
value: UnsafeCell<T>,
reference: MyCell<RefState>,
}
#[derive(Copy, Clone)]
pub enum RefState {
Shared(usize),
Unshared,
Exclusive,
}
impl<T> MyRefCell<T> {
pub fn new(value: T) -> Self {
MyRefCell {
value: UnsafeCell::new(value),
reference: MyCell::new(RefState::Unshared),
}
}
pub fn borrow(&self) -> Option<Ref<'_, T>> {
match self.reference.get() {
RefState::Unshared => {
self.reference.set(RefState::Shared(1));
// SAFE because there are no other refs set yet
Some(Ref { refcell: self })
// Some(unsafe { Ref { refcell: &*self } })
}
RefState::Shared(n) => {
self.reference.set(RefState::Shared(n + 1));
// SAFE because we can have multiple immutable borrows
Some(Ref { refcell: self })
// Some(unsafe { Ref { refcell: &*self } })
}
_ => None,
}
}
pub fn borrow_mut(&self) -> Option<RefMut<'_, T>> {
match self.reference.get() {
RefState::Unshared => {
// SAFE because we made sure there a no other refs yet
// we can only have one exclusive borrow
self.reference.set(RefState::Exclusive);
Some(RefMut { refcell: self })
}
_ => None,
}
}
}
/// # Ref type as output for borrow method
/// We need this type to handle decrementing shared ref count
/// after they go out of scope
pub struct Ref<'refcell, T> {
refcell: &'refcell MyRefCell<T>,
}
/// # Ref type as output for borrow_mut method
/// We need this to handle decrementing exclusive ref count
/// after they go out of scope
pub struct RefMut<'refcell, T> {
refcell: &'refcell MyRefCell<T>,
}
impl<T> Drop for Ref<'_, T> {
fn drop(&mut self) {
if let RefState::Shared(n) = self.refcell.reference.get() {
if n > 1 {
self.refcell.reference.set(RefState::Shared(n - 1));
} else {
self.refcell.reference.set(RefState::Unshared);
}
} else {
unreachable!()
}
}
}
impl<T> Deref for Ref<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// SAFE because ref is only created when there are
// no exclusive refs given out
unsafe { &*self.refcell.value.get() }
}
}
impl<T> Deref for RefMut<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// SAFE because ref is only created when there are
// no exclusive refs given out
unsafe { &*self.refcell.value.get() }
}
}
impl<T> DerefMut for RefMut<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
// SAFE because ref mut is only created when there are
// no refs given out.
// Also it enforces that there will not be any future refs given out
unsafe { &mut *self.refcell.value.get() }
}
}
impl<T> Drop for RefMut<'_, T> {
fn drop(&mut self) {
if let RefState::Exclusive = self.refcell.reference.get() {
self.refcell.reference.set(RefState::Unshared);
} else {
unreachable!()
}
}
}