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 crate::{TinyAsciiStr, UnvalidatedTinyAsciiStr}; 6 #[cfg(feature = "alloc")] 7 use zerovec::maps::ZeroMapKV; 8 use zerovec::ule::*; 9 #[cfg(feature = "alloc")] 10 use zerovec::{ZeroSlice, ZeroVec}; 11 12 // Safety (based on the safety checklist on the ULE trait): 13 // 1. TinyAsciiStr does not include any uninitialized or padding bytes. 14 // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant) 15 // 2. TinyAsciiStr is aligned to 1 byte. 16 // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant) 17 // 3. The impl of validate_bytes() returns an error if any byte is not valid. 18 // 4. The impl of validate_bytes() returns an error if there are extra bytes. 19 // 5. The other ULE methods use the default impl. 20 // 6. TinyAsciiStr byte equality is semantic equality 21 unsafe impl<const N: usize> ULE for TinyAsciiStr<N> { 22 #[inline] validate_bytes(bytes: &[u8]) -> Result<(), UleError>23 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> { 24 if bytes.len() % N != 0 { 25 return Err(UleError::length::<Self>(bytes.len())); 26 } 27 // Validate the bytes 28 for chunk in bytes.chunks_exact(N) { 29 let _ = TinyAsciiStr::<N>::try_from_utf8_inner(chunk, true) 30 .map_err(|_| UleError::parse::<Self>())?; 31 } 32 Ok(()) 33 } 34 } 35 36 impl<const N: usize> NicheBytes<N> for TinyAsciiStr<N> { 37 // AsciiByte is 0..128 38 const NICHE_BIT_PATTERN: [u8; N] = [255; N]; 39 } 40 41 impl<const N: usize> AsULE for TinyAsciiStr<N> { 42 type ULE = Self; 43 44 #[inline] to_unaligned(self) -> Self::ULE45 fn to_unaligned(self) -> Self::ULE { 46 self 47 } 48 49 #[inline] from_unaligned(unaligned: Self::ULE) -> Self50 fn from_unaligned(unaligned: Self::ULE) -> Self { 51 unaligned 52 } 53 } 54 55 #[cfg(feature = "alloc")] 56 impl<'a, const N: usize> ZeroMapKV<'a> for TinyAsciiStr<N> { 57 type Container = ZeroVec<'a, TinyAsciiStr<N>>; 58 type Slice = ZeroSlice<TinyAsciiStr<N>>; 59 type GetType = TinyAsciiStr<N>; 60 type OwnedType = TinyAsciiStr<N>; 61 } 62 63 // Safety (based on the safety checklist on the ULE trait): 64 // 1. UnvalidatedTinyAsciiStr does not include any uninitialized or padding bytes. 65 // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant) 66 // 2. UnvalidatedTinyAsciiStr is aligned to 1 byte. 67 // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant) 68 // 3. The impl of validate_bytes() returns an error if any byte is not valid. 69 // 4. The impl of validate_bytes() returns an error if there are extra bytes. 70 // 5. The other ULE methods use the default impl. 71 // 6. UnvalidatedTinyAsciiStr byte equality is semantic equality 72 unsafe impl<const N: usize> ULE for UnvalidatedTinyAsciiStr<N> { 73 #[inline] validate_bytes(bytes: &[u8]) -> Result<(), UleError>74 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> { 75 if bytes.len() % N != 0 { 76 return Err(UleError::length::<Self>(bytes.len())); 77 } 78 Ok(()) 79 } 80 } 81 82 impl<const N: usize> AsULE for UnvalidatedTinyAsciiStr<N> { 83 type ULE = Self; 84 85 #[inline] to_unaligned(self) -> Self::ULE86 fn to_unaligned(self) -> Self::ULE { 87 self 88 } 89 90 #[inline] from_unaligned(unaligned: Self::ULE) -> Self91 fn from_unaligned(unaligned: Self::ULE) -> Self { 92 unaligned 93 } 94 } 95 96 #[cfg(feature = "alloc")] 97 impl<'a, const N: usize> ZeroMapKV<'a> for UnvalidatedTinyAsciiStr<N> { 98 type Container = ZeroVec<'a, UnvalidatedTinyAsciiStr<N>>; 99 type Slice = ZeroSlice<UnvalidatedTinyAsciiStr<N>>; 100 type GetType = UnvalidatedTinyAsciiStr<N>; 101 type OwnedType = UnvalidatedTinyAsciiStr<N>; 102 } 103 104 #[cfg(test)] 105 mod test { 106 use crate::*; 107 use zerovec::*; 108 109 #[test] test_zerovec()110 fn test_zerovec() { 111 let mut vec = ZeroVec::<TinyAsciiStr<7>>::new(); 112 113 vec.with_mut(|v| v.push("foobar".parse().unwrap())); 114 vec.with_mut(|v| v.push("baz".parse().unwrap())); 115 vec.with_mut(|v| v.push("quux".parse().unwrap())); 116 117 let bytes = vec.as_bytes(); 118 119 let vec: ZeroVec<TinyAsciiStr<7>> = ZeroVec::parse_bytes(bytes).unwrap(); 120 121 assert_eq!(&*vec.get(0).unwrap(), "foobar"); 122 assert_eq!(&*vec.get(1).unwrap(), "baz"); 123 assert_eq!(&*vec.get(2).unwrap(), "quux"); 124 } 125 } 126