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