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` has the same layout and ABI as a non-null /// `const T*` in C, and may be used in FFI function signatures. /// /// ```text /// Arc OffsetArc /// | | /// v v /// --------------------- /// | RefCount | T (data) | [ArcInner] /// --------------------- /// ``` /// /// 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` 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 { pub(crate) ptr: ptr::NonNull, pub(crate) phantom: PhantomData, } unsafe impl Send for OffsetArc {} unsafe impl Sync for OffsetArc {} impl Deref for OffsetArc { type Target = T; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*self.ptr.as_ptr() } } } impl Clone for OffsetArc { #[inline] fn clone(&self) -> Self { Arc::into_raw_offset(self.clone_arc()) } } impl Drop for OffsetArc { fn drop(&mut self) { let _ = Arc::from_raw_offset(OffsetArc { ptr: self.ptr, phantom: PhantomData, }); } } impl fmt::Debug for OffsetArc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl PartialEq for OffsetArc { fn eq(&self, other: &OffsetArc) -> bool { *(*self) == *(*other) } #[allow(clippy::partialeq_ne_impl)] fn ne(&self, other: &OffsetArc) -> bool { *(*self) != *(*other) } } impl OffsetArc { /// Temporarily converts |self| into a bonafide Arc and exposes it to the /// provided callback. The refcount is not modified. #[inline] pub fn with_arc(&self, f: F) -> U where F: FnOnce(&Arc) -> 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 { 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) } }