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; |
6 | use crate::TinyStrError; |
7 | |
8 | /// A fixed-length bytes array that is expected to be an ASCII string but does not enforce that invariant. |
9 | /// |
10 | /// Use this type instead of `TinyAsciiStr` if you don't need to enforce ASCII during deserialization. For |
11 | /// example, strings that are keys of a map don't need to ever be reified as `TinyAsciiStr`s. |
12 | /// |
13 | /// The main advantage of this type over `[u8; N]` is that it serializes as a string in |
14 | /// human-readable formats like JSON. |
15 | #[derive (Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] |
16 | pub struct UnvalidatedTinyAsciiStr<const N: usize>(pub(crate) [u8; N]); |
17 | |
18 | impl<const N: usize> UnvalidatedTinyAsciiStr<N> { |
19 | #[inline ] |
20 | // Converts into a [`TinyAsciiStr`]. Fails if the bytes are not valid ASCII. |
21 | pub fn try_into_tinystr(&self) -> Result<TinyAsciiStr<N>, TinyStrError> { |
22 | TinyAsciiStr::try_from_raw(self.0) |
23 | } |
24 | |
25 | #[doc (hidden)] |
26 | pub const fn from_bytes_unchecked(bytes: [u8; N]) -> Self { |
27 | Self(bytes) |
28 | } |
29 | } |
30 | |
31 | impl<const N: usize> TinyAsciiStr<N> { |
32 | #[inline ] |
33 | // Converts into a [`UnvalidatedTinyAsciiStr`] |
34 | pub const fn to_unvalidated(self) -> UnvalidatedTinyAsciiStr<N> { |
35 | UnvalidatedTinyAsciiStr(*self.all_bytes()) |
36 | } |
37 | } |
38 | |
39 | #[cfg (feature = "serde" )] |
40 | impl<const N: usize> serde::Serialize for UnvalidatedTinyAsciiStr<N> { |
41 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
42 | where |
43 | S: serde::Serializer, |
44 | { |
45 | use serde::ser::Error; |
46 | self.try_into_tinystr() |
47 | .map_err(|_| S::Error::custom("invalid ascii in UnvalidatedTinyAsciiStr" ))? |
48 | .serialize(serializer) |
49 | } |
50 | } |
51 | |
52 | macro_rules! deserialize { |
53 | ($size:literal) => { |
54 | #[cfg(feature = "serde" )] |
55 | impl<'de, 'a> serde::Deserialize<'de> for UnvalidatedTinyAsciiStr<$size> |
56 | where |
57 | 'de: 'a, |
58 | { |
59 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
60 | where |
61 | D: serde::Deserializer<'de>, |
62 | { |
63 | if deserializer.is_human_readable() { |
64 | Ok(TinyAsciiStr::deserialize(deserializer)?.to_unvalidated()) |
65 | } else { |
66 | Ok(Self(<[u8; $size]>::deserialize(deserializer)?)) |
67 | } |
68 | } |
69 | } |
70 | }; |
71 | } |
72 | |
73 | deserialize!(1); |
74 | deserialize!(2); |
75 | deserialize!(3); |
76 | deserialize!(4); |
77 | deserialize!(5); |
78 | deserialize!(6); |
79 | deserialize!(7); |
80 | deserialize!(8); |
81 | deserialize!(9); |
82 | deserialize!(10); |
83 | deserialize!(11); |
84 | deserialize!(12); |
85 | deserialize!(13); |
86 | deserialize!(14); |
87 | deserialize!(15); |
88 | deserialize!(16); |
89 | deserialize!(17); |
90 | deserialize!(18); |
91 | deserialize!(19); |
92 | deserialize!(20); |
93 | deserialize!(21); |
94 | deserialize!(22); |
95 | deserialize!(23); |
96 | deserialize!(24); |
97 | deserialize!(25); |
98 | deserialize!(26); |
99 | deserialize!(27); |
100 | deserialize!(28); |
101 | deserialize!(29); |
102 | deserialize!(30); |
103 | deserialize!(31); |
104 | deserialize!(32); |
105 | |