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;
8use core::{fmt, mem};
910/// This type is used by the custom derive to represent multiple [`VarULE`]
11/// fields packed into a single end-of-struct field. It is not recommended
12/// to use this type directly, use [`Tuple2VarULE`](crate::ule::tuplevar::Tuple2VarULE) etc instead.
13///
14/// Logically, consider it to be `(, , , ..)`
15/// where `` etc are potentially different [`VarULE`] types.
16///
17/// Internally, it is represented by a VarZeroSlice without the length part.
18#[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_receiver_is_total_eq(&self) -> () {
let _:
::core::cmp::AssertParamIsEq<VarZeroLengthlessSlice<[u8],
Format>>;
}
}Eq)]
19#[repr(transparent)]
20pub struct MultiFieldsULE<const LEN: usize, Format: VarZeroVecFormat>(
21VarZeroLengthlessSlice<[u8], Format>,
22);
2324impl<const LEN: usize, Format: VarZeroVecFormat> MultiFieldsULE<LEN, Format> {
25/// Compute the amount of bytes needed to support elements with lengths `lengths`
26#[inline]
27 #[expect(clippy::expect_used)] // See #1410
28pub fn compute_encoded_len_for(lengths: [usize; LEN]) -> usize {
29let lengths = lengths.map(BlankSliceEncoder);
30crate::varzerovec::components::compute_serializable_len_without_length::<_, _, Format>(
31&lengths,
32 )
33 .expect("Too many bytes to encode") as usize34 }
3536/// Construct a partially initialized MultiFieldsULE backed by a mutable byte buffer
37pub fn new_from_lengths_partially_initialized<'a>(
38 lengths: [usize; LEN],
39 output: &'a mut [u8],
40 ) -> &'a mut Self {
41let lengths = lengths.map(BlankSliceEncoder);
42crate::varzerovec::components::write_serializable_bytes_without_length::<_, _, Format>(
43&lengths, output,
44 );
45if 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!(
46 <VarZeroLengthlessSlice<[u8], Format>>::parse_bytes(LEN as u32, output).is_ok(),
47"Encoded slice must be valid VarZeroSlice"
48);
49unsafe {
50// Safe since write_serializable_bytes produces a valid VarZeroLengthlessSlice buffer with the right format
51let slice = <VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked_mut(output);
52// safe since `Self` is transparent over VarZeroLengthlessSlice<[u8], Format>
53mem::transmute::<&mut VarZeroLengthlessSlice<[u8], Format>, &mut Self>(slice)
54 }
55 }
5657/// Given a buffer of size obtained by [`Self::compute_encoded_len_for()`], write element A to index idx
58 ///
59 /// # Safety
60 /// - `idx` must be in range
61 /// - `T` must be the appropriate type expected by the custom derive in this usage of this type
62#[inline]
63pub unsafe fn set_field_at<T: VarULE + ?Sized, A: EncodeAsVarULE<T> + ?Sized>(
64&mut self,
65 idx: usize,
66 value: &A,
67 ) {
68value.encode_var_ule_write(self.0.get_bytes_at_mut(LENas u32, idx))
69 }
7071/// Validate field at `index` to see if it is a valid `T` VarULE type
72 ///
73 /// # Safety
74 ///
75 /// - `index` must be in range
76#[inline]
77pub unsafe fn validate_field<T: VarULE + ?Sized>(&self, index: usize) -> Result<(), UleError> {
78 T::validate_bytes(self.0.get_unchecked(LENas u32, index))
79 }
8081/// Get field at `index` as a value of type T
82 ///
83 /// # Safety
84 ///
85 /// - `index` must be in range
86 /// - Element at `index` must have been created with the VarULE type T
87#[inline]
88pub unsafe fn get_field<T: VarULE + ?Sized>(&self, index: usize) -> &T {
89 T::from_bytes_unchecked(self.0.get_unchecked(LENas u32, index))
90 }
9192/// Construct from a byte slice
93 ///
94 /// # Safety
95 /// - byte slice must be a valid VarZeroLengthlessSlice<[u8], Format> with length LEN
96#[inline]
97pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
98// &Self is transparent over &VZS<..> with the right format
99mem::transmute(<VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked(bytes))
100 }
101102/// Get the bytes behind this value
103pub fn as_bytes(&self) -> &[u8] {
104self.0.as_bytes()
105 }
106}
107108impl<const LEN: usize, Format: VarZeroVecFormat> fmt::Debugfor MultiFieldsULE<LEN, Format> {
109fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110f.write_fmt(format_args!("MultiFieldsULE<{1}>({0:?})", self.0.as_bytes(),
LEN))write!(f, "MultiFieldsULE<{LEN}>({:?})", self.0.as_bytes())111 }
112}
113/// This lets us conveniently use the EncodeAsVarULE functionality to create
114/// `VarZeroVec<[u8]>`s that have the right amount of space for elements
115/// without having to duplicate any unsafe code
116#[repr(transparent)]
117struct BlankSliceEncoder(usize);
118119unsafe impl EncodeAsVarULE<[u8]> for BlankSliceEncoder {
120fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R {
121// unnecessary if the other two are implemented
122::core::panicking::panic("internal error: entered unreachable code")unreachable!()123 }
124125#[inline]
126fn encode_var_ule_len(&self) -> usize {
127self.0
128}
129130#[inline]
131fn encode_var_ule_write(&self, _dst: &mut [u8]) {
132// do nothing
133}
134}
135136// Safety (based on the safety checklist on the VarULE trait):
137// 1. MultiFieldsULE does not include any uninitialized or padding bytes (achieved by being transparent over a VarULE type)
138// 2. MultiFieldsULE is aligned to 1 byte (achieved by being transparent over a VarULE type)
139// 3. The impl of `validate_bytes()` returns an error if any byte is not valid.
140// 4. The impl of `validate_bytes()` returns an error if the slice cannot be used in its entirety
141// 5. The impl of `from_bytes_unchecked()` returns a reference to the same data.
142// 6. All other methods are defaulted
143// 7. `MultiFieldsULE` byte equality is semantic equality (achieved by being transparent over a VarULE type)
144unsafe impl<const LEN: usize, Format: VarZeroVecFormat> VarULEfor MultiFieldsULE<LEN, Format> {
145/// Note: MultiFieldsULE is usually used in cases where one should be calling .validate_field() directly for
146 /// each field, rather than using the regular VarULE impl.
147 ///
148 /// This impl exists so that EncodeAsVarULE can work.
149#[inline]
150fn validate_bytes(slice: &[u8]) -> Result<(), UleError> {
151 <VarZeroLengthlessSlice<[u8], Format>>::parse_bytes(LENas u32, slice).map(|_| ())
152 }
153154#[inline]
155unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
156// &Self is transparent over &VZS<..>
157mem::transmute(<VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked(bytes))
158 }
159}