zerovec/varzerovec/
lengthless.rs

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
5use super::components::VarZeroVecComponents;
6use super::*;
7use crate::ule::*;
8use core::marker::PhantomData;
9use 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)]
17pub(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
26impl<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]
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()`]
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.
58    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.
71    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.
82    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]
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
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}