diff options
Diffstat (limited to 'components/servo_arc/lib.rs')
-rw-r--r-- | components/servo_arc/lib.rs | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index ff4074767f8..b1f4f277a49 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -194,6 +194,30 @@ impl<T> Arc<T> { p: NonZeroPtrMut::new(ptr as *mut ArcInner<T>), } } + + /// Produce a pointer to the data that can be converted back + /// to an arc + pub fn borrow_arc<'a>(&'a self) -> ArcBorrow<'a, T> { + ArcBorrow(&**self) + } + /// Temporarily converts |self| into a bonafide RawOffsetArc and exposes it to the + /// provided callback. The refcount is not modified. + #[inline(always)] + pub fn with_raw_offset_arc<F, U>(&self, f: F) -> U + where F: FnOnce(&RawOffsetArc<T>) -> U + { + // Synthesize transient Arc, which never touches the refcount of the ArcInner. + let transient = unsafe { NoDrop::new(Arc::into_raw_offset(ptr::read(self))) }; + + // Expose the transient Arc to the callback, which may clone it if it wants. + let result = f(&transient); + + // Forget the transient Arc to leave the refcount untouched. + mem::forget(transient); + + // Forward the result. + result + } } impl<T: ?Sized> Arc<T> { @@ -637,6 +661,8 @@ impl<H: 'static, T: 'static> ThinArc<H, T> { let result = f(&transient); // Forget the transient Arc to leave the refcount untouched. + // XXXManishearth this can be removed when unions stabilize, + // since then NoDrop becomes zero overhead mem::forget(transient); // Forward the result. @@ -700,6 +726,193 @@ impl<H: PartialEq + 'static, T: PartialEq + 'static> PartialEq for ThinArc<H, T> impl<H: Eq + 'static, T: Eq + 'static> Eq for ThinArc<H, T> {} +/// An Arc, except it holds a pointer to the T instead of to the +/// entire ArcInner. +/// +/// ```text +/// Arc<T> RawOffsetArc<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 +#[derive(Eq)] +pub struct RawOffsetArc<T: 'static> { + ptr: NonZeroPtrMut<T>, +} + +unsafe impl<T: 'static + Sync + Send> Send for RawOffsetArc<T> {} +unsafe impl<T: 'static + Sync + Send> Sync for RawOffsetArc<T> {} + +impl<T: 'static> Deref for RawOffsetArc<T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr.ptr() } + } +} + +impl<T: 'static> Clone for RawOffsetArc<T> { + fn clone(&self) -> Self { + Arc::into_raw_offset(self.clone_arc()) + } +} + +impl<T: 'static> Drop for RawOffsetArc<T> { + fn drop(&mut self) { + let _ = Arc::from_raw_offset(RawOffsetArc { ptr: self.ptr.clone() }); + } +} + + +impl<T: fmt::Debug + 'static> fmt::Debug for RawOffsetArc<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<T: PartialEq> PartialEq for RawOffsetArc<T> { + fn eq(&self, other: &RawOffsetArc<T>) -> bool { + *(*self) == *(*other) + } + + fn ne(&self, other: &RawOffsetArc<T>) -> bool { + *(*self) != *(*other) + } +} + +impl<T: 'static> RawOffsetArc<T> { + /// Temporarily converts |self| into a bonafide Arc and exposes it to the + /// provided callback. The refcount is not modified. + #[inline(always)] + 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 { NoDrop::new(Arc::from_raw(self.ptr.ptr())) }; + + // Expose the transient Arc to the callback, which may clone it if it wants. + let result = f(&transient); + + // Forget the transient Arc to leave the refcount untouched. + // XXXManishearth this can be removed when unions stabilize, + // since then NoDrop becomes zero overhead + mem::forget(transient); + + // Forward the result. + result + } + + /// If uniquely owned, provide a mutable reference + /// Else create a copy, and mutate that + pub fn make_mut(&mut self) -> &mut T where T: Clone { + unsafe { + // extract the RawOffsetArc 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 RawOffsetArc again + ptr::write(self, Arc::into_raw_offset(arc)); + &mut *ret + } + } + + /// Clone it as an Arc + pub fn clone_arc(&self) -> Arc<T> { + RawOffsetArc::with_arc(self, |a| a.clone()) + } + + /// Produce a pointer to the data that can be converted back + /// to an arc + pub fn borrow_arc<'a>(&'a self) -> ArcBorrow<'a, T> { + ArcBorrow(&**self) + } +} + +impl<T: 'static> Arc<T> { + /// Converts an Arc into a RawOffsetArc. This consumes the Arc, so the refcount + /// is not modified. + #[inline] + pub fn into_raw_offset(a: Self) -> RawOffsetArc<T> { + RawOffsetArc { + ptr: NonZeroPtrMut::new(Arc::into_raw(a) as *mut T), + } + } + + /// Converts a RawOffsetArc into an Arc. This consumes the RawOffsetArc, so the refcount + /// is not modified. + #[inline] + pub fn from_raw_offset(a: RawOffsetArc<T>) -> Self { + let ptr = a.ptr.ptr(); + mem::forget(a); + unsafe { Arc::from_raw(ptr) } + } +} + +/// A "borrowed Arc". This is a pointer to +/// a T that is known to have been allocated within an +/// Arc. +/// +/// This is equivalent in guarantees to `&Arc<T>`, however it is +/// a bit more flexible. To obtain an `&Arc<T>` you must have +/// an Arc<T> instance somewhere pinned down until we're done with it. +/// +/// However, Gecko hands us refcounted things as pointers to T directly, +/// so we have to conjure up a temporary Arc on the stack each time. The +/// same happens for when the object is managed by a RawOffsetArc. +/// +/// ArcBorrow lets us deal with borrows of known-refcounted objects +/// without needing to worry about how they're actually stored. +#[derive(PartialEq, Eq)] +pub struct ArcBorrow<'a, T: 'a>(&'a T); + +impl<'a, T> Copy for ArcBorrow<'a, T> {} +impl<'a, T> Clone for ArcBorrow<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> ArcBorrow<'a, T> { + pub fn clone_arc(&self) -> Arc<T> { + let arc = unsafe { Arc::from_raw(self.0) }; + // addref it! + mem::forget(arc.clone()); + arc + } + + pub fn with_arc<F, U>(&self, f: F) -> U where F: FnOnce(&Arc<T>) -> U, T: 'static { + // Synthesize transient Arc, which never touches the refcount. + let transient = unsafe { NoDrop::new(Arc::from_raw(self.0)) }; + + // Expose the transient Arc to the callback, which may clone it if it wants. + let result = f(&transient); + + // Forget the transient Arc to leave the refcount untouched. + // XXXManishearth this can be removed when unions stabilize, + // since then NoDrop becomes zero overhead + mem::forget(transient); + + // Forward the result. + result + } +} + +impl<'a, T> Deref for ArcBorrow<'a, T> { + type Target = T; + fn deref(&self) -> &T { + &*self.0 + } +} + #[cfg(test)] mod tests { use std::clone::Clone; |