1 use std::mem;
2 use std::ptr;
3 use std::rc::Rc;
4 use std::sync::Arc;
5 
6 /// A trait describing smart reference counted pointers.
7 ///
8 /// Note that in a way [`Option<Arc<T>>`][Option] is also a smart reference counted pointer, just
9 /// one that can hold NULL.
10 ///
11 /// The trait is unsafe, because a wrong implementation will break the [ArcSwapAny]
12 /// implementation and lead to UB.
13 ///
14 /// This is not actually expected for downstream crate to implement, this is just means to reuse
15 /// code for [Arc] and [`Option<Arc>`][Option] variants. However, it is theoretically possible (if
16 /// you have your own [Arc] implementation).
17 ///
18 /// It is also implemented for [Rc], but that is not considered very useful (because the
19 /// [ArcSwapAny] is not `Send` or `Sync`, therefore there's very little advantage for it to be
20 /// atomic).
21 ///
22 /// # Safety
23 ///
24 /// Aside from the obvious properties (like that incrementing and decrementing a reference count
25 /// cancel each out and that having less references tracked than how many things actually point to
26 /// the value is fine as long as the count doesn't drop to 0), it also must satisfy that if two
27 /// pointers have the same value, they point to the same object. This is specifically not true for
28 /// ZSTs, but it is true for `Arc`s of ZSTs, because they have the reference counts just after the
29 /// value. It would be fine to point to a type-erased version of the same object, though (if one
30 /// could use this trait with unsized types in the first place).
31 ///
32 /// Furthermore, the type should be Pin (eg. if the type is cloned or moved, it should still
33 /// point/deref to the same place in memory).
34 ///
35 /// [Arc]: std::sync::Arc
36 /// [Rc]: std::rc::Rc
37 /// [ArcSwapAny]: crate::ArcSwapAny
38 pub unsafe trait RefCnt: Clone {
39     /// The base type the pointer points to.
40     type Base;
41 
42     /// Converts the smart pointer into a raw pointer, without affecting the reference count.
43     ///
44     /// This can be seen as kind of freezing the pointer ‒ it'll be later converted back using
45     /// [`from_ptr`](#method.from_ptr).
46     ///
47     /// The pointer must point to the value stored (and the value must be the same as one returned
48     /// by [`as_ptr`](#method.as_ptr).
into_ptr(me: Self) -> *mut Self::Base49     fn into_ptr(me: Self) -> *mut Self::Base;
50 
51     /// Provides a view into the smart pointer as a raw pointer.
52     ///
53     /// This must not affect the reference count ‒ the pointer is only borrowed.
as_ptr(me: &Self) -> *mut Self::Base54     fn as_ptr(me: &Self) -> *mut Self::Base;
55 
56     /// Converts a raw pointer back into the smart pointer, without affecting the reference count.
57     ///
58     /// This is only called on values previously returned by [`into_ptr`](#method.into_ptr).
59     /// However, it is not guaranteed to be 1:1 relation ‒ `from_ptr` may be called more times than
60     /// `into_ptr` temporarily provided the reference count never drops under 1 during that time
61     /// (the implementation sometimes owes a reference). These extra pointers will either be
62     /// converted back using `into_ptr` or forgotten.
63     ///
64     /// # Safety
65     ///
66     /// This must not be called by code outside of this crate.
from_ptr(ptr: *const Self::Base) -> Self67     unsafe fn from_ptr(ptr: *const Self::Base) -> Self;
68 
69     /// Increments the reference count by one.
70     ///
71     /// Return the pointer to the inner thing as a side effect.
inc(me: &Self) -> *mut Self::Base72     fn inc(me: &Self) -> *mut Self::Base {
73         Self::into_ptr(Self::clone(me))
74     }
75 
76     /// Decrements the reference count by one.
77     ///
78     /// Note this is called on a raw pointer (one previously returned by
79     /// [`into_ptr`](#method.into_ptr). This may lead to dropping of the reference count to 0 and
80     /// destruction of the internal pointer.
81     ///
82     /// # Safety
83     ///
84     /// This must not be called by code outside of this crate.
dec(ptr: *const Self::Base)85     unsafe fn dec(ptr: *const Self::Base) {
86         drop(Self::from_ptr(ptr));
87     }
88 }
89 
90 unsafe impl<T> RefCnt for Arc<T> {
91     type Base = T;
into_ptr(me: Arc<T>) -> *mut T92     fn into_ptr(me: Arc<T>) -> *mut T {
93         Arc::into_raw(me) as *mut T
94     }
as_ptr(me: &Arc<T>) -> *mut T95     fn as_ptr(me: &Arc<T>) -> *mut T {
96         // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
97         // intention as
98         //
99         // me as &T as *const T as *mut T
100         //
101         // We first create a "shallow copy" of me - one that doesn't really own its ref count
102         // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
103         // Then we can use into_raw (which preserves not having the ref count).
104         //
105         // We need to "revert" the changes we did. In current std implementation, the combination
106         // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
107         // and that read shall be paired with forget to properly "close the brackets". In future
108         // versions of STD, these may become something else that's not really no-op (unlikely, but
109         // possible), so we future-proof it a bit.
110 
111         // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
112         let ptr = Arc::into_raw(unsafe { std::ptr::read(me) });
113         let ptr = ptr as *mut T;
114 
115         // SAFETY: We got the pointer from into_raw just above
116         mem::forget(unsafe { Arc::from_raw(ptr) });
117 
118         ptr
119     }
from_ptr(ptr: *const T) -> Arc<T>120     unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
121         Arc::from_raw(ptr)
122     }
123 }
124 
125 unsafe impl<T> RefCnt for Rc<T> {
126     type Base = T;
into_ptr(me: Rc<T>) -> *mut T127     fn into_ptr(me: Rc<T>) -> *mut T {
128         Rc::into_raw(me) as *mut T
129     }
as_ptr(me: &Rc<T>) -> *mut T130     fn as_ptr(me: &Rc<T>) -> *mut T {
131         // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
132         // intention as
133         //
134         // me as &T as *const T as *mut T
135         //
136         // We first create a "shallow copy" of me - one that doesn't really own its ref count
137         // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
138         // Then we can use into_raw (which preserves not having the ref count).
139         //
140         // We need to "revert" the changes we did. In current std implementation, the combination
141         // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
142         // and that read shall be paired with forget to properly "close the brackets". In future
143         // versions of STD, these may become something else that's not really no-op (unlikely, but
144         // possible), so we future-proof it a bit.
145 
146         // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
147         let ptr = Rc::into_raw(unsafe { std::ptr::read(me) });
148         let ptr = ptr as *mut T;
149 
150         // SAFETY: We got the pointer from into_raw just above
151         mem::forget(unsafe { Rc::from_raw(ptr) });
152 
153         ptr
154     }
from_ptr(ptr: *const T) -> Rc<T>155     unsafe fn from_ptr(ptr: *const T) -> Rc<T> {
156         Rc::from_raw(ptr)
157     }
158 }
159 
160 unsafe impl<T: RefCnt> RefCnt for Option<T> {
161     type Base = T::Base;
into_ptr(me: Option<T>) -> *mut T::Base162     fn into_ptr(me: Option<T>) -> *mut T::Base {
163         me.map(T::into_ptr).unwrap_or_else(ptr::null_mut)
164     }
as_ptr(me: &Option<T>) -> *mut T::Base165     fn as_ptr(me: &Option<T>) -> *mut T::Base {
166         me.as_ref().map(T::as_ptr).unwrap_or_else(ptr::null_mut)
167     }
from_ptr(ptr: *const T::Base) -> Option<T>168     unsafe fn from_ptr(ptr: *const T::Base) -> Option<T> {
169         if ptr.is_null() {
170             None
171         } else {
172             Some(T::from_ptr(ptr))
173         }
174     }
175 }
176