tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

arc_slice.rs (4996B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! A thin atomically-reference-counted slice.
      6 
      7 use serde::de::{Deserialize, Deserializer};
      8 use serde::ser::{Serialize, Serializer};
      9 use servo_arc::ThinArc;
     10 use std::ops::Deref;
     11 use std::ptr::NonNull;
     12 use std::sync::LazyLock;
     13 use std::{
     14    hash::{Hash, Hasher},
     15    iter, mem,
     16 };
     17 
     18 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf};
     19 
     20 /// A canary that we stash in ArcSlices.
     21 ///
     22 /// Given we cannot use a zero-sized-type for the header, since well, C++
     23 /// doesn't have zsts, and we want to use cbindgen for this type, we may as well
     24 /// assert some sanity at runtime.
     25 ///
     26 /// We use an u64, to guarantee that we can use a single singleton for every
     27 /// empty slice, even if the types they hold are aligned differently.
     28 const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3;
     29 
     30 /// A wrapper type for a refcounted slice using ThinArc.
     31 #[repr(C)]
     32 #[derive(Debug, Eq, PartialEq, ToShmem)]
     33 pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>);
     34 
     35 impl<T> Deref for ArcSlice<T> {
     36    type Target = [T];
     37 
     38    #[inline]
     39    fn deref(&self) -> &Self::Target {
     40        debug_assert_eq!(self.0.header, ARC_SLICE_CANARY);
     41        self.0.slice()
     42    }
     43 }
     44 
     45 impl<T> Clone for ArcSlice<T> {
     46    fn clone(&self) -> Self {
     47        ArcSlice(self.0.clone())
     48    }
     49 }
     50 
     51 // ThinArc doesn't support alignments greater than align_of::<u64>.
     52 static EMPTY_ARC_SLICE: LazyLock<ArcSlice<u64>> =
     53    LazyLock::new(|| ArcSlice::from_iter_leaked(iter::empty()));
     54 
     55 impl<T> Default for ArcSlice<T> {
     56    #[allow(unsafe_code)]
     57    fn default() -> Self {
     58        debug_assert!(
     59            mem::align_of::<T>() <= mem::align_of::<u64>(),
     60            "Need to increase the alignment of EMPTY_ARC_SLICE"
     61        );
     62        unsafe {
     63            let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
     64            let empty: Self = mem::transmute(empty);
     65            debug_assert_eq!(empty.len(), 0);
     66            empty
     67        }
     68    }
     69 }
     70 
     71 impl<T: Serialize> Serialize for ArcSlice<T> {
     72    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     73    where
     74        S: Serializer,
     75    {
     76        self.deref().serialize(serializer)
     77    }
     78 }
     79 
     80 impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArcSlice<T> {
     81    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     82    where
     83        D: Deserializer<'de>,
     84    {
     85        let r = Vec::deserialize(deserializer)?;
     86        Ok(ArcSlice::from_iter(r.into_iter()))
     87    }
     88 }
     89 
     90 impl<T> ArcSlice<T> {
     91    /// Creates an Arc for a slice using the given iterator to generate the
     92    /// slice.
     93    #[inline]
     94    pub fn from_iter<I>(items: I) -> Self
     95    where
     96        I: Iterator<Item = T> + ExactSizeIterator,
     97    {
     98        if items.len() == 0 {
     99            return Self::default();
    100        }
    101        ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
    102    }
    103 
    104    /// Creates an Arc for a slice using the given iterator to generate the
    105    /// slice, and marks the arc as intentionally leaked from the refcount
    106    /// logging point of view.
    107    #[inline]
    108    pub fn from_iter_leaked<I>(items: I) -> Self
    109    where
    110        I: Iterator<Item = T> + ExactSizeIterator,
    111    {
    112        let arc = ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items);
    113        arc.mark_as_intentionally_leaked();
    114        ArcSlice(arc)
    115    }
    116 
    117    /// Creates a value that can be passed via FFI, and forgets this value
    118    /// altogether.
    119    #[inline]
    120    pub fn forget(self) -> ForgottenArcSlicePtr<T> {
    121        let ret = ForgottenArcSlicePtr(self.0.raw_ptr().cast());
    122        mem::forget(self);
    123        ret
    124    }
    125 
    126    /// Leaks an empty arc slice pointer, and returns it. Only to be used to
    127    /// construct ArcSlices from FFI.
    128    #[inline]
    129    pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void {
    130        let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
    131        let ptr = empty.0.raw_ptr();
    132        std::mem::forget(empty);
    133        ptr.cast().as_ptr()
    134    }
    135 
    136    /// Returns whether there's only one reference to this ArcSlice.
    137    pub fn is_unique(&self) -> bool {
    138        self.0.is_unique()
    139    }
    140 }
    141 
    142 impl<T: MallocSizeOf> MallocUnconditionalSizeOf for ArcSlice<T> {
    143    #[allow(unsafe_code)]
    144    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
    145        let mut size = unsafe { ops.malloc_size_of(self.0.heap_ptr()) };
    146        for el in self.iter() {
    147            size += el.size_of(ops);
    148        }
    149        size
    150    }
    151 }
    152 
    153 impl<T: Hash> Hash for ArcSlice<T> {
    154    fn hash<H: Hasher>(&self, state: &mut H) {
    155        T::hash_slice(&**self, state)
    156    }
    157 }
    158 
    159 /// The inner pointer of an ArcSlice<T>, to be sent via FFI.
    160 /// The type of the pointer is a bit of a lie, we just want to preserve the type
    161 /// but these pointers cannot be constructed outside of this crate, so we're
    162 /// good.
    163 #[repr(C)]
    164 pub struct ForgottenArcSlicePtr<T>(NonNull<T>);