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