summaryrefslogtreecommitdiffstats
path: root/vendor/triomphe/src/offset_arc.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/triomphe/src/offset_arc.rs
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/triomphe/src/offset_arc.rs')
-rw-r--r--vendor/triomphe/src/offset_arc.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/vendor/triomphe/src/offset_arc.rs b/vendor/triomphe/src/offset_arc.rs
new file mode 100644
index 000000000..9345416d4
--- /dev/null
+++ b/vendor/triomphe/src/offset_arc.rs
@@ -0,0 +1,134 @@
+use core::fmt;
+use core::marker::PhantomData;
+use core::mem::ManuallyDrop;
+use core::ops::Deref;
+use core::ptr;
+
+use super::{Arc, ArcBorrow};
+
+/// An `Arc`, except it holds a pointer to the T instead of to the
+/// entire ArcInner.
+///
+/// An `OffsetArc<T>` has the same layout and ABI as a non-null
+/// `const T*` in C, and may be used in FFI function signatures.
+///
+/// ```text
+/// Arc<T> OffsetArc<T>
+/// | |
+/// v v
+/// ---------------------
+/// | RefCount | T (data) | [ArcInner<T>]
+/// ---------------------
+/// ```
+///
+/// This means that this is a direct pointer to
+/// its contained data (and can be read from by both C++ and Rust),
+/// but we can also convert it to a "regular" `Arc<T>` by removing the offset.
+///
+/// This is very useful if you have an Arc-containing struct shared between Rust and C++,
+/// and wish for C++ to be able to read the data behind the `Arc` without incurring
+/// an FFI call overhead.
+#[derive(Eq)]
+#[repr(transparent)]
+pub struct OffsetArc<T> {
+ pub(crate) ptr: ptr::NonNull<T>,
+ pub(crate) phantom: PhantomData<T>,
+}
+
+unsafe impl<T: Sync + Send> Send for OffsetArc<T> {}
+unsafe impl<T: Sync + Send> Sync for OffsetArc<T> {}
+
+impl<T> Deref for OffsetArc<T> {
+ type Target = T;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.ptr.as_ptr() }
+ }
+}
+
+impl<T> Clone for OffsetArc<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Arc::into_raw_offset(self.clone_arc())
+ }
+}
+
+impl<T> Drop for OffsetArc<T> {
+ fn drop(&mut self) {
+ let _ = Arc::from_raw_offset(OffsetArc {
+ ptr: self.ptr,
+ phantom: PhantomData,
+ });
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for OffsetArc<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+impl<T: PartialEq> PartialEq for OffsetArc<T> {
+ fn eq(&self, other: &OffsetArc<T>) -> bool {
+ *(*self) == *(*other)
+ }
+
+ #[allow(clippy::partialeq_ne_impl)]
+ fn ne(&self, other: &OffsetArc<T>) -> bool {
+ *(*self) != *(*other)
+ }
+}
+
+impl<T> OffsetArc<T> {
+ /// Temporarily converts |self| into a bonafide Arc and exposes it to the
+ /// provided callback. The refcount is not modified.
+ #[inline]
+ pub fn with_arc<F, U>(&self, f: F) -> U
+ where
+ F: FnOnce(&Arc<T>) -> U,
+ {
+ // Synthesize transient Arc, which never touches the refcount of the ArcInner.
+ let transient = unsafe { ManuallyDrop::new(Arc::from_raw(self.ptr.as_ptr())) };
+
+ // Expose the transient Arc to the callback, which may clone it if it wants
+ // and forward the result to the user
+ f(&transient)
+ }
+
+ /// If uniquely owned, provide a mutable reference
+ /// Else create a copy, and mutate that
+ ///
+ /// This is functionally the same thing as `Arc::make_mut`
+ #[inline]
+ pub fn make_mut(&mut self) -> &mut T
+ where
+ T: Clone,
+ {
+ unsafe {
+ // extract the OffsetArc as an owned variable
+ let this = ptr::read(self);
+ // treat it as a real Arc
+ let mut arc = Arc::from_raw_offset(this);
+ // obtain the mutable reference. Cast away the lifetime
+ // This may mutate `arc`
+ let ret = Arc::make_mut(&mut arc) as *mut _;
+ // Store the possibly-mutated arc back inside, after converting
+ // it to a OffsetArc again
+ ptr::write(self, Arc::into_raw_offset(arc));
+ &mut *ret
+ }
+ }
+
+ /// Clone it as an `Arc`
+ #[inline]
+ pub fn clone_arc(&self) -> Arc<T> {
+ OffsetArc::with_arc(self, |a| a.clone())
+ }
+
+ /// Produce a pointer to the data that can be converted back
+ /// to an `Arc`
+ #[inline]
+ pub fn borrow_arc(&self) -> ArcBorrow<'_, T> {
+ ArcBorrow(&**self)
+ }
+}