1use crate::primitive::private::Sealed;
34use std::error::Error;
35use std::fmt;
36use std::str::FromStr;
37
38#[non_exhaustive]
40#[derive(Debug)]
41pub struct PrimitiveParseError(&'static str);
42
43impl fmt::Display for PrimitiveParseError {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(f, "failed to parse input as {}", self.0)
46    }
47}
48impl Error for PrimitiveParseError {}
49
50pub trait Parse: Sealed {
52    fn parse_smithy_primitive(input: &str) -> Result<Self, PrimitiveParseError>
54    where
55        Self: Sized;
56}
57
58mod private {
59    pub trait Sealed {}
60    impl Sealed for i8 {}
61    impl Sealed for i16 {}
62    impl Sealed for i32 {}
63    impl Sealed for i64 {}
64    impl Sealed for f32 {}
65    impl Sealed for f64 {}
66    impl Sealed for u64 {}
67    impl Sealed for bool {}
68}
69
70macro_rules! parse_from_str {
71    ($t: ty) => {
72        impl Parse for $t {
73            fn parse_smithy_primitive(input: &str) -> Result<Self, PrimitiveParseError> {
74                FromStr::from_str(input).map_err(|_| PrimitiveParseError(stringify!($t)))
75            }
76        }
77    };
78}
79
80parse_from_str!(bool);
81parse_from_str!(i8);
82parse_from_str!(i16);
83parse_from_str!(i32);
84parse_from_str!(i64);
85
86impl Parse for f32 {
87    fn parse_smithy_primitive(input: &str) -> Result<Self, PrimitiveParseError> {
88        float::parse_f32(input).map_err(|_| PrimitiveParseError("f32"))
89    }
90}
91
92impl Parse for f64 {
93    fn parse_smithy_primitive(input: &str) -> Result<Self, PrimitiveParseError> {
94        float::parse_f64(input).map_err(|_| PrimitiveParseError("f64"))
95    }
96}
97
98enum Inner {
99    Bool(bool),
101    I8(i8, itoa::Buffer),
103    I16(i16, itoa::Buffer),
105    I32(i32, itoa::Buffer),
107    I64(i64, itoa::Buffer),
109    U64(u64, itoa::Buffer),
111    F32(f32, ryu::Buffer),
113    F64(f64, ryu::Buffer),
115}
116
117impl fmt::Debug for Inner {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        match self {
120            Self::Bool(v) => write!(f, "Bool({})", v),
121            Self::I8(v, _) => write!(f, "I8({})", v),
122            Self::I16(v, _) => write!(f, "I16({})", v),
123            Self::I32(v, _) => write!(f, "I32({})", v),
124            Self::I64(v, _) => write!(f, "I64({})", v),
125            Self::U64(v, _) => write!(f, "U64({})", v),
126            Self::F32(v, _) => write!(f, "F32({})", v),
127            Self::F64(v, _) => write!(f, "F64({})", v),
128        }
129    }
130}
131
132#[non_exhaustive]
139#[derive(Debug)]
140pub struct Encoder(Inner);
141
142impl Encoder {
143    pub fn encode(&mut self) -> &str {
145        match &mut self.0 {
146            Inner::Bool(true) => "true",
147            Inner::Bool(false) => "false",
148            Inner::I8(v, buf) => buf.format(*v),
149            Inner::I16(v, buf) => buf.format(*v),
150            Inner::I32(v, buf) => buf.format(*v),
151            Inner::I64(v, buf) => buf.format(*v),
152            Inner::U64(v, buf) => buf.format(*v),
153            Inner::F32(v, buf) => {
154                if v.is_nan() {
155                    float::NAN
156                } else if *v == f32::INFINITY {
157                    float::INFINITY
158                } else if *v == f32::NEG_INFINITY {
159                    float::NEG_INFINITY
160                } else {
161                    buf.format_finite(*v)
162                }
163            }
164            Inner::F64(v, buf) => {
165                if v.is_nan() {
166                    float::NAN
167                } else if *v == f64::INFINITY {
168                    float::INFINITY
169                } else if *v == f64::NEG_INFINITY {
170                    float::NEG_INFINITY
171                } else {
172                    buf.format_finite(*v)
173                }
174            }
175        }
176    }
177}
178
179impl From<bool> for Encoder {
180    fn from(input: bool) -> Self {
181        Self(Inner::Bool(input))
182    }
183}
184
185impl From<i8> for Encoder {
186    fn from(input: i8) -> Self {
187        Self(Inner::I8(input, itoa::Buffer::new()))
188    }
189}
190
191impl From<i16> for Encoder {
192    fn from(input: i16) -> Self {
193        Self(Inner::I16(input, itoa::Buffer::new()))
194    }
195}
196
197impl From<i32> for Encoder {
198    fn from(input: i32) -> Self {
199        Self(Inner::I32(input, itoa::Buffer::new()))
200    }
201}
202
203impl From<i64> for Encoder {
204    fn from(input: i64) -> Self {
205        Self(Inner::I64(input, itoa::Buffer::new()))
206    }
207}
208
209impl From<u64> for Encoder {
210    fn from(input: u64) -> Self {
211        Self(Inner::U64(input, itoa::Buffer::new()))
212    }
213}
214
215impl From<f32> for Encoder {
216    fn from(input: f32) -> Self {
217        Self(Inner::F32(input, ryu::Buffer::new()))
218    }
219}
220
221impl From<f64> for Encoder {
222    fn from(input: f64) -> Self {
223        Self(Inner::F64(input, ryu::Buffer::new()))
224    }
225}
226
227mod float {
228    use std::num::ParseFloatError;
229
230    pub(crate) const INFINITY: &str = "Infinity";
232
233    pub(crate) const NEG_INFINITY: &str = "-Infinity";
235
236    pub(crate) const NAN: &str = "NaN";
238
239    pub(crate) fn parse_f32(data: &str) -> Result<f32, ParseFloatError> {
241        match data {
242            INFINITY => Ok(f32::INFINITY),
243            NEG_INFINITY => Ok(f32::NEG_INFINITY),
244            NAN => Ok(f32::NAN),
245            other => other.parse::<f32>(),
246        }
247    }
248
249    pub(crate) fn parse_f64(data: &str) -> Result<f64, ParseFloatError> {
251        match data {
252            INFINITY => Ok(f64::INFINITY),
253            NEG_INFINITY => Ok(f64::NEG_INFINITY),
254            NAN => Ok(f64::NAN),
255            other => other.parse::<f64>(),
256        }
257    }
258}
259
260#[cfg(test)]
261mod test {
262    use crate::primitive::{Encoder, Parse};
263
264    #[test]
265    fn bool_format() {
266        assert_eq!(Encoder::from(true).encode(), "true");
267        assert_eq!(Encoder::from(false).encode(), "false");
268        let err = bool::parse_smithy_primitive("not a boolean").expect_err("should fail");
269        assert_eq!(err.0, "bool");
270        assert!(bool::parse_smithy_primitive("true").unwrap());
271        assert!(!bool::parse_smithy_primitive("false").unwrap());
272    }
273
274    #[test]
275    fn float_format() {
276        assert_eq!(Encoder::from(55_f64).encode(), "55.0");
277        assert_eq!(Encoder::from(f64::INFINITY).encode(), "Infinity");
278        assert_eq!(Encoder::from(f32::INFINITY).encode(), "Infinity");
279        assert_eq!(Encoder::from(f32::NEG_INFINITY).encode(), "-Infinity");
280        assert_eq!(Encoder::from(f64::NEG_INFINITY).encode(), "-Infinity");
281        assert_eq!(Encoder::from(f32::NAN).encode(), "NaN");
282        assert_eq!(Encoder::from(f64::NAN).encode(), "NaN");
283    }
284
285    #[test]
286    fn float_parse() {
287        assert_eq!(f64::parse_smithy_primitive("1234.5").unwrap(), 1234.5);
288        assert!(f64::parse_smithy_primitive("NaN").unwrap().is_nan());
289        assert_eq!(
290            f64::parse_smithy_primitive("Infinity").unwrap(),
291            f64::INFINITY
292        );
293        assert_eq!(
294            f64::parse_smithy_primitive("-Infinity").unwrap(),
295            f64::NEG_INFINITY
296        );
297        assert_eq!(f32::parse_smithy_primitive("1234.5").unwrap(), 1234.5);
298        assert!(f32::parse_smithy_primitive("NaN").unwrap().is_nan());
299        assert_eq!(
300            f32::parse_smithy_primitive("Infinity").unwrap(),
301            f32::INFINITY
302        );
303        assert_eq!(
304            f32::parse_smithy_primitive("-Infinity").unwrap(),
305            f32::NEG_INFINITY
306        );
307    }
308}