Skip to main content

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>(
28    // Safety invariant: `0` is non-null, properly aligned, and points to the
29    // initialized `data: T` field of a live `ArcInner<T>` allocation that stays
30    // alive with strong count >= 1 for at least lifetime `'a`. `0` retains full
31    // provenance over the entire `ArcInner<T>` allocation (never derived from a
32    // narrowed `&T` reference).
33    pub(crate) NonNull<T>,
34    pub(crate) PhantomData<&'a T>,
35);
36
37// SAFETY:
38// `ArcBorrow<'a, T>` is semantically equivalent to `&'a Arc<T>`: sending it to
39// another thread permits reading `&'a T` (`T: Sync`) and cloning an owned
40// `Arc<T>` that may later be dropped on that thread (`T: Send`).
41unsafe impl<'a, T: ?Sized + Sync + Send> Send for ArcBorrow<'a, T> {}
42
43// SAFETY:
44// Sharing `&ArcBorrow<'a, T>` across threads permits copying `ArcBorrow<'a, T>`
45// and either dereferencing `&'a T` (`T: Sync`) or cloning an `Arc<T>` (`T: Send`).
46unsafe impl<'a, T: ?Sized + Sync + Send> Sync for ArcBorrow<'a, T> {}
47
48impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for ArcBorrow<'a, T> {}
49
50impl<'a, T: ?Sized> Copy for ArcBorrow<'a, T> {}
51impl<'a, T: ?Sized> Clone for ArcBorrow<'a, T> {
52    #[inline]
53    fn clone(&self) -> Self {
54        *self
55    }
56}
57
58impl<'a, T: ?Sized> ArcBorrow<'a, T> {
59    /// Clone this as an `Arc<T>`. This bumps the refcount.
60    #[inline]
61    pub fn clone_arc(&self) -> Arc<T> {
62        // SAFETY:
63        // By `ArcBorrow`'s field invariant, `self.0.as_ptr()` points to the
64        // `data` field of a live `ArcInner<T>` with full allocation provenance.
65        // Reconstructing `arc` via `Arc::from_raw` without incrementing the
66        // reference count is balanced by immediately cloning `arc` (which
67        // increments the strong count) and forgetting the clone via
68        // `mem::forget` (which cannot panic), leaving the returned `Arc<T>`
69        // with its own incremented strong reference.
70        let arc = unsafe { Arc::from_raw(self.0.as_ptr()) };
71        // addref it!
72        mem::forget(arc.clone());
73        arc
74    }
75
76    /// Returns the raw pointer to `T`.
77    ///
78    /// This pointer retains full provenance over the entire `ArcInner` allocation,
79    /// and thus can be safely passed to [`Arc::from_raw`].
80    #[inline]
81    pub const fn to_raw(this: &Self) -> *const T {
82        this.0.as_ptr()
83    }
84
85    /// For constructing from a pointer known to be Arc-backed,
86    /// e.g. if we obtain such a pointer over FFI
87    ///
88    /// # Safety
89    /// - The pointer to `T` must have come from a Triomphe `Arc`, `UniqueArc`, or `ArcBorrow`
90    ///   that remains live (strong count >= 1) for the entire lifetime `'a`, and `T` must not
91    ///   be mutably accessed for the duration of `'a`.
92    /// - The pointer to `T` must have full provenance over the `Arc`, `UniqueArc`, or `ArcBorrow`,
93    ///   in particular it must not have been derived from a `&T` reference, as references immediately
94    ///   lose all provenance over the adjacent reference counts. Triomphe's `Arc` and `ArcBorrow`
95    ///   offer direct APIs for obtaining such a pointer: [`Arc::as_ptr`], [`Arc::into_raw`], and [`ArcBorrow::to_raw`].
96    #[inline]
97    pub const unsafe fn from_ptr(ptr: *const T) -> Self {
98        // SAFETY:
99        // By this function's `# Safety` precondition, `ptr` came from a live
100        // `Arc`, `UniqueArc`, or `ArcBorrow` (and is therefore non-null and
101        // aligned for `T`), remains live for `'a`, and retains full provenance
102        // over the `ArcInner<T>` allocation.
103        unsafe { ArcBorrow(NonNull::new_unchecked(ptr as *mut T), PhantomData) }
104    }
105
106    /// Compare two `ArcBorrow`s via pointer equality. Will only return
107    /// true if they come from the same allocation
108    #[inline]
109    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
110        core::ptr::addr_eq(this.0.as_ptr(), other.0.as_ptr())
111    }
112
113    /// The reference count of the underlying `Arc`.
114    ///
115    /// The number does not include borrowed pointers,
116    /// or temporary `Arc` pointers created with functions like
117    /// [`ArcBorrow::with_arc`].
118    ///
119    /// The function is called `strong_count` to mirror `std::sync::Arc::strong_count`,
120    /// however `triomphe::Arc` does not support weak references.
121    #[inline]
122    pub fn strong_count(this: &Self) -> usize {
123        Self::with_arc(this, |arc| Arc::strong_count(arc))
124    }
125
126    /// Temporarily converts |self| into a bonafide Arc and exposes it to the
127    /// provided callback. The refcount is not modified.
128    #[inline]
129    pub fn with_arc<F, U>(&self, f: F) -> U
130    where
131        F: FnOnce(&Arc<T>) -> U,
132    {
133        // Synthesize transient Arc, which never touches the refcount.
134        //
135        // SAFETY:
136        // By `ArcBorrow`'s field invariant, `self.0.as_ptr()` points to the
137        // `data` field of a live `ArcInner<T>` with full allocation provenance
138        // for at least `'a`. Wrapping the reconstructed `Arc<T>` in
139        // `ManuallyDrop` ensures the borrowed strong reference count is not
140        // decremented when `with_arc` returns or if `f` unwinds.
141        let transient = unsafe { ManuallyDrop::new(Arc::from_raw(self.0.as_ptr())) };
142
143        // Expose the transient Arc to the callback, which may clone it if it wants
144        // and forward the result to the user
145        f(&transient)
146    }
147
148    /// Similar to deref, but uses the lifetime |a| rather than the lifetime of
149    /// self, which is incompatible with the signature of the Deref trait.
150    #[inline]
151    pub const fn get(&self) -> &'a T {
152        // SAFETY:
153        // By `ArcBorrow`'s field invariant, `self.0` is non-null, aligned, and
154        // points to an initialized `T` in an `ArcInner<T>` allocation that
155        // remains live and immutably shared for `'a`.
156        unsafe { &*self.0.as_ptr() }
157    }
158}
159
160impl<'a, T: ?Sized> Deref for ArcBorrow<'a, T> {
161    type Target = T;
162
163    #[inline]
164    fn deref(&self) -> &T {
165        self.get()
166    }
167}
168
169// SAFETY:
170// This implementation must guarantee that it is sound to call `replace_ptr` with an unsized variant
171// of the pointer returned in `as_sized_ptr`. By `CoerciblePtr::replace_ptr`'s contract, `new` has
172// the same address and provenance as `self.0` with unsized metadata for `U`. This continues to
173// point to the `data` field of the same live `ArcInner` for `'lt`, and the reference count remains
174// untouched since the number of owners did not change.
175#[cfg(feature = "unsize")]
176unsafe impl<'lt, T: 'lt, U: ?Sized + 'lt> unsize::CoerciblePtr<U> for ArcBorrow<'lt, T> {
177    type Pointee = T;
178    type Output = ArcBorrow<'lt, U>;
179
180    fn as_sized_ptr(&mut self) -> *mut T {
181        self.0.as_ptr()
182    }
183
184    unsafe fn replace_ptr(self, new: *mut U) -> ArcBorrow<'lt, U> {
185        let inner = ManuallyDrop::new(self);
186        // SAFETY:
187        // By `CoerciblePtr::replace_ptr`'s contract, `new` is derived from
188        // `self.as_sized_ptr()` via unsizing coercion, so it is non-null and
189        // backed by the same live `ArcInner` allocation for `'lt` with full
190        // provenance preserved.
191        ArcBorrow(unsafe { inner.0.replace_ptr(new) }, PhantomData)
192    }
193}
194
195#[test]
196fn clone_arc_borrow() {
197    let x = Arc::new(42);
198    let b: ArcBorrow<'_, i32> = x.borrow_arc();
199    let y = b.clone_arc();
200    assert_eq!(x, y);
201}
202
203#[test]
204fn clone_arc_borrow_str() {
205    let x: Arc<str> = Arc::from("hello");
206    let b: ArcBorrow<'_, str> = x.borrow_arc();
207    let y: Arc<str> = b.clone_arc();
208    assert_eq!(x, y);
209    assert_eq!(&*b, "hello");
210    assert!(ArcBorrow::ptr_eq(&b, &b));
211}