1 use core::fmt;
2 use core::ops::Deref;
3 
4 use arrayvec::ArrayString;
5 
6 const MAX_DEC_LEN: usize = 8;
7 pub(crate) const MAX_ERR_LEN: usize = 256;
8 const MAX_INF_LEN: usize = 128;
9 pub(crate) const MAX_MIN_LEN: usize = 8;
10 const MAX_NAN_LEN: usize = 64;
11 const MAX_PLUS_LEN: usize = 8;
12 pub(crate) const MAX_SEP_LEN: usize = 8;
13 
14 #[cfg(feature = "with-serde")]
15 use serde::{de, ser};
16 
17 use crate::error::Error;
18 
19 /// Simple wrapper type for a `&str` to make sure its length is less than the maximum for
20 /// a decimal (8 bytes).
21 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
22 pub struct DecimalStr<'a>(&'a str);
23 
24 impl<'a> DecimalStr<'a> {
25     /// Constructs an [`DecimalStr`], ensuring that the length is less than the maximum for
26     /// a decimal (8 bytes).
27     ///
28     /// # Errors
29     ///
30     /// Returns an error if the provided `&str`'s length is more than 8 bytes.
31     ///
32     /// [`DecimalStr`]: struct.DecimalStr.html
new(s: &'a str) -> Result<DecimalStr<'a>, Error>33     pub fn new(s: &'a str) -> Result<DecimalStr<'a>, Error> {
34         Self::_new(s)
35     }
36 }
37 
38 /// Simple wrapper type for a `&str` to make sure its length is less than the maximum for
39 /// an infinity symbol (128 bytes).
40 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
41 pub struct InfinityStr<'a>(&'a str);
42 
43 impl<'a> InfinityStr<'a> {
44     /// Constructs an [`InfinityStr`], ensuring that the length is less than the maximum for
45     /// an infinity symbol (128 bytes).
46     ///
47     /// # Errors
48     ///
49     /// Returns an error if the provided `&str`'s length is more than 128 bytes.
50     ///
51     /// [`InfinityStr`]: struct.InfinityStr.html
new(s: &'a str) -> Result<InfinityStr<'a>, Error>52     pub fn new(s: &'a str) -> Result<InfinityStr<'a>, Error> {
53         Self::_new(s)
54     }
55 }
56 
57 /// Simple wrapper type for a `&str` to make sure its length is less than the maximum for
58 /// a minus sign (8 bytes).
59 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
60 pub struct MinusSignStr<'a>(&'a str);
61 
62 impl<'a> MinusSignStr<'a> {
63     /// Constructs a [`MinusSignStr`], ensuring that the length is less than the maximum for
64     /// a minus sign (8 bytes).
65     ///
66     /// # Errors
67     ///
68     /// Returns an error if the provided `&str`'s length is more than 7 bytes.
69     ///
70     /// [`MinusSignStr`]: struct.MinusSignStr.html
new(s: &'a str) -> Result<MinusSignStr<'a>, Error>71     pub fn new(s: &'a str) -> Result<MinusSignStr<'a>, Error> {
72         Self::_new(s)
73     }
74 }
75 
76 /// Simple wrapper type for a `&str` to make sure its length is less than the maximum for
77 /// a nan symbol (64 bytes).
78 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
79 pub struct NanStr<'a>(&'a str);
80 
81 impl<'a> NanStr<'a> {
82     /// Constructs an [`NanStr`], ensuring that the length is less than the maximum for
83     /// a nan symbol (64 bytes).
84     ///
85     /// # Errors
86     ///
87     /// Returns an error if the provided `&str`'s length is more than 64 bytes.
88     ///
89     /// [`NanStr`]: struct.NanStr.html
new(s: &'a str) -> Result<NanStr<'a>, Error>90     pub fn new(s: &'a str) -> Result<NanStr<'a>, Error> {
91         Self::_new(s)
92     }
93 }
94 
95 /// Simple wrapper type for a `&str` to make sure its length is less than the maximum for
96 /// a plus sign (8 bytes).
97 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
98 pub struct PlusSignStr<'a>(&'a str);
99 
100 impl<'a> PlusSignStr<'a> {
101     /// Constructs an [`PlusSignStr`], ensuring that the length is less than the maximum for
102     /// a plus sign (8 bytes).
103     ///
104     /// # Errors
105     ///
106     /// Returns an error if the provided `&str`'s length is more than 8 bytes.
107     ///
108     /// [`PlusSignStr`]: struct.PlusSignStr.html
new(s: &'a str) -> Result<PlusSignStr<'a>, Error>109     pub fn new(s: &'a str) -> Result<PlusSignStr<'a>, Error> {
110         Self::_new(s)
111     }
112 }
113 
114 /// Simple wrapper type for a `&str` to make sure its length is less than the maximum for
115 /// a separator (8 bytes).
116 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
117 pub struct SeparatorStr<'a>(&'a str);
118 
119 impl<'a> SeparatorStr<'a> {
120     /// Constructs an [`SeparatorStr`], ensuring that the length is less than the maximum for
121     /// a separator (8 bytes).
122     ///
123     /// # Errors
124     ///
125     /// Returns an error if the provided `&str`'s length is more than 8 bytes.
126     ///
127     /// [`SeparatorStr`]: struct.SeparatorStr.html
new(s: &'a str) -> Result<SeparatorStr<'a>, Error>128     pub fn new(s: &'a str) -> Result<SeparatorStr<'a>, Error> {
129         Self::_new(s)
130     }
131 }
132 
133 macro_rules! create_impls {
134     ( $name:ident, $max_len:expr ) => {
135         impl<'a> $name<'a> {
136             #[inline(always)]
137             /// Allows recovery of the initial / wrapped `&str`.
138             pub fn into_str(self) -> &'a str {
139                 self.0
140             }
141 
142             #[inline(always)]
143             fn _new(s: &'a str) -> Result<$name<'a>, Error> {
144                 let len = s.len();
145                 if len > $max_len {
146                     return Err(Error::capacity(len, $max_len));
147                 }
148                 Ok($name(s))
149             }
150         }
151 
152         impl<'a> AsRef<str> for $name<'a> {
153             #[inline(always)]
154             fn as_ref(&self) -> &str {
155                 self.0
156             }
157         }
158 
159         impl<'a> fmt::Debug for $name<'a> {
160             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161                 write!(f, "{:?}", self.0)
162             }
163         }
164 
165         impl<'a> fmt::Display for $name<'a> {
166             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167                 write!(f, "{}", self.0)
168             }
169         }
170     };
171 }
172 
173 create_impls!(DecimalStr, MAX_DEC_LEN);
174 create_impls!(InfinityStr, MAX_INF_LEN);
175 create_impls!(MinusSignStr, MAX_MIN_LEN);
176 create_impls!(NanStr, MAX_NAN_LEN);
177 create_impls!(PlusSignStr, MAX_PLUS_LEN);
178 create_impls!(SeparatorStr, MAX_SEP_LEN);
179 
180 macro_rules! create_string {
181     ( $name:ident, $visitor:ident, $max_len:expr ) => {
182         #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
183         pub(crate) struct $name(ArrayString<[u8; $max_len]>);
184 
185         impl $name {
186             #[allow(dead_code)]
187             pub(crate) fn new<S>(s: S) -> Result<Self, Error>
188             where
189                 S: AsRef<str>,
190             {
191                 let s = s.as_ref();
192                 let a = ArrayString::from(s).map_err(|_| Error::capacity(s.len(), $max_len))?;
193                 Ok($name(a))
194             }
195 
196             #[allow(dead_code)]
197             pub(crate) fn truncated<S>(s: S) -> Self
198             where
199                 S: AsRef<str>,
200             {
201                 let s = s.as_ref();
202                 let s = if s.len() > $max_len {
203                     &s[0..$max_len]
204                 } else {
205                     s
206                 };
207                 $name(ArrayString::from(s).unwrap())
208             }
209 
210             #[allow(dead_code)]
211             #[inline(always)]
212             pub(crate) fn capacity() -> usize {
213                 $max_len
214             }
215         }
216 
217         impl Deref for $name {
218             type Target = str;
219 
220             #[inline(always)]
221             fn deref(&self) -> &str {
222                 self.0.deref()
223             }
224         }
225 
226         impl fmt::Display for $name {
227             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228                 write!(f, "{}", self.0)
229             }
230         }
231 
232         impl From<$name> for ArrayString<[u8; $max_len]> {
233             fn from(s: $name) -> Self {
234                 s.0
235             }
236         }
237 
238         #[cfg(feature = "with-serde")]
239         impl ser::Serialize for $name {
240             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
241             where
242                 S: ser::Serializer,
243             {
244                 serializer.serialize_str(self.0.as_str())
245             }
246         }
247 
248         #[cfg(feature = "with-serde")]
249         struct $visitor;
250 
251         #[cfg(feature = "with-serde")]
252         impl<'de> de::Visitor<'de> for $visitor {
253             type Value = $name;
254 
255             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
256                 write!(formatter, "a string containing at most {} bytes", $max_len)
257             }
258 
259             fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
260             where
261                 E: de::Error,
262             {
263                 $name::new(s).map_err(|_| de::Error::invalid_value(de::Unexpected::Str(s), &self))
264             }
265         }
266 
267         #[cfg(feature = "with-serde")]
268         impl<'de> de::Deserialize<'de> for $name {
269             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
270             where
271                 D: de::Deserializer<'de>,
272             {
273                 deserializer.deserialize_str($visitor)
274             }
275         }
276     };
277 }
278 
279 create_string!(DecString, DecVisitor, MAX_DEC_LEN);
280 create_string!(ErrString, ErrVisitor, MAX_ERR_LEN);
281 create_string!(InfString, InfVisitor, MAX_INF_LEN);
282 create_string!(MinString, MinVisitor, MAX_MIN_LEN);
283 create_string!(NanString, NanVisitor, MAX_NAN_LEN);
284 create_string!(PlusString, PlusVisitor, MAX_PLUS_LEN);
285 create_string!(SepString, SepVisitor, MAX_SEP_LEN);
286