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