arc_swap/ref_cnt.rs
1use core::mem;
2#[rustversion::since(1.33)]
3use core::pin::Pin;
4use core::ptr;
5
6use crate::imports::{Arc, Rc};
7
8/// A trait describing smart reference counted pointers.
9///
10/// Note that in a way [`Option<Arc<T>>`][Option] is also a smart reference counted pointer, just
11/// one that can hold NULL.
12///
13/// The trait is unsafe, because a wrong implementation will break the [ArcSwapAny]
14/// implementation and lead to UB.
15///
16/// This is not actually expected for downstream crate to implement, this is just means to reuse
17/// code for [Arc] and [`Option<Arc>`][Option] variants. However, it is theoretically possible (if
18/// you have your own [Arc] implementation).
19///
20/// It is also implemented for [Rc], but that is not considered very useful (because the
21/// [ArcSwapAny] is not `Send` or `Sync`, therefore there's very little advantage for it to be
22/// atomic).
23///
24/// # Safety
25///
26/// Aside from the obvious properties (like that incrementing and decrementing a reference count
27/// cancel each out and that having less references tracked than how many things actually point to
28/// the value is fine as long as the count doesn't drop to 0), it also must satisfy that if two
29/// pointers have the same value, they point to the same object. This is specifically not true for
30/// ZSTs, but it is true for `Arc`s of ZSTs, because they have the reference counts just after the
31/// value. It would be fine to point to a type-erased version of the same object, though (if one
32/// could use this trait with unsized types in the first place).
33///
34/// Furthermore, the type should be Pin (eg. if the type is cloned or moved, it should still
35/// point/deref to the same place in memory).
36///
37/// [Arc]: std::sync::Arc
38/// [Rc]: std::rc::Rc
39/// [ArcSwapAny]: crate::ArcSwapAny
40pub unsafe trait RefCnt: Clone {
41 /// The base type the pointer points to.
42 type Base;
43
44 /// Converts the smart pointer into a raw pointer, without affecting the reference count.
45 ///
46 /// This can be seen as kind of freezing the pointer ‒ it'll be later converted back using
47 /// [`from_ptr`](#method.from_ptr).
48 ///
49 /// The pointer must point to the value stored (and the value must be the same as one returned
50 /// by [`as_ptr`](#method.as_ptr).
51 fn into_ptr(me: Self) -> *mut Self::Base;
52
53 /// Provides a view into the smart pointer as a raw pointer.
54 ///
55 /// This must not affect the reference count ‒ the pointer is only borrowed.
56 fn as_ptr(me: &Self) -> *mut Self::Base;
57
58 /// Converts a raw pointer back into the smart pointer, without affecting the reference count.
59 ///
60 /// This is only called on values previously returned by [`into_ptr`](#method.into_ptr).
61 /// However, it is not guaranteed to be 1:1 relation ‒ `from_ptr` may be called more times than
62 /// `into_ptr` temporarily provided the reference count never drops under 1 during that time
63 /// (the implementation sometimes owes a reference). These extra pointers will either be
64 /// converted back using `into_ptr` or forgotten.
65 ///
66 /// # Safety
67 ///
68 /// This must not be called by code outside of this crate.
69 unsafe fn from_ptr(ptr: *const Self::Base) -> Self;
70
71 /// Increments the reference count by one.
72 ///
73 /// Return the pointer to the inner thing as a side effect.
74 fn inc(me: &Self) -> *mut Self::Base {
75 Self::into_ptr(Self::clone(me))
76 }
77
78 /// Decrements the reference count by one.
79 ///
80 /// Note this is called on a raw pointer (one previously returned by
81 /// [`into_ptr`](#method.into_ptr). This may lead to dropping of the reference count to 0 and
82 /// destruction of the internal pointer.
83 ///
84 /// # Safety
85 ///
86 /// This must not be called by code outside of this crate.
87 unsafe fn dec(ptr: *const Self::Base) {
88 drop(Self::from_ptr(ptr));
89 }
90}
91
92unsafe impl<T> RefCnt for Arc<T> {
93 type Base = T;
94 fn into_ptr(me: Arc<T>) -> *mut T {
95 Arc::into_raw(me) as *mut T
96 }
97 fn as_ptr(me: &Arc<T>) -> *mut T {
98 // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
99 // intention as
100 //
101 // me as &T as *const T as *mut T
102 //
103 // We first create a "shallow copy" of me - one that doesn't really own its ref count
104 // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
105 // Then we can use into_raw (which preserves not having the ref count).
106 //
107 // We need to "revert" the changes we did. In current std implementation, the combination
108 // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
109 // and that read shall be paired with forget to properly "close the brackets". In future
110 // versions of STD, these may become something else that's not really no-op (unlikely, but
111 // possible), so we future-proof it a bit.
112
113 // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
114 let ptr = Arc::into_raw(unsafe { ptr::read(me) });
115 let ptr = ptr as *mut T;
116
117 // SAFETY: We got the pointer from into_raw just above
118 mem::forget(unsafe { Arc::from_raw(ptr) });
119
120 ptr
121 }
122 unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
123 Arc::from_raw(ptr)
124 }
125}
126
127unsafe impl<T> RefCnt for Rc<T> {
128 type Base = T;
129 fn into_ptr(me: Rc<T>) -> *mut T {
130 Rc::into_raw(me) as *mut T
131 }
132 fn as_ptr(me: &Rc<T>) -> *mut T {
133 // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
134 // intention as
135 //
136 // me as &T as *const T as *mut T
137 //
138 // We first create a "shallow copy" of me - one that doesn't really own its ref count
139 // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
140 // Then we can use into_raw (which preserves not having the ref count).
141 //
142 // We need to "revert" the changes we did. In current std implementation, the combination
143 // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
144 // and that read shall be paired with forget to properly "close the brackets". In future
145 // versions of STD, these may become something else that's not really no-op (unlikely, but
146 // possible), so we future-proof it a bit.
147
148 // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
149 let ptr = Rc::into_raw(unsafe { ptr::read(me) });
150 let ptr = ptr as *mut T;
151
152 // SAFETY: We got the pointer from into_raw just above
153 mem::forget(unsafe { Rc::from_raw(ptr) });
154
155 ptr
156 }
157 unsafe fn from_ptr(ptr: *const T) -> Rc<T> {
158 Rc::from_raw(ptr)
159 }
160}
161
162unsafe impl<T: RefCnt> RefCnt for Option<T> {
163 type Base = T::Base;
164 fn into_ptr(me: Option<T>) -> *mut T::Base {
165 me.map(T::into_ptr).unwrap_or_else(ptr::null_mut)
166 }
167 fn as_ptr(me: &Option<T>) -> *mut T::Base {
168 me.as_ref().map(T::as_ptr).unwrap_or_else(ptr::null_mut)
169 }
170 unsafe fn from_ptr(ptr: *const T::Base) -> Option<T> {
171 if ptr.is_null() {
172 None
173 } else {
174 Some(T::from_ptr(ptr))
175 }
176 }
177}
178
179// Pin is only available since Rust 1.33.
180#[rustversion::since(1.33)]
181unsafe impl<T> RefCnt for Pin<Arc<T>> {
182 type Base = T;
183
184 fn into_ptr(me: Pin<Arc<T>>) -> *mut T {
185 // SAFETY: We only expose an opaque pointer, which maintains the `Pin` invariant.
186 Arc::into_raw(unsafe { Pin::into_inner_unchecked(me) }) as *mut T
187 }
188
189 fn as_ptr(me: &Pin<Arc<T>>) -> *mut T {
190 // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
191 // intention as
192 //
193 // me as &T as *const T as *mut T
194 //
195 // We first create a "shallow copy" of me - one that doesn't really own its ref count
196 // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
197 // Then we can use into_raw (which preserves not having the ref count).
198 //
199 // We need to "revert" the changes we did. In current std implementation, the combination
200 // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
201 // and that read shall be paired with forget to properly "close the brackets". In future
202 // versions of STD, these may become something else that's not really no-op (unlikely, but
203 // possible), so we future-proof it a bit.
204
205 // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
206 // We only expose an opaque pointer, which maintains the `Pin` invariant.
207 let me = Arc::into_raw(unsafe { Pin::into_inner_unchecked(ptr::read(me)) });
208 let ptr = me as *mut T;
209
210 // SAFETY: We got the pointer from into_raw just above
211 mem::forget(unsafe { Arc::from_raw(ptr) });
212
213 ptr
214 }
215
216 unsafe fn from_ptr(ptr: *const T) -> Self {
217 // SAFETY: `ptr` came from a previous `{into_ptr,as_ptr}` call, which is pinned.
218 unsafe { Pin::new_unchecked(Arc::from_raw(ptr)) }
219 }
220}
221
222// Pin is only available since Rust 1.33.
223#[rustversion::since(1.33)]
224unsafe impl<T> RefCnt for Pin<Rc<T>> {
225 type Base = T;
226
227 fn into_ptr(me: Pin<Rc<T>>) -> *mut T {
228 // SAFETY: We only expose an opaque pointer, which maintains the `Pin` invariant.
229 Rc::into_raw(unsafe { Pin::into_inner_unchecked(me) }) as *mut T
230 }
231
232 fn as_ptr(me: &Pin<Rc<T>>) -> *mut T {
233 // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
234 // intention as
235 //
236 // me as &T as *const T as *mut T
237 //
238 // We first create a "shallow copy" of me - one that doesn't really own its ref count
239 // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
240 // Then we can use into_raw (which preserves not having the ref count).
241 //
242 // We need to "revert" the changes we did. In current std implementation, the combination
243 // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
244 // and that read shall be paired with forget to properly "close the brackets". In future
245 // versions of STD, these may become something else that's not really no-op (unlikely, but
246 // possible), so we future-proof it a bit.
247
248 // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
249 // We only expose an opaque pointer, which maintains the `Pin` invariant.
250 let me = Rc::into_raw(unsafe { Pin::into_inner_unchecked(ptr::read(me)) });
251 let ptr = me as *mut T;
252
253 // SAFETY: We got the pointer from into_raw just above
254 mem::forget(unsafe { Rc::from_raw(ptr) });
255
256 ptr
257 }
258
259 unsafe fn from_ptr(ptr: *const T) -> Self {
260 // SAFETY: `ptr` came from a previous `{into_ptr,as_ptr}` call, which is pinned.
261 unsafe { Pin::new_unchecked(Rc::from_raw(ptr)) }
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn ref_cnt_arc() {
271 struct Data(u32);
272
273 let arc = Arc::new(Data(114514));
274 let ptr = RefCnt::as_ptr(&arc);
275 assert_eq!(ptr, RefCnt::into_ptr(arc));
276
277 let arc: Arc<Data> = unsafe { RefCnt::from_ptr(ptr) };
278 assert_eq!(arc.0, 114514);
279 assert_eq!(ptr, RefCnt::as_ptr(&arc));
280 assert_eq!(ptr, RefCnt::into_ptr(arc));
281
282 // Let it drop.
283 let _: Arc<Data> = unsafe { RefCnt::from_ptr(ptr) };
284 }
285
286 // Pin is only available since Rust 1.33.
287 #[rustversion::since(1.33)]
288 mod pin {
289 use super::*;
290 use core::marker::PhantomPinned;
291
292 #[test]
293 fn ref_cnt_pin_arc() {
294 struct Unmovable {
295 value: u32,
296 _phantom: PhantomPinned,
297 }
298
299 let pinned = Arc::pin(Unmovable {
300 value: 114514,
301 _phantom: PhantomPinned,
302 });
303 let ptr = RefCnt::as_ptr(&pinned);
304 assert_eq!(ptr, RefCnt::into_ptr(pinned));
305
306 let pinned: Pin<Arc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
307 assert_eq!(pinned.value, 114514);
308 assert_eq!(ptr, RefCnt::as_ptr(&pinned));
309 assert_eq!(ptr, RefCnt::into_ptr(pinned));
310
311 // Let it drop.
312 let _: Pin<Arc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
313 }
314
315 #[test]
316 fn ref_cnt_pin_rc() {
317 struct Unmovable {
318 value: u32,
319 _phantom: PhantomPinned,
320 }
321
322 let pinned = Rc::pin(Unmovable {
323 value: 114514,
324 _phantom: PhantomPinned,
325 });
326 let ptr = RefCnt::as_ptr(&pinned);
327 assert_eq!(ptr, RefCnt::into_ptr(pinned));
328
329 let pinned: Pin<Rc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
330 assert_eq!(pinned.value, 114514);
331 assert_eq!(ptr, RefCnt::as_ptr(&pinned));
332 assert_eq!(ptr, RefCnt::into_ptr(pinned));
333
334 // Let it drop.
335 let _: Pin<Rc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
336 }
337 }
338}