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