Bug 1548691 - Add an owned slice type which cbindgen can understand. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 09 May 2019 10:49:22 +0000
changeset 532019 41acb048244d7d2bad371761bf54c80670fe683b
parent 532018 a93ed2a80220b9ba15fb9b59ea79b5f1ee8f7693
child 532020 fe11fc11ec5b0ee0111351c01cf601109798ca85
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1548691
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1548691 - Add an owned slice type which cbindgen can understand. r=heycam Passing these by value won't be ok of course, but that's fine. I plan to combine this with https://github.com/eqrion/cbindgen/pull/333 to actually be able to share representation for ~all the things, this is just the first bit. Box<T>, Atom and Arc<T> will be much easier since cbindgen can understand them without issues. It's boxed slices the only ones I should need something like this. I could avoid it if I rely on Rust's internal representation, which we can per [1], but then I need to teach cbindgen all about slices, which is generally hard, I think. [1]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/reference/src/layout/pointers.md Differential Revision: https://phabricator.services.mozilla.com/D29768
servo/components/style/lib.rs
servo/components/style/owned_slice.rs
servo/components/style/values/animated/mod.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/resolved/mod.rs
servo/components/to_shmem/lib.rs
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -138,16 +138,17 @@ pub mod gecko_bindings;
 pub mod global_style_data;
 pub mod hash;
 pub mod invalidation;
 #[allow(missing_docs)] // TODO.
 pub mod logical_geometry;
 pub mod matching;
 #[macro_use]
 pub mod media_queries;
+pub mod owned_slice;
 pub mod parallel;
 pub mod parser;
 pub mod rule_cache;
 pub mod rule_collector;
 pub mod rule_tree;
 pub mod scoped_tls;
 pub mod selector_map;
 pub mod selector_parser;
@@ -183,16 +184,18 @@ pub use crate::gecko_string_cache::Names
 pub use html5ever::LocalName;
 #[cfg(feature = "servo")]
 pub use html5ever::Namespace;
 #[cfg(feature = "servo")]
 pub use html5ever::Prefix;
 #[cfg(feature = "servo")]
 pub use servo_atoms::Atom;
 
+pub use owned_slice::OwnedSlice;
+
 /// The CSS properties supported by the style system.
 /// Generated from the properties.mako.rs template by build.rs
 #[macro_use]
 #[allow(unsafe_code)]
 #[deny(missing_docs)]
 pub mod properties {
     include!(concat!(env!("OUT_DIR"), "/properties.rs"));
 }
