From 0d5c4481b8b5f96325260ee0ffc2b5f206c97548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 9 May 2019 10:53:50 +0000 Subject: [PATCH] style: Introduce ArcSlice, a small wrapper over ThinArc but without an explicit header. We could make the header PhantomData or something, but then we wouldn't be able to bind to C++, since C++ doesn't have ZSTs. So add a canary instead to add a runtime check of stuff being sane. Differential Revision: https://phabricator.services.mozilla.com/D30133 --- components/servo_arc/lib.rs | 17 ++++- components/style/lib.rs | 1 + components/style/values/animated/mod.rs | 14 ++++ components/style_traits/arc_slice.rs | 66 +++++++++++++++++++ components/style_traits/lib.rs | 1 + .../style_traits/specified_value_info.rs | 2 + 6 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 components/style_traits/arc_slice.rs diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index 40a8ff3d193..09b81920164 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -784,6 +784,13 @@ pub struct ThinArc { phantom: PhantomData<(H, T)>, } + +impl fmt::Debug for ThinArc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.deref(), f) + } +} + unsafe impl Send for ThinArc {} unsafe impl Sync for ThinArc {} @@ -856,8 +863,12 @@ impl ThinArc { } /// Returns the address on the heap of the ThinArc itself -- not the T - /// within it -- for memory reporting. - /// + /// within it -- for memory reporting, and bindings. + #[inline] + pub fn ptr(&self) -> *const c_void { + self.ptr.as_ptr() as *const ArcInner as *const c_void + } + /// If this is a static ThinArc, this returns null. #[inline] pub fn heap_ptr(&self) -> *const c_void { @@ -866,7 +877,7 @@ impl ThinArc { if is_static { ptr::null() } else { - self.ptr.as_ptr() as *const ArcInner as *const c_void + self.ptr() } } } diff --git a/components/style/lib.rs b/components/style/lib.rs index 10d45408065..4d523d65c4f 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -188,6 +188,7 @@ pub use html5ever::Prefix; #[cfg(feature = "servo")] pub use servo_atoms::Atom; +pub use style_traits::arc_slice::ArcSlice; pub use style_traits::owned_slice::OwnedSlice; /// The CSS properties supported by the style system. diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index 6f8de1decca..29e74859cd6 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -462,3 +462,17 @@ where Ok(v.into_boxed_slice()) } } + +impl ToAnimatedZero for crate::ArcSlice +where + T: ToAnimatedZero, +{ + #[inline] + fn to_animated_zero(&self) -> Result { + let v = self + .iter() + .map(|v| v.to_animated_zero()) + .collect::, _>>()?; + Ok(crate::ArcSlice::from_iter(v.into_iter())) + } +} diff --git a/components/style_traits/arc_slice.rs b/components/style_traits/arc_slice.rs new file mode 100644 index 00000000000..f7097e3d086 --- /dev/null +++ b/components/style_traits/arc_slice.rs @@ -0,0 +1,66 @@ +/* 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 thin atomically-reference-counted slice. + +use servo_arc::ThinArc; +use std::mem; +use std::ops::Deref; +use std::ptr::NonNull; + +/// A canary that we stash in ArcSlices. +/// +/// Given we cannot use a zero-sized-type for the header, since well, C++ +/// doesn't have zsts, and we want to use cbindgen for this type, we may as well +/// assert some sanity at runtime. +const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3; + +/// A wrapper type for a refcounted slice using ThinArc. +/// +/// cbindgen:derive-eq=false +/// cbindgen:derive-neq=false +#[repr(C)] +#[derive(Debug, Clone, PartialEq, Eq, ToShmem)] +pub struct ArcSlice(#[shmem(field_bound)] ThinArc); + +impl Deref for ArcSlice { + type Target = [T]; + + #[inline] + fn deref(&self) -> &Self::Target { + debug_assert_eq!(self.0.header.header, ARC_SLICE_CANARY); + &self.0.slice + } +} + +/// The inner pointer of an ArcSlice, to be sent via FFI. +/// The type of the pointer is a bit of a lie, we just want to preserve the type +/// but these pointers cannot be constructed outside of this crate, so we're +/// good. +#[repr(C)] +pub struct ForgottenArcSlicePtr(NonNull); + +impl ArcSlice { + /// Creates an Arc for a slice using the given iterator to generate the + /// slice. + #[inline] + pub fn from_iter(items: I) -> Self + where + I: Iterator + ExactSizeIterator, + { + ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items)) + } + + /// Creates a value that can be passed via FFI, and forgets this value + /// altogether. + #[inline] + #[allow(unsafe_code)] + pub fn forget(self) -> ForgottenArcSlicePtr { + let ret = unsafe { + ForgottenArcSlicePtr(NonNull::new_unchecked(self.0.ptr() as *const _ as *mut _)) + }; + mem::forget(self); + ret + } +} diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 14ce2c9801e..d4a907fa956 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -84,6 +84,7 @@ pub enum CSSPixel {} // / hidpi_ratio => DeviceIndependentPixel // / desktop_zoom => CSSPixel +pub mod arc_slice; pub mod specified_value_info; #[macro_use] pub mod values; diff --git a/components/style_traits/specified_value_info.rs b/components/style_traits/specified_value_info.rs index c978727b47a..63a7b71d990 100644 --- a/components/style_traits/specified_value_info.rs +++ b/components/style_traits/specified_value_info.rs @@ -4,6 +4,7 @@ //! Value information for devtools. +use crate::arc_slice::ArcSlice; use servo_arc::Arc; use std::ops::Range; use std::sync::Arc as StdArc; @@ -116,6 +117,7 @@ impl_generic_specified_value_info!(Option); impl_generic_specified_value_info!(Vec); impl_generic_specified_value_info!(Arc); impl_generic_specified_value_info!(StdArc); +impl_generic_specified_value_info!(ArcSlice); impl_generic_specified_value_info!(Range); impl SpecifiedValueInfo for (T1, T2)