/* 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 { ptr: NonNull, len: usize, _phantom: PhantomData, } impl Default for OwnedSlice { #[inline] fn default() -> Self { Self { len: 0, ptr: NonNull::dangling(), _phantom: PhantomData, } } } impl Drop for OwnedSlice { #[inline] fn drop(&mut self) { if self.len != 0 { let _ = mem::replace(self, Self::default()).into_vec(); } } } unsafe impl Send for OwnedSlice {} unsafe impl Sync for OwnedSlice {} impl Clone for OwnedSlice { #[inline] fn clone(&self) -> Self { Self::from_slice(&**self) } } impl fmt::Debug for OwnedSlice { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { self.deref().fmt(formatter) } } impl PartialEq for OwnedSlice { fn eq(&self, other: &Self) -> bool { self.deref().eq(other.deref()) } } impl Eq for OwnedSlice {} impl OwnedSlice { /// 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 { 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 IntoIterator for OwnedSlice { type Item = T; type IntoIter = as IntoIterator>::IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { self.into_vec().into_iter() } } impl Deref for OwnedSlice { type Target = [T]; #[inline(always)] fn deref(&self) -> &Self::Target { unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) } } } impl DerefMut for OwnedSlice { #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) } } } impl From> for OwnedSlice { #[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 From> for OwnedSlice { #[inline] fn from(b: Vec) -> Self { Self::from(b.into_boxed_slice()) } } impl MallocShallowSizeOf for OwnedSlice { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { unsafe { ops.malloc_size_of(self.ptr.as_ptr()) } } } impl MallocSizeOf for OwnedSlice { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { self.shallow_size_of(ops) + (**self).size_of(ops) } } impl ToShmem for OwnedSlice { fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result { unsafe { let dest = to_shmem::to_shmem_slice(self.iter(), builder)?; Ok(mem::ManuallyDrop::new(Self::from(Box::from_raw(dest)))) } } } impl iter::FromIterator for OwnedSlice { #[inline] fn from_iter>(iter: I) -> Self { Vec::from_iter(iter).into() } } impl Serialize for OwnedSlice { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.deref().serialize(serializer) } } impl<'de, T: Deserialize<'de>> Deserialize<'de> for OwnedSlice { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let r = Box::<[T]>::deserialize(deserializer)?; Ok(r.into()) } }