Skip to content

Commit 88cbab8

Browse files
committed
Use serde_test to test serde
2 parents 3ff2b06 + 8355022 commit 88cbab8

File tree

3 files changed

+202
-166
lines changed

3 files changed

+202
-166
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ serde = { version = "1.0", optional = true, default-features = false }
2828

2929
[dev-dependencies]
3030
paste = "1"
31-
serde_json = "<1.0.101"
31+
serde_test = "<1.0.176"
3232
siphasher = { version = "0.3.10", default-features = false }
3333
# The following dev-dependencies are only required for benchmarking
3434
# (use the `benchmark-bigdecimal` script to uncomment these and run benchmarks)

src/impl_serde.rs

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
//!
2+
//! Support for serde implementations
3+
//!
4+
use crate::*;
5+
use serde::{de, ser};
6+
7+
8+
impl ser::Serialize for BigDecimal {
9+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
10+
where
11+
S: ser::Serializer,
12+
{
13+
serializer.collect_str(&self)
14+
}
15+
}
16+
17+
/// Used by SerDe to construct a BigDecimal
18+
struct BigDecimalVisitor;
19+
20+
impl<'de> de::Visitor<'de> for BigDecimalVisitor {
21+
type Value = BigDecimal;
22+
23+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
24+
write!(formatter, "a number or formatted decimal string")
25+
}
26+
27+
fn visit_str<E>(self, value: &str) -> Result<BigDecimal, E>
28+
where
29+
E: de::Error,
30+
{
31+
BigDecimal::from_str(value).map_err(|err| E::custom(format!("{}", err)))
32+
}
33+
34+
fn visit_u64<E>(self, value: u64) -> Result<BigDecimal, E>
35+
where
36+
E: de::Error,
37+
{
38+
Ok(BigDecimal::from(value))
39+
}
40+
41+
fn visit_i64<E>(self, value: i64) -> Result<BigDecimal, E>
42+
where
43+
E: de::Error,
44+
{
45+
Ok(BigDecimal::from(value))
46+
}
47+
48+
fn visit_f64<E>(self, value: f64) -> Result<BigDecimal, E>
49+
where
50+
E: de::Error,
51+
{
52+
BigDecimal::try_from(value).map_err(|err| E::custom(format!("{}", err)))
53+
}
54+
}
55+
56+
#[cfg(not(feature = "string-only"))]
57+
impl<'de> de::Deserialize<'de> for BigDecimal {
58+
fn deserialize<D>(d: D) -> Result<Self, D::Error>
59+
where
60+
D: de::Deserializer<'de>,
61+
{
62+
d.deserialize_any(BigDecimalVisitor)
63+
}
64+
}
65+
66+
#[cfg(feature = "string-only")]
67+
impl<'de> de::Deserialize<'de> for BigDecimal {
68+
fn deserialize<D>(d: D) -> Result<Self, D::Error>
69+
where
70+
D: de::Deserializer<'de>,
71+
{
72+
d.deserialize_str(BigDecimalVisitor)
73+
}
74+
}
75+
76+
#[cfg(test)]
77+
mod test {
78+
use super::*;
79+
use paste::paste;
80+
81+
use serde_test::{
82+
Token, assert_tokens, assert_de_tokens, assert_de_tokens_error
83+
};
84+
85+
mod serde_serialize_deserialize_str {
86+
use super::*;
87+
88+
macro_rules! impl_case {
89+
($name:ident : $input:literal => $output:literal) => {
90+
#[test]
91+
fn $name() {
92+
let expected = Token::Str($output);
93+
let decimal: BigDecimal = $input.parse().unwrap();
94+
assert_tokens(&decimal, &[expected]);
95+
}
96+
}
97+
}
98+
99+
impl_case!(case_1d0: "1.0" => "1.0");
100+
impl_case!(case_0d5: "0.5" => "0.5");
101+
impl_case!(case_50: "50" => "50");
102+
impl_case!(case_50000: "50000" => "50000");
103+
impl_case!(case_1en3: "1e-3" => "0.001");
104+
impl_case!(case_1e12: "1e12" => "1000000000000");
105+
impl_case!(case_d25: ".25" => "0.25");
106+
impl_case!(case_12d34e1: "12.34e1" => "123.4");
107+
impl_case!(case_40d0010: "40.0010" => "40.0010");
108+
}
109+
110+
#[cfg(not(feature = "string-only"))]
111+
mod serde_deserialize_int {
112+
use super::*;
113+
114+
macro_rules! impl_case {
115+
( $( $ttype:ident ),+ : -$input:literal ) => {
116+
$( paste! { impl_case!([< case_n $input _ $ttype:lower >] : $ttype : -$input); } )*
117+
};
118+
( $( $ttype:ident ),+ : $input:literal ) => {
119+
$( paste! { impl_case!([< case_ $input _ $ttype:lower >] : $ttype : $input); } )*
120+
};
121+
($name:ident : $type:ident : $input:literal) => {
122+
#[test]
123+
fn $name() {
124+
let expected = BigDecimal::from($input);
125+
let token = Token::$type($input);
126+
assert_de_tokens(&expected, &[token]);
127+
}
128+
};
129+
}
130+
131+
impl_case!(I8, I16, I32, I64, U8, U16, U32, U64 : 0);
132+
impl_case!(I8, I16, I32, I64, U8, U16, U32, U64 : 1);
133+
impl_case!(I8, I16, I32, I64 : -1);
134+
impl_case!(I64: -99999999999i64);
135+
impl_case!(I64: -9_223_372_036_854_775_808i64);
136+
}
137+
138+
#[cfg(not(feature = "string-only"))]
139+
mod serde_deserialize_float {
140+
use super::*;
141+
142+
macro_rules! impl_case {
143+
( $name:ident : $input:literal => $ttype:ident : $expected:literal ) => {
144+
paste! {
145+
#[test]
146+
fn [< $name _ $ttype:lower >]() {
147+
let expected: BigDecimal = $expected.parse().unwrap();
148+
let token = Token::$ttype($input);
149+
assert_de_tokens(&expected, &[token]);
150+
}
151+
}
152+
};
153+
( $name:ident : $input:literal => $( $ttype:ident : $expected:literal )+ ) => {
154+
$( impl_case!($name : $input => $ttype : $expected); )*
155+
};
156+
( $name:ident : $input:literal => $( $ttype:ident ),+ : $expected:literal ) => {
157+
$( impl_case!($name : $input => $ttype : $expected); )*
158+
};
159+
}
160+
161+
impl_case!(case_1d0 : 1.0 => F32, F64 : "1");
162+
impl_case!(case_1d1 : 1.1 => F32 : "1.10000002384185791015625"
163+
F64 : "1.100000000000000088817841970012523233890533447265625");
164+
165+
impl_case!(case_0d001834988943300:
166+
0.001834988943300 => F32 : "0.001834988943301141262054443359375"
167+
F64 : "0.00183498894330000003084768511740776375518180429935455322265625");
168+
169+
impl_case!(case_n869651d9131236838:
170+
-869651.9131236838 => F32 : "-869651.9375"
171+
F64 : "-869651.91312368377111852169036865234375");
172+
173+
impl_case!(case_n1en20:
174+
-1e-20 => F32 : "-9.999999682655225388967887463487205224055287544615566730499267578125E-21"
175+
F64 : "-999999999999999945153271454209571651729503702787392447107715776066783064379706047475337982177734375e-119");
176+
}
177+
178+
#[cfg(not(feature = "string-only"))]
179+
mod serde_deserialize_nan {
180+
use super::*;
181+
182+
#[test]
183+
fn case_f32() {
184+
let tokens = [ Token::F32(f32::NAN) ];
185+
assert_de_tokens_error::<BigDecimal>(&tokens, "NAN");
186+
}
187+
188+
#[test]
189+
fn case_f64() {
190+
let tokens = [ Token::F64(f64::NAN) ];
191+
assert_de_tokens_error::<BigDecimal>(&tokens, "NAN");
192+
}
193+
}
194+
}

