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 ).
45use super::*;
6use crate::varzerovec::lengthless::VarZeroLengthlessSlice;
7use crate::vecs::VarZeroVecFormat;
8#[cfg(doc)]
9use crate::VarZeroSlice;
10use core::fmt;
1112/// This type is used by the custom derive to represent multiple [`VarULE`]
13/// fields packed into a single end-of-struct field. It is not recommended
14/// to use this type directly, use [`Tuple2VarULE`](crate::ule::tuplevar::Tuple2VarULE) etc instead.
15///
16/// Logically, consider it to be `(, , , ..)`
17/// where ` ` etc are potentially different [`VarULE`] types.
18///
19/// Internally, it is represented by a [`VarZeroSlice`] without the length part.
20#[derive(#[automatically_derived]
impl<const LEN : usize, Format: ::core::cmp::PartialEq + VarZeroVecFormat>
::core::cmp::PartialEq for MultiFieldsULE<LEN, Format> {
#[inline]
fn eq(&self, other: &MultiFieldsULE<LEN, Format>) -> bool {
self.0 == other.0
}
}PartialEq, #[automatically_derived]
impl<const LEN : usize, Format: ::core::cmp::Eq + VarZeroVecFormat>
::core::cmp::Eq for MultiFieldsULE<LEN, Format> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _:
::core::cmp::AssertParamIsEq<VarZeroLengthlessSlice<[u8],
Format>>;
}
}Eq)]
21#[repr(transparent)]
22pub struct MultiFieldsULE<const LEN: usize, Format: VarZeroVecFormat>(
23VarZeroLengthlessSlice<[u8], Format>,
24);
2526impl<const LEN: usize, Format: VarZeroVecFormat> MultiFieldsULE<LEN, Format> {
27/// Compute the amount of bytes needed to support elements with lengths `lengths`
28#[inline]
29 #[expect(clippy::expect_used)] // See #1410
30pub fn compute_encoded_len_for(lengths: [usize; LEN]) -> usize {
31let lengths = lengths.map(BlankSliceEncoder);
32crate::varzerovec::components::compute_serializable_len_without_length::<_, _, Format>(
33&lengths,
34 )
35 .expect("Too many bytes to encode") as usize36 }
3738/// Construct a partially initialized `MultiFieldsULE` backed by a mutable byte buffer
39pub fn new_from_lengths_partially_initialized<'a>(
40 lengths: [usize; LEN],
41 output: &'a mut [u8],
42 ) -> &'a mut Self {
43let lengths = lengths.map(BlankSliceEncoder);
44crate::varzerovec::components::write_serializable_bytes_without_length::<_, _, Format>(
45&lengths, output,
46 );
47if true {
if !<VarZeroLengthlessSlice<[u8],
Format>>::parse_bytes(LEN as u32, output).is_ok() {
{
::core::panicking::panic_fmt(format_args!("Encoded slice must be valid VarZeroSlice"));
}
};
};debug_assert!(
48 <VarZeroLengthlessSlice<[u8], Format>>::parse_bytes(LEN as u32, output).is_ok(),
49"Encoded slice must be valid VarZeroSlice"
50);
51unsafe {
52// Safe since write_serializable_bytes produces a valid VarZeroLengthlessSlice buffer with the right format
53let slice = VarZeroLengthlessSlice::<[u8], Format>::from_bytes_unchecked_mut(output);
54// safe since `Self` is transparent over VarZeroLengthlessSlice<[u8], Format>
55&mut *(sliceas *mut VarZeroLengthlessSlice<[u8], Format>
56as *mut MultiFieldsULE<LEN, Format>)
57 }
58 }
5960/// Given a buffer of size obtained by [`Self::compute_encoded_len_for()`], write element A to index idx
61 ///
62 /// # Safety
63 /// - `idx` must be in range
64 /// - `T` must be the appropriate type expected by the custom derive in this usage of this type
65#[inline]
66pub unsafe fn set_field_at<T: VarULE + ?Sized, A: EncodeAsVarULE<T> + ?Sized>(
67&mut self,
68 idx: usize,
69 value: &A,
70 ) {
71value.encode_var_ule_write(self.0.get_bytes_at_mut(LENas u32, idx))
72 }
7374/// Validate field at `index` to see if it is a valid `T` [`VarULE`] type
75 ///
76 /// # Safety
77 ///
78 /// - `index` must be in range
79#[inline]
80pub unsafe fn validate_field<T: VarULE + ?Sized>(&self, index: usize) -> Result<(), UleError> {
81 T::validate_bytes(self.0.get_unchecked(LENas u32, index))
82 }
8384/// Get field at `index` as a value of type T
85 ///
86 /// # Safety
87 ///
88 /// - `index` must be in range
89 /// - Element at `index` must have been created with the [`VarULE`] type T
90#[inline]
91pub unsafe fn get_field<T: VarULE + ?Sized>(&self, index: usize) -> &T {
92 T::from_bytes_unchecked(self.0.get_unchecked(LENas u32, index))
93 }
9495/// Construct from a byte slice
96 ///
97 /// # Safety
98 /// - byte slice must be a valid `VarZeroLengthlessSlice<[u8], Format>` with length `LEN`
99#[inline]
100pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
101// &Self is transparent over &VZS<..> with the right format
102let slice = VarZeroLengthlessSlice::<[u8], Format>::from_bytes_unchecked(bytes);
103&*(sliceas *const VarZeroLengthlessSlice<[u8], Format>
104as *const MultiFieldsULE<LEN, Format>)
105 }
106107/// Get the bytes behind this value
108pub fn as_bytes(&self) -> &[u8] {
109self.0.as_bytes()
110 }
111}
112113impl<const LEN: usize, Format: VarZeroVecFormat> fmt::Debugfor MultiFieldsULE<LEN, Format> {
114fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115f.write_fmt(format_args!("MultiFieldsULE<{1}>({0:?})", self.0.as_bytes(),
LEN))write!(f, "MultiFieldsULE<{LEN}>({:?})", self.0.as_bytes())116 }
117}
118/// This lets us conveniently use the `EncodeAsVarULE` functionality to create
119/// `VarZeroVec<[u8]>`s that have the right amount of space for elements
120/// without having to duplicate any unsafe code
121#[repr(transparent)]
122struct BlankSliceEncoder(usize);
123124unsafe impl EncodeAsVarULE<[u8]> for BlankSliceEncoder {
125fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R {
126// unnecessary if the other two are implemented
127::core::panicking::panic("internal error: entered unreachable code")unreachable!()128 }
129130#[inline]
131fn encode_var_ule_len(&self) -> usize {
132self.0
133}
134135#[inline]
136fn encode_var_ule_write(&self, _dst: &mut [u8]) {
137// do nothing
138}
139}
140141// Safety (based on the safety checklist on the VarULE trait):
142// 1. MultiFieldsULE does not include any uninitialized or padding bytes (achieved by being transparent over a VarULE type)
143// 2. MultiFieldsULE is aligned to 1 byte (achieved by being transparent over a VarULE type)
144// 3. The impl of `validate_bytes()` returns an error if any byte is not valid.
145// 4. The impl of `validate_bytes()` returns an error if the slice cannot be used in its entirety
146// 5. The impl of `from_bytes_unchecked()` returns a reference to the same data.
147// 6. All other methods are defaulted
148// 7. `MultiFieldsULE` byte equality is semantic equality (achieved by being transparent over a VarULE type)
149unsafe impl<const LEN: usize, Format: VarZeroVecFormat> VarULEfor MultiFieldsULE<LEN, Format> {
150/// Note: `MultiFieldsULE` is usually used in cases where one should be calling .`validate_field()` directly for
151 /// each field, rather than using the regular `VarULE` impl.
152 ///
153 /// This impl exists so that `EncodeAsVarULE` can work.
154#[inline]
155fn validate_bytes(slice: &[u8]) -> Result<(), UleError> {
156 VarZeroLengthlessSlice::<[u8], Format>::parse_bytes(LENas u32, slice).map(|_| ())
157 }
158159#[inline]
160unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
161// &Self is transparent over &VZS<..>
162let slice = VarZeroLengthlessSlice::<[u8], Format>::from_bytes_unchecked(bytes);
163&*(sliceas *const VarZeroLengthlessSlice<[u8], Format>
164as *const MultiFieldsULE<LEN, Format>)
165 }
166}