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