Bug 1367904 - Part 2: stylo: Add RawOffsetArc<T>; r?bholley draft
authorManish Goregaokar <manishearth@gmail.com>
Thu, 15 Jun 2017 22:49:50 -0700
changeset 609391 5b7815530a134baf533faa254d04a10225c96c07
parent 609390 a75e26860c60a78254c606eebd63421f6e8c042e
child 609392 b562033c87bce4bc5aa5a334f6cccdc178fe9d91
push id68565
push userbmo:manishearth@gmail.com
push dateSun, 16 Jul 2017 03:07:34 +0000
reviewersbholley
bugs1367904
milestone56.0a1
Bug 1367904 - Part 2: stylo: Add RawOffsetArc<T>; r?bholley MozReview-Commit-ID: 6LcLxiRP9Y6
layout/style/ServoBindings.toml
servo/components/servo_arc/lib.rs
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -308,17 +308,17 @@ opaque-types = [
     "StyleAnimationValue", # pulls in a whole bunch of stuff we don't need in the bindings
 ]
 mapped-generic-types = [
     { generic = true, gecko = "mozilla::ServoUnsafeCell", servo = "::std::cell::UnsafeCell" },
     { generic = true, gecko = "mozilla::ServoCell", servo = "::std::cell::Cell" },
     { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
     { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
     { generic = false, gecko = "mozilla::ServoFontComputationData", servo = "::properties::FontComputationData" },
-    { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::stylearc::Arc<::custom_properties::ComputedValuesMap>>" },
+    { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::stylearc::Arc<::custom_properties::CustomPropertiesMap>>" },
     { generic = false, gecko = "mozilla::ServoVisitedStyle", servo = "Option<::stylearc::Arc<ServoComputedValues2>>" },
 ]
 fixups = [
     { pat = "root::nsString", rep = "::nsstring::nsStringRepr" },
 ]
 
 [bindings]
 headers = ["mozilla/ServoBindings.h"]
--- a/servo/components/servo_arc/lib.rs
+++ b/servo/components/servo_arc/lib.rs
@@ -632,16 +632,18 @@ impl<H: 'static, T: 'static> ThinArc<H, 
         let transient = NoDrop::new(Arc {
             p: NonZeroPtrMut::new(thin_to_thick(self.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
     }
 }
 
 impl<H, T> Deref for ThinArc<H, T> {
@@ -695,16 +697,105 @@ impl<H: PartialEq + 'static, T: PartialE
                 *a == *b
             })
         })
     }
 }
 
 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
+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 {
+        RawOffsetArc::with_arc(self, |a| Arc::into_raw_offset(a.clone()))
+    }
+}
+
+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: '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
+    }
+}
+
+impl<T: 'static> Arc<T> {
+    /// Converts an Arc into a RawOffsetArc. This consumes the Arc, so the refcount
+    /// is not modified.
+    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.
+    pub fn from_raw_offset(a: RawOffsetArc<T>) -> Self {
+        let ptr = a.ptr.ptr();
+        mem::forget(a);
+        unsafe { Arc::from_raw(ptr) }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use std::clone::Clone;
     use std::ops::Drop;
     use std::sync::atomic;
     use std::sync::atomic::Ordering::{Acquire, SeqCst};
     use super::{Arc, HeaderWithLength, ThinArc};