elysees/
arc_borrow.rs

1use core::borrow::Borrow;
2use core::ffi::c_void;
3use core::hash::{Hash, Hasher};
4use core::ops::Deref;
5use core::ptr;
6use core::ptr::NonNull;
7use core::sync::atomic;
8use core::{cmp::Ordering, marker::PhantomData};
9use core::{fmt, mem};
10
11use erasable::{Erasable, ErasablePtr};
12
13use super::{Arc, ArcInner, ArcRef};
14
15/// A "borrowed [`Arc`]". This is essentially a reference to an `ArcInner<T>`
16///
17/// This is equivalent in guarantees to [`&Arc<T>`][`Arc`], however it has the same representation as an [`Arc<T>`], minimizing pointer-chasing.
18///
19/// [`ArcBorrow`] lets us deal with borrows of known-refcounted objects
20/// without needing to worry about where the [`Arc<T>`][`Arc`] is.
21#[repr(transparent)]
22pub struct ArcBorrow<'a, T: ?Sized + 'a> {
23    pub(crate) p: ptr::NonNull<T>,
24    pub(crate) phantom: PhantomData<&'a T>,
25}
26
27impl<'a, T: ?Sized> Copy for ArcBorrow<'a, T> {}
28impl<'a, T: ?Sized> Clone for ArcBorrow<'a, T> {
29    #[inline]
30    fn clone(&self) -> Self {
31        *self
32    }
33}
34
35impl<'a, T: ?Sized> ArcBorrow<'a, T> {
36    /// Clone this as an [`Arc<T>`]. This bumps the refcount.
37    #[inline]
38    pub fn clone_arc(this: Self) -> Arc<T> {
39        let arc = unsafe { Arc::from_raw(this.p.as_ptr()) };
40        // addref it!
41        mem::forget(arc.clone());
42        arc
43    }
44
45    /// Compare two [`ArcBorrow`]s via pointer equality. Will only return
46    /// true if they come from the same allocation
47    #[inline]
48    pub fn ptr_eq(this: Self, other: Self) -> bool {
49        core::ptr::eq(this.p.as_ptr(), other.p.as_ptr())
50    }
51
52    /// Similar to deref, but uses the lifetime `'a` rather than the lifetime of
53    /// `self`, which is incompatible with the signature of the [`Deref`] trait.
54    #[inline]
55    pub fn get(&self) -> &'a T {
56        unsafe { &*(self.p.as_ptr() as *const T) }
57    }
58
59    /// Borrow this as an [`Arc`]. This does *not* bump the refcount.
60    #[inline]
61    pub fn as_arc(this: &Self) -> &Arc<T> {
62        unsafe { &*(this as *const _ as *const Arc<T>) }
63    }
64
65    /// Get the internal pointer of an [`ArcBorrow`]
66    #[inline]
67    pub fn into_raw(this: Self) -> *const T {
68        let arc = Self::as_arc(&this);
69        Arc::as_ptr(arc)
70    }
71
72    /// Construct an [`ArcBorrow`] from an internal pointer
73    ///
74    /// # Safety
75    /// This pointer must be the result of `ArcBorrow::from_raw` or `Arc::from_raw`. In the latter case, the reference count is not incremented.
76    #[inline]
77    pub unsafe fn from_raw(raw: *const T) -> Self {
78        ArcBorrow {
79            p: NonNull::new_unchecked(raw as *mut T),
80            phantom: PhantomData,
81        }
82    }
83
84    /// Gets the number of [`Arc`] pointers to this allocation
85    #[inline]
86    pub fn count(this: Self) -> usize {
87        ArcBorrow::load_count(this, atomic::Ordering::Acquire)
88    }
89
90    /// Gets the number of [`Arc`] pointers to this allocation, with a given load ordering
91    #[inline]
92    pub fn load_count(this: Self, order: atomic::Ordering) -> usize {
93        unsafe {
94            (*(ArcInner::count_ptr(this.p.as_ptr()) as *const atomic::AtomicUsize)).load(order)
95        }
96    }
97
98    /// Returns the address on the heap of the [`ArcRef`] itself -- not the `T` within it -- for memory
99    /// reporting.
100    pub fn heap_ptr(self) -> *const c_void {
101        unsafe { ArcInner::count_ptr(self.p.as_ptr()) as *const c_void }
102    }
103}
104
105impl<'a, T> ArcBorrow<'a, T> {
106    /// Borrow this as an [`ArcRef`]. This does *not* bump the refcount.
107    #[inline]
108    pub fn as_arc_ref(this: &'a ArcBorrow<'a, T>) -> &'a ArcRef<'a, T> {
109        unsafe { &*(this as *const _ as *const ArcRef<'a, T>) }
110    }
111}
112
113impl<'a, T> Deref for ArcBorrow<'a, T> {
114    type Target = T;
115
116    #[inline]
117    fn deref(&self) -> &T {
118        self.get()
119    }
120}
121
122unsafe impl<T: ?Sized + Erasable> ErasablePtr for ArcBorrow<'_, T> {
123    #[inline]
124    fn erase(this: Self) -> erasable::ErasedPtr {
125        T::erase(unsafe { ptr::NonNull::new_unchecked(ArcBorrow::into_raw(this) as *mut _) })
126    }
127
128    #[inline]
129    unsafe fn unerase(this: erasable::ErasedPtr) -> Self {
130        ArcBorrow::from_raw(T::unerase(this).as_ptr())
131    }
132}
133
134impl<'a, 'b, T, U: PartialEq<T>> PartialEq<ArcBorrow<'a, T>> for ArcBorrow<'b, U> {
135    #[inline]
136    fn eq(&self, other: &ArcBorrow<'a, T>) -> bool {
137        *(*self) == *(*other)
138    }
139
140    #[allow(clippy::partialeq_ne_impl)]
141    #[inline]
142    fn ne(&self, other: &ArcBorrow<'a, T>) -> bool {
143        *(*self) != *(*other)
144    }
145}
146
147impl<'a, 'b, T, U: PartialOrd<T>> PartialOrd<ArcBorrow<'a, T>> for ArcBorrow<'b, U> {
148    #[inline]
149    fn partial_cmp(&self, other: &ArcBorrow<'a, T>) -> Option<Ordering> {
150        (**self).partial_cmp(&**other)
151    }
152
153    #[inline]
154    fn lt(&self, other: &ArcBorrow<'a, T>) -> bool {
155        *(*self) < *(*other)
156    }
157
158    #[inline]
159    fn le(&self, other: &ArcBorrow<'a, T>) -> bool {
160        *(*self) <= *(*other)
161    }
162
163    #[inline]
164    fn gt(&self, other: &ArcBorrow<'a, T>) -> bool {
165        *(*self) > *(*other)
166    }
167
168    #[inline]
169    fn ge(&self, other: &ArcBorrow<'a, T>) -> bool {
170        *(*self) >= *(*other)
171    }
172}
173
174impl<'a, T: Ord> Ord for ArcBorrow<'a, T> {
175    #[inline]
176    fn cmp(&self, other: &ArcBorrow<'a, T>) -> Ordering {
177        (**self).cmp(&**other)
178    }
179}
180
181impl<'a, T: Eq> Eq for ArcBorrow<'a, T> {}
182
183impl<'a, T: fmt::Display> fmt::Display for ArcBorrow<'a, T> {
184    #[inline]
185    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186        fmt::Display::fmt(&**self, f)
187    }
188}
189
190impl<'a, T: fmt::Debug> fmt::Debug for ArcBorrow<'a, T> {
191    #[inline]
192    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193        fmt::Debug::fmt(&**self, f)
194    }
195}
196
197impl<T: Hash> Hash for ArcBorrow<'_, T> {
198    #[inline]
199    fn hash<H: Hasher>(&self, state: &mut H) {
200        (**self).hash(state)
201    }
202}
203
204impl<T> Borrow<T> for ArcBorrow<'_, T> {
205    #[inline]
206    fn borrow(&self) -> &T {
207        self
208    }
209}
210
211impl<T> AsRef<T> for ArcBorrow<'_, T> {
212    #[inline]
213    fn as_ref(&self) -> &T {
214        self
215    }
216}
217
218#[cfg(test)]
219mod test {
220    use super::*;
221
222    #[test]
223    fn borrow_count() {
224        let mut borrows = alloc::vec::Vec::with_capacity(100);
225        let x = Arc::new(76);
226        let y = Arc::borrow_arc(&x);
227        assert_eq!(Arc::count(&x), 1);
228        assert_eq!(ArcBorrow::count(y), 1);
229        for i in 0..100 {
230            borrows.push(x.clone());
231            assert_eq!(Arc::count(&x), i + 2);
232            assert_eq!(ArcBorrow::count(y), i + 2);
233        }
234    }
235}