|
1 | 1 | //! Deserialize JSON data to a Rust data structure |
2 | 2 |
|
| 3 | +use core::str::FromStr; |
3 | 4 | use core::{fmt, str}; |
4 | 5 |
|
5 | 6 | use serde::de::{self, Visitor}; |
@@ -27,6 +28,9 @@ pub enum Error { |
27 | 28 | /// EOF while parsing a string. |
28 | 29 | EofWhileParsingString, |
29 | 30 |
|
| 31 | + /// EOF while parsing a JSON number. |
| 32 | + EofWhileParsingNumber, |
| 33 | + |
30 | 34 | /// EOF while parsing a JSON value. |
31 | 35 | EofWhileParsingValue, |
32 | 36 |
|
@@ -273,6 +277,29 @@ macro_rules! deserialize_signed { |
273 | 277 | }}; |
274 | 278 | } |
275 | 279 |
|
| 280 | +macro_rules! deserialize_fromstr { |
| 281 | + ($self:ident, $visitor:ident, $typ:ident, $visit_fn:ident, $pattern:expr) => {{ |
| 282 | + let start = $self.index; |
| 283 | + loop { |
| 284 | + match $self.peek() { |
| 285 | + Some(c) => { |
| 286 | + if $pattern.iter().find(|&&d| d == c).is_some() { |
| 287 | + $self.eat_char(); |
| 288 | + } else { |
| 289 | + let s = unsafe { |
| 290 | + // already checked that it contains only ascii |
| 291 | + str::from_utf8_unchecked(&$self.slice[start..$self.index]) |
| 292 | + }; |
| 293 | + let v = $typ::from_str(s).or(Err(Error::InvalidNumber))?; |
| 294 | + return $visitor.$visit_fn(v); |
| 295 | + } |
| 296 | + } |
| 297 | + None => return Err(Error::EofWhileParsingNumber), |
| 298 | + } |
| 299 | + } |
| 300 | + }}; |
| 301 | +} |
| 302 | + |
276 | 303 | impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { |
277 | 304 | type Error = Error; |
278 | 305 |
|
@@ -360,18 +387,20 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { |
360 | 387 | deserialize_unsigned!(self, visitor, u64, visit_u64) |
361 | 388 | } |
362 | 389 |
|
363 | | - fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value> |
| 390 | + fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value> |
364 | 391 | where |
365 | 392 | V: Visitor<'de>, |
366 | 393 | { |
367 | | - unreachable!() |
| 394 | + self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?; |
| 395 | + deserialize_fromstr!(self, visitor, f32, visit_f32, b"0123456789+-.eE") |
368 | 396 | } |
369 | 397 |
|
370 | | - fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value> |
| 398 | + fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value> |
371 | 399 | where |
372 | 400 | V: Visitor<'de>, |
373 | 401 | { |
374 | | - unreachable!() |
| 402 | + self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?; |
| 403 | + deserialize_fromstr!(self, visitor, f64, visit_f64, b"0123456789+-.eE") |
375 | 404 | } |
376 | 405 |
|
377 | 406 | fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value> |
@@ -711,6 +740,51 @@ mod tests { |
711 | 740 | assert!(crate::from_str::<Temperature>(r#"{ "temperature": -129 }"#).is_err()); |
712 | 741 | } |
713 | 742 |
|
| 743 | + #[test] |
| 744 | + fn struct_f32() { |
| 745 | + #[derive(Debug, Deserialize, PartialEq)] |
| 746 | + struct Temperature { |
| 747 | + temperature: f32, |
| 748 | + } |
| 749 | + |
| 750 | + assert_eq!( |
| 751 | + crate::from_str(r#"{ "temperature": -17.2 }"#), |
| 752 | + Ok(Temperature { temperature: -17.2 }) |
| 753 | + ); |
| 754 | + |
| 755 | + assert_eq!( |
| 756 | + crate::from_str(r#"{ "temperature": -0.0 }"#), |
| 757 | + Ok(Temperature { temperature: -0. }) |
| 758 | + ); |
| 759 | + |
| 760 | + assert_eq!( |
| 761 | + crate::from_str(r#"{ "temperature": -2.1e-3 }"#), |
| 762 | + Ok(Temperature { |
| 763 | + temperature: -2.1e-3 |
| 764 | + }) |
| 765 | + ); |
| 766 | + |
| 767 | + assert_eq!( |
| 768 | + crate::from_str(r#"{ "temperature": -3 }"#), |
| 769 | + Ok(Temperature { temperature: -3. }) |
| 770 | + ); |
| 771 | + |
| 772 | + use core::f32; |
| 773 | + |
| 774 | + assert_eq!( |
| 775 | + crate::from_str(r#"{ "temperature": -1e500 }"#), |
| 776 | + Ok(Temperature { |
| 777 | + temperature: f32::NEG_INFINITY |
| 778 | + }) |
| 779 | + ); |
| 780 | + |
| 781 | + assert!(crate::from_str::<Temperature>(r#"{ "temperature": 1e1e1 }"#).is_err()); |
| 782 | + assert!(crate::from_str::<Temperature>(r#"{ "temperature": -2-2 }"#).is_err()); |
| 783 | + assert!(crate::from_str::<Temperature>(r#"{ "temperature": 1 1 }"#).is_err()); |
| 784 | + assert!(crate::from_str::<Temperature>(r#"{ "temperature": 0.0. }"#).is_err()); |
| 785 | + assert!(crate::from_str::<Temperature>(r#"{ "temperature": ä }"#).is_err()); |
| 786 | + } |
| 787 | + |
714 | 788 | #[test] |
715 | 789 | fn struct_option() { |
716 | 790 | #[derive(Debug, Deserialize, PartialEq)] |
|
0 commit comments