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}