Skip to main content

arc_swap/
ref_cnt.rs

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