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