From 0ca5a69d734c4f5a0185e93de491b45e25ca39b6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 15 Jan 2022 16:39:19 -0800 Subject: [PATCH 1/2] Add regression test for issue 845 --- tests/regression/issue845.rs | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/regression/issue845.rs diff --git a/tests/regression/issue845.rs b/tests/regression/issue845.rs new file mode 100644 index 000000000..dcca55694 --- /dev/null +++ b/tests/regression/issue845.rs @@ -0,0 +1,72 @@ +use serde::{Deserialize, Deserializer}; +use std::convert::TryFrom; +use std::fmt::{self, Display}; +use std::marker::PhantomData; +use std::str::FromStr; + +pub struct NumberVisitor { + marker: PhantomData, +} + +impl<'de, T> serde::de::Visitor<'de> for NumberVisitor +where + T: TryFrom + TryFrom + FromStr, + >::Error: Display, + >::Error: Display, + ::Err: Display, +{ + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an integer or string") + } + + fn visit_u64(self, v: u64) -> Result + where + E: serde::de::Error, + { + T::try_from(v).map_err(serde::de::Error::custom) + } + + fn visit_i64(self, v: i64) -> Result + where + E: serde::de::Error, + { + T::try_from(v).map_err(serde::de::Error::custom) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + v.parse().map_err(serde::de::Error::custom) + } +} + +fn deserialize_integer_or_string<'de, D, T>(deserializer: D) -> Result +where + D: Deserializer<'de>, + T: TryFrom + TryFrom + FromStr, + >::Error: Display, + >::Error: Display, + ::Err: Display, +{ + deserializer.deserialize_any(NumberVisitor { + marker: PhantomData, + }) +} + +#[derive(Deserialize, Debug)] +pub struct Struct { + #[serde(deserialize_with = "deserialize_integer_or_string")] + pub i: i64, +} + +#[test] +fn test() { + let j = r#" {"i":100} "#; + println!("{:?}", serde_json::from_str::(j).unwrap()); + + let j = r#" {"i":"100"} "#; + println!("{:?}", serde_json::from_str::(j).unwrap()); +} From d54138145514758ea9475baf77cd5bf4788e9eaf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 15 Jan 2022 16:27:44 -0800 Subject: [PATCH 2/2] Deserialize small numbers as integers in arbitrary_precision --- src/de.rs | 9 +++++++++ src/lib.rs | 1 + tests/test.rs | 12 ++---------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/de.rs b/src/de.rs index b4c5ef7dc..bf103f04b 100644 --- a/src/de.rs +++ b/src/de.rs @@ -864,6 +864,15 @@ impl<'de, R: Read<'de>> Deserializer { buf.push('-'); } self.scan_integer(&mut buf)?; + if positive { + if let Ok(unsigned) = buf.parse() { + return Ok(ParserNumber::U64(unsigned)); + } + } else { + if let Ok(signed) = buf.parse() { + return Ok(ParserNumber::I64(signed)); + } + } Ok(ParserNumber::String(buf)) } diff --git a/src/lib.rs b/src/lib.rs index c36876da3..0a815747c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -303,6 +303,7 @@ #![doc(html_root_url = "https://docs.rs/serde_json/1.0.74")] // Ignored clippy lints #![allow( + clippy::collapsible_else_if, clippy::comparison_chain, clippy::deprecated_cfg_attr, clippy::doc_markdown, diff --git a/tests/test.rs b/tests/test.rs index 054e96088..bfcb5290f 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -715,11 +715,7 @@ fn test_parse_char() { ), ( "10", - if cfg!(feature = "arbitrary_precision") { - "invalid type: number, expected a character at line 1 column 2" - } else { - "invalid type: integer `10`, expected a character at line 1 column 2" - }, + "invalid type: integer `10`, expected a character at line 1 column 2", ), ]); @@ -1203,11 +1199,7 @@ fn test_parse_struct() { test_parse_err::(&[ ( "5", - if cfg!(feature = "arbitrary_precision") { - "invalid type: number, expected struct Outer at line 1 column 1" - } else { - "invalid type: integer `5`, expected struct Outer at line 1 column 1" - }, + "invalid type: integer `5`, expected struct Outer at line 1 column 1", ), ( "\"hello\"",