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