Skip to main content

zerovec/ule/
multi.rs

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
5use super::*;
6use crate::varzerovec::lengthless::VarZeroLengthlessSlice;
7use crate::vecs::VarZeroVecFormat;
8#[cfg(doc)]
9use crate::VarZeroSlice;
10use core::fmt;
11
12/// 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>(
23    VarZeroLengthlessSlice<[u8], Format>,
24);
25
26impl<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
30    pub fn compute_encoded_len_for(lengths: [usize; LEN]) -> usize {
31        let lengths = lengths.map(BlankSliceEncoder);
32        crate::varzerovec::components::compute_serializable_len_without_length::<_, _, Format>(
33            &lengths,
34        )
35        .expect("Too many bytes to encode") as usize
36    }
37
38    /// Construct a partially initialized `MultiFieldsULE` backed by a mutable byte buffer
39    pub fn new_from_lengths_partially_initialized<'a>(
40        lengths: [usize; LEN],
41        output: &'a mut [u8],
42    ) -> &'a mut Self {
43        let lengths = lengths.map(BlankSliceEncoder);
44        crate::varzerovec::components::write_serializable_bytes_without_length::<_, _, Format>(
45            &lengths, output,
46        );
47        if 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        );
51        unsafe {
52            // Safe since write_serializable_bytes produces a valid VarZeroLengthlessSlice buffer with the right format
53            let slice = VarZeroLengthlessSlice::<[u8], Format>::from_bytes_unchecked_mut(output);
54            // safe since `Self` is transparent over VarZeroLengthlessSlice<[u8], Format>
55            &mut *(slice as *mut VarZeroLengthlessSlice<[u8], Format>
56                as *mut MultiFieldsULE<LEN, Format>)
57        }
58    }
59
60    /// 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]
66    pub unsafe fn set_field_at<T: VarULE + ?Sized, A: EncodeAsVarULE<T> + ?Sized>(
67        &mut self,
68        idx: usize,
69        value: &A,
70    ) {
71        value.encode_var_ule_write(self.0.get_bytes_at_mut(LEN as u32, idx))
72    }
73
74    /// 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]
80    pub unsafe fn validate_field<T: VarULE + ?Sized>(&self, index: usize) -> Result<(), UleError> {
81        T::validate_bytes(self.0.get_unchecked(LEN as u32, index))
82    }
83
84    /// 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]
91    pub unsafe fn get_field<T: VarULE + ?Sized>(&self, index: usize) -> &T {
92        T::from_bytes_unchecked(self.0.get_unchecked(LEN as u32, index))
93    }
94
95    /// Construct from a byte slice
96    ///
97    /// # Safety
98    /// - byte slice must be a valid `VarZeroLengthlessSlice<[u8], Format>` with length `LEN`
99    #[inline]
100    pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
101        // &Self is transparent over &VZS<..> with the right format
102        let slice = VarZeroLengthlessSlice::<[u8], Format>::from_bytes_unchecked(bytes);
103        &*(slice as *const VarZeroLengthlessSlice<[u8], Format>
104            as *const MultiFieldsULE<LEN, Format>)
105    }
106
107    /// Get the bytes behind this value
108    pub fn as_bytes(&self) -> &[u8] {
109        self.0.as_bytes()
110    }
111}
112
113impl<const LEN: usize, Format: VarZeroVecFormat> fmt::Debug for MultiFieldsULE<LEN, Format> {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        f.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);
123
124unsafe impl EncodeAsVarULE<[u8]> for BlankSliceEncoder {
125    fn 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    }
129
130    #[inline]
131    fn encode_var_ule_len(&self) -> usize {
132        self.0
133    }
134
135    #[inline]
136    fn encode_var_ule_write(&self, _dst: &mut [u8]) {
137        // do nothing
138    }
139}
140
141// 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> VarULE for 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]
155    fn validate_bytes(slice: &[u8]) -> Result<(), UleError> {
156        VarZeroLengthlessSlice::<[u8], Format>::parse_bytes(LEN as u32, slice).map(|_| ())
157    }
158
159    #[inline]
160    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
161        // &Self is transparent over &VZS<..>
162        let slice = VarZeroLengthlessSlice::<[u8], Format>::from_bytes_unchecked(bytes);
163        &*(slice as *const VarZeroLengthlessSlice<[u8], Format>
164            as *const MultiFieldsULE<LEN, Format>)
165    }
166}