1 // This file is part of ICU4X. For terms of use, please see the file 2 // called LICENSE at the top level of the ICU4X source tree 3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). 4 5 use super::components::VarZeroVecComponents; 6 use super::*; 7 use crate::ule::*; 8 use core::marker::PhantomData; 9 use core::mem; 10 11 /// A slice representing the index and data tables of a VarZeroVec, 12 /// *without* any length fields. The length field is expected to be stored elsewhere. 13 /// 14 /// Without knowing the length this is of course unsafe to use directly. 15 #[repr(transparent)] 16 #[derive(PartialEq, Eq)] 17 pub(crate) struct VarZeroLengthlessSlice<T: ?Sized, F> { 18 marker: PhantomData<(F, T)>, 19 /// The original slice this was constructed from 20 // Safety invariant: This field must have successfully passed through 21 // VarZeroVecComponents::parse_bytes_with_length() with the length 22 // associated with this value. 23 entire_slice: [u8], 24 } 25 26 impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroLengthlessSlice<T, F> { 27 /// Obtain a [`VarZeroVecComponents`] borrowing from the internal buffer 28 /// 29 /// Safety: `len` must be the length associated with this value 30 #[inline] as_components<'a>(&'a self, len: u32) -> VarZeroVecComponents<'a, T, F>31 pub(crate) unsafe fn as_components<'a>(&'a self, len: u32) -> VarZeroVecComponents<'a, T, F> { 32 unsafe { 33 // safety: VarZeroSlice is guaranteed to parse here 34 VarZeroVecComponents::from_bytes_unchecked_with_length(len, &self.entire_slice) 35 } 36 } 37 38 /// Parse a VarZeroLengthlessSlice from a slice of the appropriate format 39 /// 40 /// Slices of the right format can be obtained via [`VarZeroSlice::as_bytes()`] parse_bytes<'a>(len: u32, slice: &'a [u8]) -> Result<&'a Self, UleError>41 pub fn parse_bytes<'a>(len: u32, slice: &'a [u8]) -> Result<&'a Self, UleError> { 42 let _ = VarZeroVecComponents::<T, F>::parse_bytes_with_length(len, slice) 43 .map_err(|_| UleError::parse::<Self>())?; 44 unsafe { 45 // Safety: We just verified that it is of the correct format. 46 Ok(Self::from_bytes_unchecked(slice)) 47 } 48 } 49 50 /// Uses a `&[u8]` buffer as a `VarZeroLengthlessSlice<T>` without any verification. 51 /// 52 /// # Safety 53 /// 54 /// `bytes` need to be an output from [`VarZeroLengthlessSlice::as_bytes()`], or alternatively 55 /// successfully pass through `parse_bytes` (with `len`) 56 /// 57 /// The length associated with this value will be the length associated with the original slice. from_bytes_unchecked(bytes: &[u8]) -> &Self58 pub(crate) const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { 59 // self is really just a wrapper around a byte slice 60 mem::transmute(bytes) 61 } 62 63 /// Uses a `&mut [u8]` buffer as a `VarZeroLengthlessSlice<T>` without any verification. 64 /// 65 /// # Safety 66 /// 67 /// `bytes` need to be an output from [`VarZeroLengthlessSlice::as_bytes()`], or alternatively 68 /// be valid to be passed to `from_bytes_unchecked_with_length` 69 /// 70 /// The length associated with this value will be the length associated with the original slice. from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut Self71 pub(crate) unsafe fn from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut Self { 72 // self is really just a wrapper around a byte slice 73 mem::transmute(bytes) 74 } 75 76 /// Get one of this slice's elements 77 /// 78 /// # Safety 79 /// 80 /// `index` must be in range, and `len` must be the length associated with this 81 /// instance of VarZeroLengthlessSlice. get_unchecked(&self, len: u32, idx: usize) -> &T82 pub(crate) unsafe fn get_unchecked(&self, len: u32, idx: usize) -> &T { 83 self.as_components(len).get_unchecked(idx) 84 } 85 86 /// Get a reference to the entire encoded backing buffer of this slice 87 /// 88 /// The bytes can be passed back to [`Self::parse_bytes()`]. 89 /// 90 /// To take the bytes as a vector, see [`VarZeroVec::into_bytes()`]. 91 #[inline] as_bytes(&self) -> &[u8]92 pub(crate) const fn as_bytes(&self) -> &[u8] { 93 &self.entire_slice 94 } 95 96 /// Get the bytes behind this as a mutable slice 97 /// 98 /// # Safety 99 /// 100 /// - `len` is the length associated with this VarZeroLengthlessSlice 101 /// - The resultant slice is only mutated in a way such that it remains a valid `T` 102 /// 103 /// # Panics 104 /// 105 /// Panics when idx is not in bounds for this slice get_bytes_at_mut(&mut self, len: u32, idx: usize) -> &mut [u8]106 pub(crate) unsafe fn get_bytes_at_mut(&mut self, len: u32, idx: usize) -> &mut [u8] { 107 let components = self.as_components(len); 108 let range = components.get_things_range(idx); 109 let offset = components.get_indices_size(); 110 111 // get_indices_size() returns the start of the things slice, and get_things_range() 112 // returns a range in-bounds of the things slice 113 #[allow(clippy::indexing_slicing)] 114 &mut self.entire_slice[offset..][range] 115 } 116 } 117