new file mode 100644
--- /dev/null
+++ b/servo/components/style/owned_slice.rs
@@ -0,0 +1,163 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! A replacement for `Box<[T]>` that cbindgen can understand.
+
+use std::marker::PhantomData;
+use std::{fmt, mem, slice};
+use std::ptr::NonNull;
+use std::ops::{Deref, DerefMut};
+use malloc_size_of::{MallocSizeOf, MallocShallowSizeOf, MallocSizeOfOps};
+use to_shmem::{SharedMemoryBuilder, ToShmem};
+
+/// A struct that basically replaces a `Box<[T]>`, but which cbindgen can
+/// understand.
+///
+/// We could rely on the struct layout of `Box<[T]>` per:
+///
+///   https://github.com/rust-lang/unsafe-code-guidelines/blob/master/reference/src/layout/pointers.md
+///
+/// But handling fat pointers with cbindgen both in structs and argument
+/// positions more generally is a bit tricky.
+#[repr(C)]
+pub struct OwnedSlice<T: Sized> {
+    ptr: NonNull<T>,
+    len: usize,
+    _phantom: PhantomData<T>,
+}
+
+impl<T: Sized> Default for OwnedSlice<T> {
+    #[inline]
+    fn default() -> Self {
+        Self {
+            len: 0,
+            ptr: NonNull::dangling(),
+            _phantom: PhantomData,
+        }
+    }
+}
+
+impl<T: Sized> Drop for OwnedSlice<T> {
+    #[inline]
+    fn drop(&mut self) {
+        if self.len != 0 {
+            let _ = mem::replace(self, Self::default()).into_vec();
+        }
+    }
+}
+
+unsafe impl<T: Sized + Send> Send for OwnedSlice<T> {}
+unsafe impl<T: Sized + Sync> Sync for OwnedSlice<T> {}
+
+impl<T: Clone> Clone for OwnedSlice<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::from_slice(&**self)
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for OwnedSlice<T> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        self.deref().fmt(formatter)
+    }
+}
+
+impl<T: PartialEq> PartialEq for OwnedSlice<T> {
+    fn eq(&self, other: &Self) -> bool {
+        self.deref().eq(other.deref())
+    }
+}
+
+impl<T: Eq> Eq for OwnedSlice<T> {}
+
+impl<T: Sized> OwnedSlice<T> {
+    /// Convert the OwnedSlice into a boxed slice.
+    #[inline]
+    pub fn into_box(self) -> Box<[T]> {
+        self.into_vec().into_boxed_slice()
+    }
+
+    /// Convert the OwnedSlice into a Vec.
+    #[inline]
+    pub fn into_vec(self) -> Vec<T> {
+        let ret = unsafe {
+            Vec::from_raw_parts(self.ptr.as_ptr(), self.len, self.len)
+        };
+        mem::forget(self);
+        ret
+    }
+
+    /// Iterate over all the elements in the slice taking ownership of them.
+    #[inline]
+    pub fn into_iter(self) -> impl Iterator<Item = T> {
+        self.into_vec().into_iter()
+    }
+
+    /// Convert the regular slice into an owned slice.
+    #[inline]
+    pub fn from_slice(s: &[T]) -> Self
+    where
+        T: Clone,
+    {
+        Self::from(s.to_vec())
+    }
+}
+
+impl<T> Deref for OwnedSlice<T> {
+    type Target = [T];
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
+    }
+}
+
+impl<T> DerefMut for OwnedSlice<T> {
+    #[inline(always)]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
+    }
+}
+
+impl<T> From<Box<[T]>> for OwnedSlice<T> {
+    #[inline]
+    fn from(mut b: Box<[T]>) -> Self {
+        let len = b.len();
+        let ptr = unsafe { NonNull::new_unchecked(b.as_mut_ptr()) };
+        mem::forget(b);
+        Self {
+            len,
+            ptr,
+            _phantom: PhantomData,
+        }
+    }
+}
+
+impl<T> From<Vec<T>> for OwnedSlice<T> {
+    #[inline]
+    fn from(b: Vec<T>) -> Self {
+        Self::from(b.into_boxed_slice())
+    }
+}
+
+impl<T: Sized> MallocShallowSizeOf for OwnedSlice<T> {
+    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+        unsafe { ops.malloc_size_of(self.ptr.as_ptr()) }
+    }
+}
+
+impl<T: MallocSizeOf + Sized> MallocSizeOf for OwnedSlice<T> {
+    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+        self.shallow_size_of(ops) + (**self).size_of(ops)
+    }
+}
+
+impl<T: ToShmem + Sized> ToShmem for OwnedSlice<T> {
+    fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> mem::ManuallyDrop<Self> {
+        unsafe {
+            let dest = to_shmem::to_shmem_slice(self.iter(), builder);
+            mem::ManuallyDrop::new(Self::from(Box::from_raw(dest)))
+        }
+    }
+}
--- a/servo/components/style/values/animated/mod.rs
+++ b/servo/components/style/values/animated/mod.rs
@@ -283,16 +283,60 @@ where
     }
 
     #[inline]
     fn from_animated_value(animated: Self::AnimatedValue) -> Self {
         animated.into_iter().map(T::from_animated_value).collect()
     }
 }
 
