mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
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<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
This commit is contained in:
parent
4b761848a0
commit
330bccd659
6 changed files with 252 additions and 1 deletions
|
@ -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]
|
||||
|
|
163
components/style/owned_slice.rs
Normal file
163
components/style/owned_slice.rs
Normal file
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -288,6 +288,50 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -444,6 +444,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -193,3 +193,20 @@ where
|
|||
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()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Item = &'a T>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue