summaryrefslogtreecommitdiffstats
path: root/servo/components/style_traits/owned_slice.rs
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style_traits/owned_slice.rs')
-rw-r--r--servo/components/style_traits/owned_slice.rs198
1 files changed, 198 insertions, 0 deletions
diff --git a/servo/components/style_traits/owned_slice.rs b/servo/components/style_traits/owned_slice.rs
new file mode 100644
index 0000000000..36ba3162e5
--- /dev/null
+++ b/servo/components/style_traits/owned_slice.rs
@@ -0,0 +1,198 @@
+/* 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/. */
+
+#![allow(unsafe_code)]
+
+//! A replacement for `Box<[T]>` that cbindgen can understand.
+
+use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
+use serde::de::{Deserialize, Deserializer};
+use serde::ser::{Serialize, Serializer};
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+use std::ptr::NonNull;
+use std::{fmt, iter, mem, slice};
+use to_shmem::{self, 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.
+///
+/// cbindgen:derive-eq=false
+/// cbindgen:derive-neq=false
+#[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
+ }
+
+ /// 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> IntoIterator for OwnedSlice<T> {
+ type Item = T;
+ type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.into_vec().into_iter()
+ }
+}
+
+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) -> to_shmem::Result<Self> {
+ unsafe {
+ let dest = to_shmem::to_shmem_slice(self.iter(), builder)?;
+ Ok(mem::ManuallyDrop::new(Self::from(Box::from_raw(dest))))
+ }
+ }
+}
+
+impl<T> iter::FromIterator<T> for OwnedSlice<T> {
+ #[inline]
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
+ Vec::from_iter(iter).into()
+ }
+}
+
+impl<T: Serialize> Serialize for OwnedSlice<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 OwnedSlice<T> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let r = Box::<[T]>::deserialize(deserializer)?;
+ Ok(r.into())
+ }
+}