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 5 use super::*; 6 use crate::varzerovec::lengthless::VarZeroLengthlessSlice; 7 use crate::vecs::VarZeroVecFormat; 8 use core::{fmt, mem}; 9 10 /// 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(PartialEq, Eq)] 19 #[repr(transparent)] 20 pub struct MultiFieldsULE<const LEN: usize, Format: VarZeroVecFormat>( 21 VarZeroLengthlessSlice<[u8], Format>, 22 ); 23 24 impl<const LEN: usize, Format: VarZeroVecFormat> MultiFieldsULE<LEN, Format> { 25 /// Compute the amount of bytes needed to support elements with lengths `lengths` 26 #[inline] 27 #[allow(clippy::expect_used)] // See #1410 compute_encoded_len_for(lengths: [usize; LEN]) -> usize28 pub fn compute_encoded_len_for(lengths: [usize; LEN]) -> usize { 29 let lengths = lengths.map(BlankSliceEncoder); 30 crate::varzerovec::components::compute_serializable_len_without_length::<_, _, Format>( 31 &lengths, 32 ) 33 .expect("Too many bytes to encode") as usize 34 } 35 36 /// Construct a partially initialized MultiFieldsULE backed by a mutable byte buffer new_from_lengths_partially_initialized<'a>( lengths: [usize; LEN], output: &'a mut [u8], ) -> &'a mut Self37 pub fn new_from_lengths_partially_initialized<'a>( 38 lengths: [usize; LEN], 39 output: &'a mut [u8], 40 ) -> &'a mut Self { 41 let lengths = lengths.map(BlankSliceEncoder); 42 crate::varzerovec::components::write_serializable_bytes_without_length::<_, _, Format>( 43 &lengths, output, 44 ); 45 debug_assert!( 46 <VarZeroLengthlessSlice<[u8], Format>>::parse_bytes(LEN as u32, output).is_ok(), 47 "Encoded slice must be valid VarZeroSlice" 48 ); 49 unsafe { 50 // Safe since write_serializable_bytes produces a valid VarZeroLengthlessSlice buffer with the right format 51 let slice = <VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked_mut(output); 52 // safe since `Self` is transparent over VarZeroLengthlessSlice<[u8], Format> 53 mem::transmute::<&mut VarZeroLengthlessSlice<[u8], Format>, &mut Self>(slice) 54 } 55 } 56 57 /// 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] set_field_at<T: VarULE + ?Sized, A: EncodeAsVarULE<T> + ?Sized>( &mut self, idx: usize, value: &A, )63 pub unsafe fn set_field_at<T: VarULE + ?Sized, A: EncodeAsVarULE<T> + ?Sized>( 64 &mut self, 65 idx: usize, 66 value: &A, 67 ) { 68 value.encode_var_ule_write(self.0.get_bytes_at_mut(LEN as u32, idx)) 69 } 70 71 /// 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] validate_field<T: VarULE + ?Sized>(&self, index: usize) -> Result<(), UleError>77 pub unsafe fn validate_field<T: VarULE + ?Sized>(&self, index: usize) -> Result<(), UleError> { 78 T::validate_bytes(self.0.get_unchecked(LEN as u32, index)) 79 } 80 81 /// 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] get_field<T: VarULE + ?Sized>(&self, index: usize) -> &T88 pub unsafe fn get_field<T: VarULE + ?Sized>(&self, index: usize) -> &T { 89 T::from_bytes_unchecked(self.0.get_unchecked(LEN as u32, index)) 90 } 91 92 /// Construct from a byte slice 93 /// 94 /// # Safety 95 /// - byte slice must be a valid VarZeroLengthlessSlice<[u8], Format> with length LEN 96 #[inline] from_bytes_unchecked(bytes: &[u8]) -> &Self97 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { 98 // &Self is transparent over &VZS<..> with the right format 99 mem::transmute(<VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked(bytes)) 100 } 101 102 /// Get the bytes behind this value as_bytes(&self) -> &[u8]103 pub fn as_bytes(&self) -> &[u8] { 104 self.0.as_bytes() 105 } 106 } 107 108 impl<const LEN: usize, Format: VarZeroVecFormat> fmt::Debug for MultiFieldsULE<LEN, Format> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 110 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)] 117 struct BlankSliceEncoder(usize); 118 119 unsafe impl EncodeAsVarULE<[u8]> for BlankSliceEncoder { encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R120 fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R { 121 // unnecessary if the other two are implemented 122 unreachable!() 123 } 124 125 #[inline] encode_var_ule_len(&self) -> usize126 fn encode_var_ule_len(&self) -> usize { 127 self.0 128 } 129 130 #[inline] encode_var_ule_write(&self, _dst: &mut [u8])131 fn encode_var_ule_write(&self, _dst: &mut [u8]) { 132 // do nothing 133 } 134 } 135 136 // 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) 144 unsafe impl<const LEN: usize, Format: VarZeroVecFormat> VarULE for 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] validate_bytes(slice: &[u8]) -> Result<(), UleError>150 fn validate_bytes(slice: &[u8]) -> Result<(), UleError> { 151 <VarZeroLengthlessSlice<[u8], Format>>::parse_bytes(LEN as u32, slice).map(|_| ()) 152 } 153 154 #[inline] from_bytes_unchecked(bytes: &[u8]) -> &Self155 unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { 156 // &Self is transparent over &VZS<..> 157 mem::transmute(<VarZeroLengthlessSlice<[u8], Format>>::from_bytes_unchecked(bytes)) 158 } 159 } 160