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