arc_swap/
ref_cnt.rs

1use core::mem;
2use core::ptr;
3
4use alloc::rc::Rc;
5use 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
39pub 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).
50    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.
55    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.
68    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.
73    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.
86    unsafe fn dec(ptr: *const Self::Base) {
87        drop(Self::from_ptr(ptr));
88    }
89}
90
91unsafe impl<T> RefCnt for Arc<T> {
92    type Base = T;
93    fn into_ptr(me: Arc<T>) -> *mut T {
94        Arc::into_raw(me) as *mut T
95    }
96    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    }
121    unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
122        Arc::from_raw(ptr)
123    }
124}
125
126unsafe impl<T> RefCnt for Rc<T> {
127    type Base = T;
128    fn into_ptr(me: Rc<T>) -> *mut T {
129        Rc::into_raw(me) as *mut T
130    }
131    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    }
156    unsafe fn from_ptr(ptr: *const T) -> Rc<T> {
157        Rc::from_raw(ptr)
158    }
159}
160
161unsafe impl<T: RefCnt> RefCnt for Option<T> {
162    type Base = T::Base;
163    fn into_ptr(me: Option<T>) -> *mut T::Base {
164        me.map(T::into_ptr).unwrap_or_else(ptr::null_mut)
165    }
166    fn as_ptr(me: &Option<T>) -> *mut T::Base {
167        me.as_ref().map(T::as_ptr).unwrap_or_else(ptr::null_mut)
168    }
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}