• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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