From 4e8199b572f2035b7749cba276ece3a26630d23e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:21 +0200 Subject: Adding upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/zerovec/src/ule/multi.rs | 152 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 vendor/zerovec/src/ule/multi.rs (limited to 'vendor/zerovec/src/ule/multi.rs') diff --git a/vendor/zerovec/src/ule/multi.rs b/vendor/zerovec/src/ule/multi.rs new file mode 100644 index 000000000..1eacfac69 --- /dev/null +++ b/vendor/zerovec/src/ule/multi.rs @@ -0,0 +1,152 @@ +// 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::*; +use crate::varzerovec::Index32; +use crate::VarZeroSlice; +use core::mem; + +/// This type is used by the custom derive to represent multiple [`VarULE`] +/// fields packed into a single end-of-struct field. It is not recommended +/// to use this type directly. +/// +/// Logically, consider it to be `(V1, V2, V3, ..)` +/// where `V1` etc are potentially different [`VarULE`] types. +/// +/// Internally, it is represented by a VarZeroSlice. +#[derive(PartialEq, Eq)] +#[repr(transparent)] +pub struct MultiFieldsULE(VarZeroSlice<[u8], Index32>); + +impl MultiFieldsULE { + /// Compute the amount of bytes needed to support elements with lengths `lengths` + #[inline] + pub fn compute_encoded_len_for(lengths: &[usize]) -> usize { + #[allow(clippy::expect_used)] // See #1410 + unsafe { + // safe since BlankSliceEncoder is transparent over usize + let lengths = &*(lengths as *const [usize] as *const [BlankSliceEncoder]); + crate::varzerovec::components::compute_serializable_len::<_, _, Index32>(lengths) + .expect("Too many bytes to encode") as usize + } + } + + /// Construct a partially initialized MultiFieldsULE backed by a mutable byte buffer + pub fn new_from_lengths_partially_initialized<'a>( + lengths: &[usize], + output: &'a mut [u8], + ) -> &'a mut Self { + unsafe { + // safe since BlankSliceEncoder is transparent over usize + let lengths = &*(lengths as *const [usize] as *const [BlankSliceEncoder]); + crate::varzerovec::components::write_serializable_bytes::<_, _, Index32>( + lengths, output, + ); + debug_assert!( + >::validate_byte_slice(output).is_ok(), + "Encoded slice must be valid VarZeroSlice" + ); + // Safe since write_serializable_bytes produces a valid VarZeroSlice buffer + let slice = >::from_byte_slice_unchecked_mut(output); + // safe since `Self` is transparent over VarZeroSlice + mem::transmute::<&mut VarZeroSlice<_, Index32>, &mut Self>(slice) + } + } + + /// Given a buffer of size obtained by [`Self::compute_encoded_len_for()`], write element A to index idx + /// + /// # Safety + /// - `idx` must be in range + /// - `T` must be the appropriate type expected by the custom derive in this usage of this type + #[inline] + pub unsafe fn set_field_at + ?Sized>( + &mut self, + idx: usize, + value: &A, + ) { + value.encode_var_ule_write(self.0.get_bytes_at_mut(idx)) + } + + /// Validate field at `index` to see if it is a valid `T` VarULE type + /// + /// # Safety + /// + /// - `index` must be in range + #[inline] + pub unsafe fn validate_field( + &self, + index: usize, + ) -> Result<(), ZeroVecError> { + T::validate_byte_slice(self.0.get_unchecked(index)) + } + + /// Get field at `index` as a value of type T + /// + /// # Safety + /// + /// - `index` must be in range + /// - Element at `index` must have been created with the VarULE type T + #[inline] + pub unsafe fn get_field(&self, index: usize) -> &T { + T::from_byte_slice_unchecked(self.0.get_unchecked(index)) + } + + /// Construct from a byte slice + /// + /// # Safety + /// - byte slice must be a valid VarZeroSlice<[u8]> + #[inline] + pub unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self { + // &Self is transparent over &VZS<..> + mem::transmute(>::from_byte_slice_unchecked(bytes)) + } +} + +/// This lets us conveniently use the EncodeAsVarULE functionality to create +/// `VarZeroVec<[u8]>`s that have the right amount of space for elements +/// without having to duplicate any unsafe code +#[repr(transparent)] +struct BlankSliceEncoder(usize); + +unsafe impl EncodeAsVarULE<[u8]> for BlankSliceEncoder { + fn encode_var_ule_as_slices(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R { + // unnecessary if the other two are implemented + unreachable!() + } + + #[inline] + fn encode_var_ule_len(&self) -> usize { + self.0 + } + + #[inline] + fn encode_var_ule_write(&self, _dst: &mut [u8]) { + // do nothing + } +} + +// Safety (based on the safety checklist on the VarULE trait): +// 1. MultiFieldsULE does not include any uninitialized or padding bytes (achieved by being transparent over a VarULE type) +// 2. MultiFieldsULE is aligned to 1 byte (achieved by being transparent over a VarULE type) +// 3. The impl of `validate_byte_slice()` returns an error if any byte is not valid. +// 4. The impl of `validate_byte_slice()` returns an error if the slice cannot be used in its entirety +// 5. The impl of `from_byte_slice_unchecked()` returns a reference to the same data. +// 6. All other methods are defaulted +// 7. `MultiFieldsULE` byte equality is semantic equality (achieved by being transparent over a VarULE type) +unsafe impl VarULE for MultiFieldsULE { + /// Note: MultiFieldsULE is usually used in cases where one should be calling .validate_field() directly for + /// each field, rather than using the regular VarULE impl. + /// + /// This impl exists so that EncodeAsVarULE can work. + #[inline] + fn validate_byte_slice(slice: &[u8]) -> Result<(), ZeroVecError> { + >::validate_byte_slice(slice) + } + + #[inline] + unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self { + // &Self is transparent over &VZS<..> + mem::transmute(>::from_byte_slice_unchecked(bytes)) + } +} -- cgit v1.2.3