Skip to content

Commit

Permalink
style: Introduce ArcSlice, a small wrapper over ThinArc but without a…
Browse files Browse the repository at this point in the history
…n 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
  • Loading branch information
emilio committed May 10, 2019
1 parent 2ed2151 commit 0d5c448
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 3 deletions.
17 changes: 14 additions & 3 deletions components/servo_arc/lib.rs
Expand Up @@ -784,6 +784,13 @@ pub struct ThinArc<H, T> {
phantom: PhantomData<(H, T)>,
}


impl<H: fmt::Debug, T: fmt::Debug> fmt::Debug for ThinArc<H, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.deref(), f)
}
}

unsafe impl<H: Sync + Send, T: Sync + Send> Send for ThinArc<H, T> {}
unsafe impl<H: Sync + Send, T: Sync + Send> Sync for ThinArc<H, T> {}

Expand Down Expand Up @@ -856,8 +863,12 @@ impl<H, T> ThinArc<H, T> {
}

/// 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<T> as *const c_void
}

/// If this is a static ThinArc, this returns null.
#[inline]
pub fn heap_ptr(&self) -> *const c_void {
Expand All @@ -866,7 +877,7 @@ impl<H, T> ThinArc<H, T> {
if is_static {
ptr::null()
} else {
self.ptr.as_ptr() as *const ArcInner<T> as *const c_void
self.ptr()
}
}
}
Expand Down
1 change: 1 addition & 0 deletions components/style/lib.rs
Expand Up @@ -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.
Expand Down
14 changes: 14 additions & 0 deletions components/style/values/animated/mod.rs
Expand Up @@ -462,3 +462,17 @@ where
Ok(v.into_boxed_slice())
}
}

impl<T> ToAnimatedZero for crate::ArcSlice<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
let v = self
.iter()
.map(|v| v.to_animated_zero())
.collect::<Result<Vec<_>, _>>()?;
Ok(crate::ArcSlice::from_iter(v.into_iter()))
}
}
66 changes: 66 additions & 0 deletions 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<T>(#[shmem(field_bound)] ThinArc<u32, T>);

impl<T> Deref for ArcSlice<T> {
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<T>, 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<T>(NonNull<T>);

impl<T> ArcSlice<T> {
/// Creates an Arc for a slice using the given iterator to generate the
/// slice.
#[inline]
pub fn from_iter<I>(items: I) -> Self
where
I: Iterator<Item = T> + 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<T> {
let ret = unsafe {
ForgottenArcSlicePtr(NonNull::new_unchecked(self.0.ptr() as *const _ as *mut _))
};
mem::forget(self);
ret
}
}
1 change: 1 addition & 0 deletions components/style_traits/lib.rs
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions components/style_traits/specified_value_info.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -116,6 +117,7 @@ impl_generic_specified_value_info!(Option<T>);
impl_generic_specified_value_info!(Vec<T>);
impl_generic_specified_value_info!(Arc<T>);
impl_generic_specified_value_info!(StdArc<T>);
impl_generic_specified_value_info!(ArcSlice<T>);
impl_generic_specified_value_info!(Range<Idx>);

impl<T1, T2> SpecifiedValueInfo for (T1, T2)
Expand Down

0 comments on commit 0d5c448

Please sign in to comment.