num_format/
strings.rs

1use core::fmt;
2use core::ops::Deref;
3
4use arrayvec::ArrayString;
5
6const MAX_DEC_LEN: usize = 8;
7pub(crate) const MAX_ERR_LEN: usize = 256;
8const MAX_INF_LEN: usize = 128;
9pub(crate) const MAX_MIN_LEN: usize = 8;
10const MAX_NAN_LEN: usize = 64;
11const MAX_PLUS_LEN: usize = 8;
12pub(crate) const MAX_SEP_LEN: usize = 8;
13
14#[cfg(feature = "with-serde")]
15use serde::{de, ser};
16
17use 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)]
22pub struct DecimalStr<'a>(&'a str);
23
24impl<'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
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)]
41pub struct InfinityStr<'a>(&'a str);
42
43impl<'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
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)]
60pub struct MinusSignStr<'a>(&'a str);
61
62impl<'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
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)]
79pub struct NanStr<'a>(&'a str);
80
81impl<'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
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)]
98pub struct PlusSignStr<'a>(&'a str);
99
100impl<'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
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)]
117pub struct SeparatorStr<'a>(&'a str);
118
119impl<'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
128    pub fn new(s: &'a str) -> Result<SeparatorStr<'a>, Error> {
129        Self::_new(s)
130    }
131}
132
133macro_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
173create_impls!(DecimalStr, MAX_DEC_LEN);
174create_impls!(InfinityStr, MAX_INF_LEN);
175create_impls!(MinusSignStr, MAX_MIN_LEN);
176create_impls!(NanStr, MAX_NAN_LEN);
177create_impls!(PlusSignStr, MAX_PLUS_LEN);
178create_impls!(SeparatorStr, MAX_SEP_LEN);
179
180macro_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<$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<$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
279create_string!(DecString, DecVisitor, MAX_DEC_LEN);
280create_string!(ErrString, ErrVisitor, MAX_ERR_LEN);
281create_string!(InfString, InfVisitor, MAX_INF_LEN);
282create_string!(MinString, MinVisitor, MAX_MIN_LEN);
283create_string!(NanString, NanVisitor, MAX_NAN_LEN);
284create_string!(PlusString, PlusVisitor, MAX_PLUS_LEN);
285create_string!(SepString, SepVisitor, MAX_SEP_LEN);