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(&self, data: usize) {
104        let mut up = unsafe { self.meta_mut() };
105        up.alloc();
106        let mut ptr = up.cast_mut();
107        unsafe {
108            ptr.write(data);
109        }
110    }
111
112    /// `inner_ref` returns a reference to the internal data of a
113    /// [`RefCounter`]. Writing to the memory area if not already
114    /// allocated.
115    pub fn inner_ref<'c>(&self) -> &'c usize {
116        if self.data.is_null() {
117            &0
118        } else {
119            let ptr = self.cast_const();
120            unsafe { &*ptr }
121        }
122    }
123
124    /// `inner_mut` returns a mutable reference to the internal data
125    /// of a [`RefCounter`]. Writing to the memory area if not already
126    /// allocated.
127    pub fn inner_mut<'c>(&self) -> &'c mut usize {
128        if self.data.is_null() {
129            self.write(0);
130        }
131        let mut ptr = self.cast_mut();
132        unsafe { &mut *ptr }
133    }
134}
135impl RefCounter {
136    // private methods
137    fn cast_mut(&self) -> *mut usize {
138        self.data
139    }
140
141    fn cast_const(&self) -> *const usize {
142        self.data.cast_const()
143    }
144}
145impl From<usize> for RefCounter {
146    fn from(refs: usize) -> RefCounter {
147        let mut ref_counter = RefCounter::new();
148        ref_counter.write(refs);
149        ref_counter
150    }
151}
152impl AsRef<usize> for RefCounter {
153    fn as_ref(&self) -> &usize {
154        self.inner_ref()
155    }
156}
157impl AsMut<usize> for RefCounter {
158    fn as_mut(&mut self) -> &mut usize {
159        if self.data.is_null() {
160            self.write(0);
161        }
162        let mut ptr = self.cast_mut();
163        unsafe { &mut *ptr }
164    }
165}
166impl Deref for RefCounter {
167    type Target = usize;
168
169    fn deref(&self) -> &usize {
170        self.inner_ref()
171    }
172}
173impl DerefMut for RefCounter {
174    fn deref_mut(&mut self) -> &mut usize {
175        self.inner_mut()
176    }
177}
178
179impl Drop for RefCounter {
180    fn drop(&mut self) {
181        self.drain()
182    }
183}
184
185impl Clone for RefCounter {
186    fn clone(&self) -> RefCounter {
187        let mut clone = RefCounter::new();
188        clone.data = self.data;
189        clone
190    }
191}
192
193impl std::fmt::Debug for RefCounter {
194    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
195        write!(
196            f,
197            "{}",
198            [
199                format!("RefCounter@"),
200                format!("{:016x}", self.data.addr()),
201                format!("[data={}]", self.read()),
202            ]
203            .join("")
204        )
205    }
206}
207impl std::fmt::Display for RefCounter {
208    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
209        write!(f, "{}", self.read())
210    }
211}
212
213#[allow(invalid_reference_casting)]
214impl<'c> RefCounter {
215    /// `meta_mut` is an unsafe method that turns a "self reference"
216    /// into a mutable "self reference"
217    unsafe fn meta_mut(&'c self) -> &'c mut RefCounter {
218        unsafe {
219            let ptr = self.meta_mut_ptr();
220            let mut up = &mut *ptr;
221            std::mem::transmute::<&mut RefCounter, &'c mut RefCounter>(up)
222        }
223    }
224
225    /// `meta_mut_ptr` is an unsafe method that turns a [`*mut UniquePointer`] from a "self reference"
226    unsafe fn meta_mut_ptr(&self) -> *mut RefCounter {
227        let ptr = self as *const RefCounter;
228        unsafe {
229            let ptr: *mut RefCounter =
230                std::mem::transmute::<*const RefCounter, *mut RefCounter>(ptr);
231            ptr
232        }
233    }
234}
235
236impl AddAssign<usize> for RefCounter {
237    fn add_assign(&mut self, other: usize) {
238        self.incr_by(other)
239    }
240}
241
242impl SubAssign<usize> for RefCounter {
243    fn sub_assign(&mut self, other: usize) {
244        self.decr_by(other)
245    }
246}
247
248impl PartialOrd<usize> for RefCounter {
249    fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
250        self.read().partial_cmp(other)
251    }
252}
253
254impl PartialEq<usize> for RefCounter {
255    fn eq(&self, other: &usize) -> bool {
256        self.read().eq(other)
257    }
258}
259
260impl PartialOrd for RefCounter {
261    fn partial_cmp(&self, other: &RefCounter) -> Option<Ordering> {
262        self.read().partial_cmp(other.inner_ref())
263    }
264}
265
266impl Ord for RefCounter {
267    fn cmp(&self, other: &RefCounter) -> Ordering {
268        self.read().cmp(other.inner_ref())
269    }
270}
271
272impl PartialEq for RefCounter {
273    fn eq(&self, other: &RefCounter) -> bool {
274        self.read().eq(other.inner_ref())
275    }
276}
277
278impl Eq for RefCounter {}