backdrop_arc/
offset_arc.rs

1use alloc::boxed::Box;
2use core::fmt;
3use core::marker::PhantomData;
4use core::mem::ManuallyDrop;
5use core::ops::Deref;
6use core::ptr;
7
8extern crate backdrop;
9use crate::ArcInner;
10
11use self::backdrop::BackdropStrategy;
12
13use super::{Arc, ArcBorrow};
14
15/// An `Arc`, except it holds a pointer to the T instead of to the
16/// entire ArcInner.
17///
18/// An `OffsetArc<T, S>` has the same layout and ABI as a non-null
19/// `const T*` in C, and may be used in FFI function signatures.
20///
21/// ```text
22///  Arc<T, S>    OffsetArc<T, S>
23///   |          |
24///   v          v
25///  ---------------------
26/// | RefCount | T (data) | [ArcInner<T>]
27///  ---------------------
28/// ```
29///
30/// This means that this is a direct pointer to
31/// its contained data (and can be read from by both C++ and Rust),
32/// but we can also convert it to a "regular" `Arc<T, S>` by removing the offset.
33///
34/// This is very useful if you have an Arc-containing struct shared between Rust and C++,
35/// and wish for C++ to be able to read the data behind the `Arc` without incurring
36/// an FFI call overhead.
37#[derive(Eq)]
38#[repr(transparent)]
39pub struct OffsetArc<T, S>
40where
41    S: BackdropStrategy<Box<ArcInner<T>>>,
42{
43    pub(crate) ptr: ptr::NonNull<T>,
44    pub(crate) phantom: PhantomData<T>,
45    pub(crate) phantom_strategy: PhantomData<S>,
46}
47
48unsafe impl<T: Sync + Send, S> Send for OffsetArc<T, S> where S: BackdropStrategy<Box<ArcInner<T>>> {}
49unsafe impl<T: Sync + Send, S> Sync for OffsetArc<T, S> where S: BackdropStrategy<Box<ArcInner<T>>> {}
50
51impl<T, S> Deref for OffsetArc<T, S>
52where
53    S: BackdropStrategy<Box<ArcInner<T>>>,
54{
55    type Target = T;
56    #[inline]
57    fn deref(&self) -> &Self::Target {
58        unsafe { &*self.ptr.as_ptr() }
59    }
60}
61
62impl<T, S> Clone for OffsetArc<T, S>
63where
64    S: BackdropStrategy<Box<ArcInner<T>>>,
65{
66    #[inline]
67    fn clone(&self) -> Self {
68        Arc::into_raw_offset(self.clone_arc())
69    }
70}
71
72impl<T, S> Drop for OffsetArc<T, S>
73where
74    S: BackdropStrategy<Box<ArcInner<T>>>,
75{
76    fn drop(&mut self) {
77        let _ = Arc::<_, S>::from_raw_offset(OffsetArc {
78            ptr: self.ptr,
79            phantom: PhantomData,
80            phantom_strategy: PhantomData,
81        });
82    }
83}
84
85impl<T: fmt::Debug, S> fmt::Debug for OffsetArc<T, S>
86where
87    S: BackdropStrategy<Box<ArcInner<T>>>,
88{
89    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90        fmt::Debug::fmt(&**self, f)
91    }
92}
93
94impl<T: PartialEq, S> PartialEq for OffsetArc<T, S>
95where
96    S: BackdropStrategy<Box<ArcInner<T>>>,
97{
98    fn eq(&self, other: &OffsetArc<T, S>) -> bool {
99        *(*self) == *(*other)
100    }
101
102    #[allow(clippy::partialeq_ne_impl)]
103    fn ne(&self, other: &OffsetArc<T, S>) -> bool {
104        *(*self) != *(*other)
105    }
106}
107
108impl<T, S> OffsetArc<T, S>
109where
110    S: BackdropStrategy<Box<ArcInner<T>>>,
111{
112    /// Temporarily converts |self| into a bonafide Arc and exposes it to the
113    /// provided callback. The refcount is not modified.
114    #[inline]
115    pub fn with_arc<F, U>(&self, f: F) -> U
116    where
117        F: FnOnce(&Arc<T, S>) -> U,
118    {
119        // Synthesize transient Arc, which never touches the refcount of the ArcInner.
120        let transient = unsafe { ManuallyDrop::new(Arc::from_raw(self.ptr.as_ptr())) };
121
122        // Expose the transient Arc to the callback, which may clone it if it wants
123        // and forward the result to the user
124        f(&transient)
125    }
126
127    /// If uniquely owned, provide a mutable reference
128    /// Else create a copy, and mutate that
129    ///
130    /// This is functionally the same thing as `Arc::make_mut`
131    #[inline]
132    pub fn make_mut(&mut self) -> &mut T
133    where
134        T: Clone,
135    {
136        unsafe {
137            // extract the OffsetArc as an owned variable
138            let this = ptr::read(self);
139            // treat it as a real Arc
140            let mut arc = Arc::from_raw_offset(this);
141            // obtain the mutable reference. Cast away the lifetime
142            // This may mutate `arc`
143            let ret = Arc::make_mut(&mut arc) as *mut _;
144            // Store the possibly-mutated arc back inside, after converting
145            // it to a OffsetArc again
146            ptr::write(self, Arc::into_raw_offset(arc));
147            &mut *ret
148        }
149    }
150
151    /// Clone it as an `Arc`
152    #[inline]
153    pub fn clone_arc(&self) -> Arc<T, S> {
154        OffsetArc::with_arc(self, |a| a.clone())
155    }
156
157    /// Produce a pointer to the data that can be converted back
158    /// to an `Arc`
159    #[inline]
160    pub fn borrow_arc(&self) -> ArcBorrow<'_, T> {
161        ArcBorrow(&**self)
162    }
163}