• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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