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