From 330bccd6595007b62a6b0f8629b717a0c6ac30bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 9 May 2019 10:49:22 +0000 Subject: [PATCH] style: Add an owned slice type which cbindgen can understand. 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, Atom and Arc 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 --- components/style/lib.rs | 3 + components/style/owned_slice.rs | 163 ++++++++++++++++++++++++ components/style/values/animated/mod.rs | 44 +++++++ components/style/values/computed/mod.rs | 24 ++++ components/style/values/resolved/mod.rs | 17 +++ components/to_shmem/lib.rs | 2 +- 6 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 components/style/owned_slice.rs diff --git a/components/style/lib.rs b/components/style/lib.rs index bd33dbeafe4..65f2eda52ff 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -143,6 +143,7 @@ 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; @@ -188,6 +189,8 @@ 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] diff --git a/components/style/owned_slice.rs b/components/style/owned_slice.rs new file mode 100644 index 00000000000..a92a6269e70 --- /dev/null +++ b/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 { + ptr: NonNull, + len: usize, + _phantom: PhantomData, +} + +impl Default for OwnedSlice { + #[inline] + fn default() -> Self { + Self { + len: 0, + ptr: NonNull::dangling(), + _phantom: PhantomData, + } + } +} + +impl Drop for OwnedSlice { + #[inline] + fn drop(&mut self) { + if self.len != 0 { + let _ = mem::replace(self, Self::default()).into_vec(); + } + } +} + +unsafe impl Send for OwnedSlice {} +unsafe impl Sync for OwnedSlice {} + +impl Clone for OwnedSlice { + #[inline] + fn clone(&self) -> Self { + Self::from_slice(&**self) + } +} + +impl fmt::Debug for OwnedSlice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.deref().fmt(formatter) + } +} + +impl PartialEq for OwnedSlice { + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other.deref()) + } +} + +impl Eq for OwnedSlice {} + +impl OwnedSlice { + /// 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 { + 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 { + 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 Deref for OwnedSlice { + type Target = [T]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) } + } +} + +impl DerefMut for OwnedSlice { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) } + } +} + +impl From> for OwnedSlice { + #[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 From> for OwnedSlice { + #[inline] + fn from(b: Vec) -> Self { + Self::from(b.into_boxed_slice()) + } +} + +impl MallocShallowSizeOf for OwnedSlice { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + unsafe { ops.malloc_size_of(self.ptr.as_ptr()) } + } +} + +impl MallocSizeOf for OwnedSlice { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.shallow_size_of(ops) + (**self).size_of(ops) + } +} + +impl ToShmem for OwnedSlice { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> mem::ManuallyDrop { + unsafe { + let dest = to_shmem::to_shmem_slice(self.iter(), builder); + mem::ManuallyDrop::new(Self::from(Box::from_raw(dest))) + } + } +} diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index 3b83c71e6e2..a1e5ca4618c 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -288,6 +288,50 @@ where } } +impl ToAnimatedValue for Box<[T]> +where + T: ToAnimatedValue, +{ + type AnimatedValue = Box<[::AnimatedValue]>; + + #[inline] + fn to_animated_value(self) -> Self::AnimatedValue { + self + .into_vec() + .into_iter() + .map(T::to_animated_value) + .collect::>() + .into_boxed_slice() + } + + #[inline] + fn from_animated_value(animated: Self::AnimatedValue) -> Self { + animated + .into_vec() + .into_iter() + .map(T::from_animated_value) + .collect::>() + .into_boxed_slice() + } +} + +impl ToAnimatedValue for crate::OwnedSlice +where + T: ToAnimatedValue, +{ + type AnimatedValue = crate::OwnedSlice<::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 ToAnimatedValue for SmallVec<[T; 1]> where T: ToAnimatedValue, diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index f7f14c79d9c..5bf0333dbfe 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -444,6 +444,30 @@ where } } +impl ToComputedValue for crate::OwnedSlice +where + T: ToComputedValue, +{ + type ComputedValue = crate::OwnedSlice<::ComputedValue>; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + self.iter() + .map(|item| item.to_computed_value(context)) + .collect::>() + .into() + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + computed + .iter() + .map(T::from_computed_value) + .collect::>() + .into() + } +} + trivial_to_computed_value!(()); trivial_to_computed_value!(bool); trivial_to_computed_value!(f32); diff --git a/components/style/values/resolved/mod.rs b/components/style/values/resolved/mod.rs index 4003060148c..379ea83ec6b 100644 --- a/components/style/values/resolved/mod.rs +++ b/components/style/values/resolved/mod.rs @@ -193,3 +193,20 @@ where Vec::from_resolved_value(Vec::from(resolved)).into_boxed_slice() } } + +impl ToResolvedValue for crate::OwnedSlice +where + T: ToResolvedValue, +{ + type ResolvedValue = crate::OwnedSlice<::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())) + } +} diff --git a/components/to_shmem/lib.rs b/components/to_shmem/lib.rs index 96dfbb3a5e9..07c5fc9ccaa 100644 --- a/components/to_shmem/lib.rs +++ b/components/to_shmem/lib.rs @@ -311,7 +311,7 @@ where /// 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,