tinystr/
ule.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 crate::{TinyAsciiStr, UnvalidatedTinyAsciiStr};
6#[cfg(feature = "alloc")]
7use zerovec::maps::ZeroMapKV;
8use zerovec::ule::*;
9#[cfg(feature = "alloc")]
10use 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
21unsafe impl<const N: usize> ULE for TinyAsciiStr<N> {
22    #[inline]
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
36impl<const N: usize> NicheBytes<N> for TinyAsciiStr<N> {
37    // AsciiByte is 0..128
38    const NICHE_BIT_PATTERN: [u8; N] = [255; N];
39}
40
41impl<const N: usize> AsULE for TinyAsciiStr<N> {
42    type ULE = Self;
43
44    #[inline]
45    fn to_unaligned(self) -> Self::ULE {
46        self
47    }
48
49    #[inline]
50    fn from_unaligned(unaligned: Self::ULE) -> Self {
51        unaligned
52    }
53}
54
55#[cfg(feature = "alloc")]
56impl<'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
72unsafe impl<const N: usize> ULE for UnvalidatedTinyAsciiStr<N> {
73    #[inline]
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
82impl<const N: usize> AsULE for UnvalidatedTinyAsciiStr<N> {
83    type ULE = Self;
84
85    #[inline]
86    fn to_unaligned(self) -> Self::ULE {
87        self
88    }
89
90    #[inline]
91    fn from_unaligned(unaligned: Self::ULE) -> Self {
92        unaligned
93    }
94}
95
96#[cfg(feature = "alloc")]
97impl<'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)]
105mod test {
106    use crate::*;
107    use zerovec::*;
108
109    #[test]
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}