+impl<T> ToAnimatedValue for Box<[T]>
+where
+    T: ToAnimatedValue,
+{
+    type AnimatedValue = Box<[<T as ToAnimatedValue>::AnimatedValue]>;
+
+    #[inline]
+    fn to_animated_value(self) -> Self::AnimatedValue {
+        self
+            .into_vec()
+            .into_iter()
+            .map(T::to_animated_value)
+            .collect::<Vec<_>>()
+            .into_boxed_slice()
+    }
+
+    #[inline]
+    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+        animated
+            .into_vec()
+            .into_iter()
+            .map(T::from_animated_value)
+            .collect::<Vec<_>>()
+            .into_boxed_slice()
+    }
+}
+
+impl<T> ToAnimatedValue for crate::OwnedSlice<T>
+where
+    T: ToAnimatedValue,
+{
+    type AnimatedValue = crate::OwnedSlice<<T as ToAnimatedValue>::AnimatedValue>;
+
+    #[inline]
+    fn to_animated_value(self) -> Self::AnimatedValue {
+        self.into_box().to_animated_value().into()
+    }
+
+    #[inline]
+    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+        Box::from_animated_value(animated.into_box()).into()
+    }
+}
+
 impl<T> ToAnimatedValue for SmallVec<[T; 1]>
 where
     T: ToAnimatedValue,
 {
     type AnimatedValue = SmallVec<[T::AnimatedValue; 1]>;
 
     #[inline]
     fn to_animated_value(self) -> Self::AnimatedValue {
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -439,16 +439,40 @@ where
         computed
             .iter()
             .map(T::from_computed_value)
             .collect::<Vec<_>>()
             .into_boxed_slice()
     }
 }
 
+impl<T> ToComputedValue for crate::OwnedSlice<T>
+where
+    T: ToComputedValue,
+{
+    type ComputedValue = crate::OwnedSlice<<T as ToComputedValue>::ComputedValue>;
+
+    #[inline]
+    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+        self.iter()
+            .map(|item| item.to_computed_value(context))
+            .collect::<Vec<_>>()
+            .into()
+    }
+
+    #[inline]
+    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+        computed
+            .iter()
+            .map(T::from_computed_value)
+            .collect::<Vec<_>>()
+            .into()
+    }
+}
+
 trivial_to_computed_value!(());
 trivial_to_computed_value!(bool);
 trivial_to_computed_value!(f32);
 trivial_to_computed_value!(i32);
 trivial_to_computed_value!(u8);
 trivial_to_computed_value!(u16);
 trivial_to_computed_value!(u32);
 trivial_to_computed_value!(Atom);
--- a/servo/components/style/values/resolved/mod.rs
+++ b/servo/components/style/values/resolved/mod.rs
@@ -188,8 +188,25 @@ where
             .into_boxed_slice()
     }
 
     #[inline]
     fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
         Vec::from_resolved_value(Vec::from(resolved)).into_boxed_slice()
     }
 }
+
+impl<T> ToResolvedValue for crate::OwnedSlice<T>
+where
+    T: ToResolvedValue,
+{
+    type ResolvedValue = crate::OwnedSlice<<T as ToResolvedValue>::ResolvedValue>;
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        self.into_box().to_resolved_value(context).into()
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        Self::from(Box::from_resolved_value(resolved.into_box()))
+    }
+}
--- a/servo/components/to_shmem/lib.rs
+++ b/servo/components/to_shmem/lib.rs
@@ -306,17 +306,17 @@ where
         ptr::write(dest, ManuallyDrop::into_inner(src.to_shmem(builder)));
     }
 
     dest
 }
 
 /// Writes all the items in `src` into a slice in the shared memory buffer and
 /// returns a pointer to the slice.
-unsafe fn to_shmem_slice<'a, T, I>(src: I, builder: &mut SharedMemoryBuilder) -> *mut [T]
+pub unsafe fn to_shmem_slice<'a, T, I>(src: I, builder: &mut SharedMemoryBuilder) -> *mut [T]
 where
     T: 'a + ToShmem,
     I: ExactSizeIterator<Item = &'a T>,
 {
     let dest = builder.alloc_array(src.len());
     to_shmem_slice_ptr(src, dest, builder)
 }