triomphe/
arc_borrow.rs

1use core::marker::PhantomData;
2use core::mem;
3use core::mem::ManuallyDrop;
4use core::ops::Deref;
5use core::panic::{RefUnwindSafe, UnwindSafe};
6use core::ptr::NonNull;
7
8use super::Arc;
9
10/// A "borrowed `Arc`". This is a pointer to
11/// a T that is known to have been allocated within an
12/// `Arc`.
13///
14/// This is equivalent in guarantees to `&Arc<T>`, however it is
15/// a bit more flexible. To obtain an `&Arc<T>` you must have
16/// an `Arc<T>` instance somewhere pinned down until we're done with it.
17/// It's also a direct pointer to `T`, so using this involves less pointer-chasing
18///
19/// However, C++ code may hand us refcounted things as pointers to T directly,
20/// so we have to conjure up a temporary `Arc` on the stack each time. The
21/// same happens for when the object is managed by a `OffsetArc`.
22///
23/// `ArcBorrow` lets us deal with borrows of known-refcounted objects
24/// without needing to worry about where the `Arc<T>` is.
25#[derive(Debug, Eq, PartialEq)]
26#[repr(transparent)]
27pub struct ArcBorrow<'a, T: ?Sized + 'a>(pub(crate) NonNull<T>, pub(crate) PhantomData<&'a T>);
28
29unsafe impl<'a, T: ?Sized + Sync + Send> Send for ArcBorrow<'a, T> {}
30unsafe impl<'a, T: ?Sized + Sync + Send> Sync for ArcBorrow<'a, T> {}
31
32impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for ArcBorrow<'a, T> {}
33
34impl<'a, T> Copy for ArcBorrow<'a, T> {}
35impl<'a, T> Clone for ArcBorrow<'a, T> {
36    #[inline]
37    fn clone(&self) -> Self {
38        *self
39    }
40}
41
42impl<'a, T> ArcBorrow<'a, T> {
43    /// Clone this as an `Arc<T>`. This bumps the refcount.
44    #[inline]
45    pub fn clone_arc(&self) -> Arc<T> {
46        let arc = unsafe { Arc::from_raw(self.0.as_ptr()) };
47        // addref it!
48        mem::forget(arc.clone());
49        arc
50    }
51
52    /// For constructing from a pointer known to be Arc-backed,
53    /// e.g. if we obtain such a pointer over FFI
54    ///
55    // TODO: should from_ptr be relaxed to unsized types? It can't be
56    // converted back to an Arc right now for unsized types.
57    //
58    /// # Safety
59    /// - The pointer to `T` must have come from a Triomphe `Arc`, `UniqueArc`, or `ArcBorrow`.
60    /// - The pointer to `T` must have full provenance over the `Arc`, `UniqueArc`, or `ArcBorrow`,
61    ///   in particular it must not have been derived from a `&T` reference, as references immediately
62    ///   loose all provenance over the adjacent reference counts. As of this writing,
63    ///   of the 3 types, only Trimphe's `Arc` offers a direct API for obtaining such a pointer:
64    ///   [`Arc::as_ptr`].
65    #[inline]
66    pub unsafe fn from_ptr(ptr: *const T) -> Self {
67        unsafe { ArcBorrow(NonNull::new_unchecked(ptr as *mut T), PhantomData) }
68    }
69
70    /// Compare two `ArcBorrow`s via pointer equality. Will only return
71    /// true if they come from the same allocation
72    #[inline]
73    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
74        this.0 == other.0
75    }
76
77    /// The reference count of the underlying `Arc`.
78    ///
79    /// The number does not include borrowed pointers,
80    /// or temporary `Arc` pointers created with functions like
81    /// [`ArcBorrow::with_arc`].
82    ///
83    /// The function is called `strong_count` to mirror `std::sync::Arc::strong_count`,
84    /// however `triomphe::Arc` does not support weak references.
85    #[inline]
86    pub fn strong_count(this: &Self) -> usize {
87        Self::with_arc(this, |arc| Arc::strong_count(arc))
88    }
89
90    /// Temporarily converts |self| into a bonafide Arc and exposes it to the
91    /// provided callback. The refcount is not modified.
92    #[inline]
93    pub fn with_arc<F, U>(&self, f: F) -> U
94    where
95        F: FnOnce(&Arc<T>) -> U,
96    {
97        // Synthesize transient Arc, which never touches the refcount.
98        let transient = unsafe { ManuallyDrop::new(Arc::from_raw(self.0.as_ptr())) };
99
100        // Expose the transient Arc to the callback, which may clone it if it wants
101        // and forward the result to the user
102        f(&transient)
103    }
104
105    /// Similar to deref, but uses the lifetime |a| rather than the lifetime of
106    /// self, which is incompatible with the signature of the Deref trait.
107    #[inline]
108    pub fn get(&self) -> &'a T {
109        unsafe { &*self.0.as_ptr() }
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
122// Safety:
123// This implementation must guarantee that it is sound to call replace_ptr with an unsized variant
124// of the pointer retuned in `as_sized_ptr`. We leverage unsizing the contained reference. This
125// continues to point to the data of an ArcInner. The reference count remains untouched which is
126// correct since the number of owners did not change. This implies the returned instance fulfills
127// its safety invariants.
128#[cfg(feature = "unsize")]
129unsafe impl<'lt, T: 'lt, U: ?Sized + 'lt> unsize::CoerciblePtr<U> for ArcBorrow<'lt, T> {
130    type Pointee = T;
131    type Output = ArcBorrow<'lt, U>;
132
133    fn as_sized_ptr(&mut self) -> *mut T {
134        self.0.as_ptr()
135    }
136
137    unsafe fn replace_ptr(self, new: *mut U) -> ArcBorrow<'lt, U> {
138        let inner = ManuallyDrop::new(self);
139        // Safety: backed by the same Arc that backed `self`.
140        ArcBorrow(inner.0.replace_ptr(new), PhantomData)
141    }
142}
143
144#[test]
145fn clone_arc_borrow() {
146    let x = Arc::new(42);
147    let b: ArcBorrow<'_, i32> = x.borrow_arc();
148    let y = b.clone_arc();
149    assert_eq!(x, y);
150}