unique_pointer/
refcounter.rs

1use std::alloc::Layout;
2use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
3use std::convert::{AsMut, AsRef};
4use std::marker::PhantomData;
5use std::ops::{AddAssign, Deref, DerefMut, SubAssign};
6/// `RefCounter` is a data-structure designed specifically for
7/// internal use in [`unique_pointer::UniquePointer`] allowing reference counts to be
8/// shared across clones of [`unique_pointer::UniquePointer`].
9///
10/// [`RefCounter`] uses relatively obscure rust techniques under
11/// the hood to allow writing in non-mut references in strategic
12/// occasions such as incrementing its reference count within its
13/// [`Clone`] implementation.
14pub struct RefCounter {
15    data: *mut usize,
16}
17
18impl RefCounter {
19    /// `new` creates a new [`RefCounter`] with its internal state
20    /// equivalent to zero.
21    pub fn null() -> RefCounter {
22        RefCounter {
23            data: std::ptr::null_mut::<usize>(),
24        }
25    }
26
27    /// `new` creates a new [`RefCounter`] with the value 1
28    pub fn new() -> RefCounter {
29        let mut ref_counter = RefCounter::null();
30        ref_counter.incr();
31        ref_counter
32    }
33
34    /// `reset` resets a [`RefCounter`] to one which is the equivalent
35    /// state of a [`RefCounter::new`].
36    pub fn reset(&mut self) {
37        self.write(1);
38    }
39
40    /// `incr` increments the `RefCounter` by one
41    pub fn incr(&mut self) {
42        self.incr_by(1);
43    }
44
45    /// `incr_by` increments the `RefCounter`
46    pub fn incr_by(&mut self, by: usize) {
47        self.write(self.read() + by);
48    }
49
50    /// `decr` decrements the `RefCounter` by one
51    pub fn decr(&mut self) {
52        self.decr_by(1);
53    }
54
55    /// `decr_by` decrements the `RefCounter`
56    pub fn decr_by(&mut self, by: usize) {
57        let data = self.read();
58        if data >= by {
59            self.write(data - by);
60        }
61    }
62
63    /// `drain` deallocates the memory used by a [`RefCounter`]
64    /// resetting its internals so as to behave as though it has been
65    /// written `0`.
66    pub fn drain(&mut self) {
67        if !self.data.is_null() {
68            unsafe {
69                self.data.drop_in_place();
70            }
71        }
72    }
73
74    pub fn read(&self) -> usize {
75        if self.data.is_null() {
76            0
77        } else {
78            let mut ptr = self.cast_const();
79            unsafe { ptr.read() }
80        }
81    }
82
83    fn alloc(&self) {
84        if !self.data.is_null() {
85            return;
86        }
87
88        let layout = Layout::new::<usize>();
89        let ptr = unsafe {
90            let ptr = std::alloc::alloc(layout);
91            if ptr.is_null() {
92                std::alloc::handle_alloc_error(layout);
93            }
94            ptr as *mut usize
95        };
96        let mut up = unsafe { self.meta_mut() };
97        up.data = ptr;
98        up.write(1);
99    }
100
101    /// `write` writes a [`usize`] into a [`RefCounter`] as opposed to
102    /// incrementing or decrementing it.
103    pub fn write(&mut self, data: usize) {
104        self.alloc();
105        let mut ptr = self.cast_mut();
106        unsafe {
107            ptr.write(data);
108        }
109    }
110
111    /// `inner_ref` returns a reference to the internal data of a
112    /// [`RefCounter`]. Writing to the memory area if not already
113    /// allocated.
114    pub fn inner_ref<'c>(&self) -> &'c usize {
115        if self.data.is_null() {
116            &0
117        } else {
118            let ptr = self.cast_const();
119            unsafe { &*ptr }
120        }
121    }
122
123    /// `inner_mut` returns a mutable reference to the internal data
124    /// of a [`RefCounter`]. Writing to the memory area if not already
125    /// allocated.
126    pub fn inner_mut<'c>(&mut self) -> &'c mut usize {
127        if self.data.is_null() {
128            self.write(0);
129        }
130        let mut ptr = self.cast_mut();
131        unsafe { &mut *ptr }
132    }
133}
134impl RefCounter {
135    // private methods
136    fn cast_mut(&self) -> *mut usize {
137        self.data
138    }
139
140    fn cast_const(&self) -> *const usize {
141        self.data.cast_const()
142    }
143}
144impl From<usize> for RefCounter {
145    fn from(refs: usize) -> RefCounter {
146        let mut ref_counter = RefCounter::new();
147        ref_counter.write(refs);
148        ref_counter
149    }
150}
151impl AsRef<usize> for RefCounter {
152    fn as_ref(&self) -> &usize {
153        self.inner_ref()
154    }
155}
156impl AsMut<usize> for RefCounter {
157    fn as_mut(&mut self) -> &mut usize {
158        if self.data.is_null() {
159            self.write(0);
160        }
161        let mut ptr = self.cast_mut();
162        unsafe { &mut *ptr }
163    }
164}
165impl Deref for RefCounter {
166    type Target = usize;
167
168    fn deref(&self) -> &usize {
169        self.inner_ref()
170    }
171}
172impl DerefMut for RefCounter {
173    fn deref_mut(&mut self) -> &mut usize {
174        self.inner_mut()
175    }
176}
177
178impl Drop for RefCounter {
179    fn drop(&mut self) {
180        self.drain()
181    }
182}
183
184impl Clone for RefCounter {
185    fn clone(&self) -> RefCounter {
186        let mut clone = RefCounter::new();
187        clone.data = self.data;
188        clone
189    }
190}
191
192impl std::fmt::Debug for RefCounter {
193    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
194        write!(
195            f,
196            "{}",
197            [
198                format!("RefCounter@"),
199                format!("{:016x}", self.data.addr()),
200                format!("[data={}]", self.read()),
201            ]
202            .join("")
203        )
204    }
205}
206impl std::fmt::Display for RefCounter {
207    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
208        write!(f, "{}", self.read())
209    }
210}
211
212#[allow(invalid_reference_casting)]
213impl<'c> RefCounter {
214    /// `meta_mut` is an unsafe method that turns a "self reference"
215    /// into a mutable "self reference"
216    unsafe fn meta_mut(&'c self) -> &'c mut RefCounter {
217        unsafe {
218            let ptr = self.meta_mut_ptr();
219            let mut up = &mut *ptr;
220            std::mem::transmute::<&mut RefCounter, &'c mut RefCounter>(up)
221        }
222    }
223
224    /// `meta_mut_ptr` is an unsafe method that turns a [`*mut UniquePointer`] from a "self reference"
225    unsafe fn meta_mut_ptr(&self) -> *mut RefCounter {
226        let ptr = self as *const RefCounter;
227        unsafe {
228            let ptr: *mut RefCounter =
229                std::mem::transmute::<*const RefCounter, *mut RefCounter>(ptr);
230            ptr
231        }
232    }
233}
234
235impl AddAssign<usize> for RefCounter {
236    fn add_assign(&mut self, other: usize) {
237        self.incr_by(other)
238    }
239}
240
241impl SubAssign<usize> for RefCounter {
242    fn sub_assign(&mut self, other: usize) {
243        self.decr_by(other)
244    }
245}
246
247impl PartialOrd<usize> for RefCounter {
248    fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
249        self.read().partial_cmp(other)
250    }
251}
252
253impl PartialEq<usize> for RefCounter {
254    fn eq(&self, other: &usize) -> bool {
255        self.read().eq(other)
256    }
257}
258
259impl PartialOrd for RefCounter {
260    fn partial_cmp(&self, other: &RefCounter) -> Option<Ordering> {
261        self.read().partial_cmp(other.inner_ref())
262    }
263}
264
265impl Ord for RefCounter {
266    fn cmp(&self, other: &RefCounter) -> Ordering {
267        self.read().cmp(other.inner_ref())
268    }
269}
270
271impl PartialEq for RefCounter {
272    fn eq(&self, other: &RefCounter) -> bool {
273        self.read().eq(other.inner_ref())
274    }
275}
276
277impl Eq for RefCounter {}