src/lib.rs

+7-165
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ extern crate paste;
5959
#[cfg(feature = "serde")]
6060
extern crate serde;
6161

62+
#[cfg(all(test, feature = "serde"))]
63+
extern crate serde_test;
64+
6265
#[cfg(feature = "std")]
6366
include!("./with_std.rs");
6467

@@ -113,6 +116,10 @@ mod impl_cmp;
113116
// Implementations of num_traits
114117
mod impl_num;
115118

119+
// Implementations for deserializations and serializations
120+
#[cfg(feature = "serde")]
121+
pub mod impl_serde;
122+
116123
// construct BigDecimals from strings and floats
117124
mod parsing;
118125

@@ -1344,171 +1351,6 @@ impl<'a> From<&'a BigInt> for BigDecimalRef<'a> {
13441351
}
13451352
}
13461353

1347-
1348-
/// Tools to help serializing/deserializing `BigDecimal`s
1349-
#[cfg(feature = "serde")]
1350-
mod bigdecimal_serde {
1351-
use super::*;
1352-
use serde::{de, ser};
1353-
1354-
#[allow(unused_imports)]
1355-
use num_traits::FromPrimitive;
1356-
1357-
impl ser::Serialize for BigDecimal {
1358-
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1359-
where
1360-
S: ser::Serializer,
1361-
{
1362-
serializer.collect_str(&self)
1363-
}
1364-
}
1365-
1366-
struct BigDecimalVisitor;
1367-
1368-
impl<'de> de::Visitor<'de> for BigDecimalVisitor {
1369-
type Value = BigDecimal;
1370-
1371-
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1372-
write!(formatter, "a number or formatted decimal string")
1373-
}
1374-
1375-
fn visit_str<E>(self, value: &str) -> Result<BigDecimal, E>
1376-
where
1377-
E: de::Error,
1378-
{
1379-
BigDecimal::from_str(value).map_err(|err| E::custom(format!("{}", err)))
1380-
}
1381-
1382-
fn visit_u64<E>(self, value: u64) -> Result<BigDecimal, E>
1383-
where
1384-
E: de::Error,
1385-
{
1386-
Ok(BigDecimal::from(value))
1387-
}
1388-
1389-
fn visit_i64<E>(self, value: i64) -> Result<BigDecimal, E>
1390-
where
1391-
E: de::Error,
1392-
{
1393-
Ok(BigDecimal::from(value))
1394-
}
1395-
1396-
fn visit_f64<E>(self, value: f64) -> Result<BigDecimal, E>
1397-
where
1398-
E: de::Error,
1399-
{
1400-
BigDecimal::try_from(value).map_err(|err| E::custom(format!("{}", err)))
1401-
}
1402-
}
1403-
1404-
#[cfg(not(feature = "string-only"))]
1405-
impl<'de> de::Deserialize<'de> for BigDecimal {
1406-
fn deserialize<D>(d: D) -> Result<Self, D::Error>
1407-
where
1408-
D: de::Deserializer<'de>,
1409-
{
1410-
d.deserialize_any(BigDecimalVisitor)
1411-
}
1412-
}
1413-
1414-
#[cfg(feature = "string-only")]
1415-
impl<'de> de::Deserialize<'de> for BigDecimal {
1416-
fn deserialize<D>(d: D) -> Result<Self, D::Error>
1417-
where
1418-
D: de::Deserializer<'de>,
1419-
{
1420-
d.deserialize_str(BigDecimalVisitor)
1421-
}
1422-
}
1423-
1424-
#[cfg(test)]
1425-
extern crate serde_json;
1426-
1427-
#[test]
1428-
fn test_serde_serialize() {
1429-
let vals = vec![
1430-
("1.0", "1.0"),
1431-
("0.5", "0.5"),
1432-
("50", "50"),
1433-
("50000", "50000"),
1434-
("1e-3", "0.001"),
1435-
("1e12", "1000000000000"),
1436-
("0.25", "0.25"),
1437-
("12.34", "12.34"),
1438-
("0.15625", "0.15625"),
1439-
("0.3333333333333333", "0.3333333333333333"),
1440-
("3.141592653589793", "3.141592653589793"),
1441-
("94247.77960769380", "94247.77960769380"),
1442-
("10.99", "10.99"),
1443-
("12.0010", "12.0010"),
1444-
];
1445-
for (s, v) in vals {
1446-
let expected = format!("\"{}\"", v);
1447-
let value = serde_json::to_string(&BigDecimal::from_str(s).unwrap()).unwrap();
1448-
assert_eq!(expected, value);
1449-
}
1450-
}
1451-
1452-
#[test]
1453-
fn test_serde_deserialize_str() {
1454-
let vals = vec![
1455-
("1.0", "1.0"),
1456-
("0.5", "0.5"),
1457-
("50", "50"),
1458-
("50000", "50000"),
1459-
("1e-3", "0.001"),
1460-
("1e12", "1000000000000"),
1461-
("0.25", "0.25"),
1462-
("12.34", "12.34"),
1463-
("0.15625", "0.15625"),
1464-
("0.3333333333333333", "0.3333333333333333"),
1465-
("3.141592653589793", "3.141592653589793"),
1466-
("94247.77960769380", "94247.77960769380"),
1467-
("10.99", "10.99"),
1468-
("12.0010", "12.0010"),
1469-
];
1470-
for (s, v) in vals {
1471-
let expected = BigDecimal::from_str(v).unwrap();
1472-
let value: BigDecimal = serde_json::from_str(&format!("\"{}\"", s)).unwrap();
1473-
assert_eq!(expected, value);
1474-
}
1475-
}
1476-
1477-
#[test]
1478-
#[cfg(not(feature = "string-only"))]
1479-
fn test_serde_deserialize_int() {
1480-
let vals = vec![0, 1, 81516161, -370, -8, -99999999999];
1481-
for n in vals {
1482-
let expected = BigDecimal::from_i64(n).unwrap();
1483-
let value: BigDecimal = serde_json::from_str(&serde_json::to_string(&n).unwrap()).unwrap();
1484-
assert_eq!(expected, value);
1485-
}
1486-
}
1487-
1488-
#[test]
1489-
#[cfg(not(feature = "string-only"))]
1490-
fn test_serde_deserialize_f64() {
1491-
let vals = vec![
1492-
1.0,
1493-
0.5,
1494-
0.25,
1495-
50.0,
1496-
50000.,
1497-
0.001,
1498-
12.34,
1499-
5.0 * 0.03125,
1500-
stdlib::f64::consts::PI,
1501-
stdlib::f64::consts::PI * 10000.0,
1502-
stdlib::f64::consts::PI * 30000.0,
1503-
];
1504-
for n in vals {
1505-
let expected = BigDecimal::from_f64(n).unwrap();
1506-
let value: BigDecimal = serde_json::from_str(&serde_json::to_string(&n).unwrap()).unwrap();
1507-
assert_eq!(expected, value);
1508-
}
1509-
}
1510-
}
1511-
15121354
#[rustfmt::skip]
15131355
#[cfg(test)]
15141356
#[allow(non_snake_case)]

0 commit comments

Comments
 (0)