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}