mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
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
This commit is contained in:
parent
2ed2151b3d
commit
0d5c4481b8
6 changed files with 98 additions and 3 deletions
66
components/style_traits/arc_slice.rs
Normal file
66
components/style_traits/arc_slice.rs
Normal file
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue