Skip to content

Commit 36c43bf

Browse files
authored
Merge pull request #848 from serde-rs/num
Deserialize small numbers as integers in arbitrary_precision
2 parents 6691977 + d541381 commit 36c43bf

File tree

4 files changed

+84
-10
lines changed

4 files changed

+84
-10
lines changed

src/de.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,15 @@ impl<'de, R: Read<'de>> Deserializer<R> {
864864
buf.push('-');
865865
}
866866
self.scan_integer(&mut buf)?;
867+
if positive {
868+
if let Ok(unsigned) = buf.parse() {
869+
return Ok(ParserNumber::U64(unsigned));
870+
}
871+
} else {
872+
if let Ok(signed) = buf.parse() {
873+
return Ok(ParserNumber::I64(signed));
874+
}
875+
}
867876
Ok(ParserNumber::String(buf))
868877
}
869878

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@
303303
#![doc(html_root_url = "https://docs.rs/serde_json/1.0.74")]
304304
// Ignored clippy lints
305305
#![allow(
306+
clippy::collapsible_else_if,
306307
clippy::comparison_chain,
307308
clippy::deprecated_cfg_attr,
308309
clippy::doc_markdown,

tests/regression/issue845.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use serde::{Deserialize, Deserializer};
2+
use std::convert::TryFrom;
3+
use std::fmt::{self, Display};
4+
use std::marker::PhantomData;
5+
use std::str::FromStr;
6+
7+
pub struct NumberVisitor<T> {
8+
marker: PhantomData<T>,
9+
}
10+
11+
impl<'de, T> serde::de::Visitor<'de> for NumberVisitor<T>
12+
where
13+
T: TryFrom<u64> + TryFrom<i64> + FromStr,
14+
<T as TryFrom<u64>>::Error: Display,
15+
<T as TryFrom<i64>>::Error: Display,
16+
<T as FromStr>::Err: Display,
17+
{
18+
type Value = T;
19+
20+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
21+
formatter.write_str("an integer or string")
22+
}
23+
24+
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
25+
where
26+
E: serde::de::Error,
27+
{
28+
T::try_from(v).map_err(serde::de::Error::custom)
29+
}
30+
31+
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
32+
where
33+
E: serde::de::Error,
34+
{
35+
T::try_from(v).map_err(serde::de::Error::custom)
36+
}
37+
38+
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
39+
where
40+
E: serde::de::Error,
41+
{
42+
v.parse().map_err(serde::de::Error::custom)
43+
}
44+
}
45+
46+
fn deserialize_integer_or_string<'de, D, T>(deserializer: D) -> Result<T, D::Error>
47+
where
48+
D: Deserializer<'de>,
49+
T: TryFrom<u64> + TryFrom<i64> + FromStr,
50+
<T as TryFrom<u64>>::Error: Display,
51+
<T as TryFrom<i64>>::Error: Display,
52+
<T as FromStr>::Err: Display,
53+
{
54+
deserializer.deserialize_any(NumberVisitor {
55+
marker: PhantomData,
56+
})
57+
}
58+
59+
#[derive(Deserialize, Debug)]
60+
pub struct Struct {
61+
#[serde(deserialize_with = "deserialize_integer_or_string")]
62+
pub i: i64,
63+
}
64+
65+
#[test]
66+
fn test() {
67+
let j = r#" {"i":100} "#;
68+
println!("{:?}", serde_json::from_str::<Struct>(j).unwrap());
69+
70+
let j = r#" {"i":"100"} "#;
71+
println!("{:?}", serde_json::from_str::<Struct>(j).unwrap());
72+
}

tests/test.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -715,11 +715,7 @@ fn test_parse_char() {
715715
),
716716
(
717717
"10",
718-
if cfg!(feature = "arbitrary_precision") {
719-
"invalid type: number, expected a character at line 1 column 2"
720-
} else {
721-
"invalid type: integer `10`, expected a character at line 1 column 2"
722-
},
718+
"invalid type: integer `10`, expected a character at line 1 column 2",
723719
),
724720
]);
725721

@@ -1203,11 +1199,7 @@ fn test_parse_struct() {
12031199
test_parse_err::<Outer>(&[
12041200
(
12051201
"5",
1206-
if cfg!(feature = "arbitrary_precision") {
1207-
"invalid type: number, expected struct Outer at line 1 column 1"
1208-
} else {
1209-
"invalid type: integer `5`, expected struct Outer at line 1 column 1"
1210-
},
1202+
"invalid type: integer `5`, expected struct Outer at line 1 column 1",
12111203
),
12121204
(
12131205
"\"hello\"",

0 commit comments

Comments
 (0)