mirror of
https://github.com/servo/servo.git
synced 2025-06-27 02:23:41 +01:00
We have this optimization where, for non-generic structs, we generate just a clone / move as the ToComputedValue / ToResolvedValue implementation. This moves the optimization a bit further down, and refines it so that we still generate all the relevant where clauses that make it sound, that is, that all the ToComputedValue implementations of the fields return the same type. Otherwise this wouldn't be sound and the type would need to become generic. We add an escape hatch (no_field_bound) for fields that need to be cloned but which don't implement the trait. This is right now only for the RefPtr<> in the shared font-family list, and a piece of code in PaintWorklet which looks kinda fishy, and probably should be fixed (but we don't ship it in Firefox and there's a pre-existing FIXME for servo, so I punted on it for now). The other thing this patch does is adding a bunch of ToComputedValue / ToResolvedValue implementations that are trivial and were missing. Differential Revision: https://phabricator.services.mozilla.com/D67913
145 lines
4.3 KiB
Rust
145 lines
4.3 KiB
Rust
/* 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 serde::de::{Deserialize, Deserializer};
|
|
use serde::ser::{Serialize, Serializer};
|
|
use servo_arc::ThinArc;
|
|
use std::ops::Deref;
|
|
use std::ptr::NonNull;
|
|
use std::{iter, mem};
|
|
|
|
/// 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.
|
|
///
|
|
/// We use an u64, to guarantee that we can use a single singleton for every
|
|
/// empty slice, even if the types they hold are aligned differently.
|
|
const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3;
|
|
|
|
/// A wrapper type for a refcounted slice using ThinArc.
|
|
///
|
|
/// cbindgen:derive-eq=false
|
|
/// cbindgen:derive-neq=false
|
|
#[repr(C)]
|
|
#[derive(Debug, Eq, PartialEq, ToShmem)]
|
|
pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, 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
|
|
}
|
|
}
|
|
|
|
impl<T> Clone for ArcSlice<T> {
|
|
fn clone(&self) -> Self {
|
|
ArcSlice(self.0.clone())
|
|
}
|
|
}
|
|
|
|
lazy_static! {
|
|
// ThinArc doesn't support alignments greater than align_of::<u64>.
|
|
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
|
|
ArcSlice::from_iter_leaked(iter::empty())
|
|
};
|
|
}
|
|
|
|
impl<T> Default for ArcSlice<T> {
|
|
#[allow(unsafe_code)]
|
|
fn default() -> Self {
|
|
debug_assert!(
|
|
mem::align_of::<T>() <= mem::align_of::<u64>(),
|
|
"Need to increase the alignment of EMPTY_ARC_SLICE"
|
|
);
|
|
unsafe {
|
|
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
|
|
let empty: Self = mem::transmute(empty);
|
|
debug_assert_eq!(empty.len(), 0);
|
|
empty
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Serialize> Serialize for ArcSlice<T> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
self.deref().serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArcSlice<T> {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let r = Vec::deserialize(deserializer)?;
|
|
Ok(ArcSlice::from_iter(r.into_iter()))
|
|
}
|
|
}
|
|
|
|
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,
|
|
{
|
|
if items.len() == 0 {
|
|
return Self::default();
|
|
}
|
|
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
|
|
}
|
|
|
|
/// Creates an Arc for a slice using the given iterator to generate the
|
|
/// slice, and marks the arc as intentionally leaked from the refcount
|
|
/// logging point of view.
|
|
#[inline]
|
|
pub fn from_iter_leaked<I>(items: I) -> Self
|
|
where
|
|
I: Iterator<Item = T> + ExactSizeIterator,
|
|
{
|
|
let thin_arc = ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items);
|
|
thin_arc.with_arc(|a| a.mark_as_intentionally_leaked());
|
|
ArcSlice(thin_arc)
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
|
|
/// Leaks an empty arc slice pointer, and returns it. Only to be used to
|
|
/// construct ArcSlices from FFI.
|
|
#[inline]
|
|
pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void {
|
|
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
|
|
let ptr = empty.0.ptr();
|
|
std::mem::forget(empty);
|
|
ptr as *mut _
|
|
}
|
|
}
|
|
|
|
/// 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>);
|