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