1use crate::*;
5use serde_crate::{self as serde, de, ser, Serialize, Deserialize};
6
7#[cfg(feature = "serde_json")]
9include!(concat!(env!("OUT_DIR"), "/serde_scale_limit.rs"));
10
11impl ser::Serialize for BigDecimal {
12 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
13 where
14 S: ser::Serializer,
15 {
16 serializer.collect_str(&self)
17 }
18}
19
20struct BigDecimalVisitor;
22
23impl<'de> de::Visitor<'de> for BigDecimalVisitor {
24 type Value = BigDecimal;
25
26 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
27 write!(formatter, "a number or formatted decimal string")
28 }
29
30 fn visit_str<E>(self, value: &str) -> Result<BigDecimal, E>
31 where
32 E: de::Error,
33 {
34 BigDecimal::from_str(value).map_err(|err| E::custom(format!("{}", err)))
35 }
36
37 fn visit_u64<E>(self, value: u64) -> Result<BigDecimal, E>
38 where
39 E: de::Error,
40 {
41 Ok(BigDecimal::from(value))
42 }
43
44 fn visit_i64<E>(self, value: i64) -> Result<BigDecimal, E>
45 where
46 E: de::Error,
47 {
48 Ok(BigDecimal::from(value))
49 }
50
51 fn visit_u128<E>(self, value: u128) -> Result<BigDecimal, E>
52 where
53 E: de::Error,
54 {
55 Ok(BigDecimal::from(value))
56 }
57
58 fn visit_i128<E>(self, value: i128) -> Result<BigDecimal, E>
59 where
60 E: de::Error,
61 {
62 Ok(BigDecimal::from(value))
63 }
64
65 fn visit_f32<E>(self, value: f32) -> Result<BigDecimal, E>
66 where
67 E: de::Error,
68 {
69 BigDecimal::try_from(value).map_err(|err| E::custom(format!("{}", err)))
70 }
71
72 fn visit_f64<E>(self, value: f64) -> Result<BigDecimal, E>
73 where
74 E: de::Error,
75 {
76 BigDecimal::try_from(value).map_err(|err| E::custom(format!("{}", err)))
77 }
78
79 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
80 where
81 A: de::MapAccess<'de>,
82 {
83 match map.next_key::<&str>() {
84 Ok(Some("$serde_json::private::Number")) => {
85 map.next_value::<BigDecimal>()
86 }
87 _ => {
88 Err(de::Error::invalid_type(de::Unexpected::Map, &self))
89 }
90 }
91 }
92}
93
94#[cfg(not(feature = "string-only"))]
95impl<'de> de::Deserialize<'de> for BigDecimal {
96 fn deserialize<D>(d: D) -> Result<Self, D::Error>
97 where
98 D: de::Deserializer<'de>,
99 {
100 d.deserialize_any(BigDecimalVisitor)
101 }
102}
103
104#[cfg(feature = "string-only")]
105impl<'de> de::Deserialize<'de> for BigDecimal {
106 fn deserialize<D>(d: D) -> Result<Self, D::Error>
107 where
108 D: de::Deserializer<'de>,
109 {
110 d.deserialize_str(BigDecimalVisitor)
111 }
112}
113
114#[cfg(test)]
115mod test {
116 use super::*;
117 use paste::paste;
118
119 use serde_test::{
120 Token, assert_tokens, assert_de_tokens, assert_de_tokens_error
121 };
122
123 mod serde_serialize_deserialize_str {
124 use super::*;
125
126 macro_rules! impl_case {
127 ($name:ident : $input:literal => $output:literal) => {
128 #[test]
129 fn $name() {
130 let expected = Token::Str($output);
131 let decimal: BigDecimal = $input.parse().unwrap();
132 assert_tokens(&decimal, &[expected]);
133 }
134 }
135 }
136
137 impl_case!(case_1d0: "1.0" => "1.0");
138 impl_case!(case_0d5: "0.5" => "0.5");
139 impl_case!(case_50: "50" => "50");
140 impl_case!(case_50000: "50000" => "50000");
141 impl_case!(case_1en3: "1e-3" => "0.001");
142 impl_case!(case_10e11: "10e11" => "1000000000000");
143 impl_case!(case_d25: ".25" => "0.25");
144 impl_case!(case_12d34e1: "12.34e1" => "123.4");
145 impl_case!(case_40d0010: "40.0010" => "40.0010");
146 }
147
148 #[cfg(not(feature = "string-only"))]
149 mod serde_deserialize_int {
150 use super::*;
151
152 macro_rules! impl_case {
153 ( $( $ttype:ident ),+ : -$input:literal ) => {
154 $( paste! { impl_case!([< case_n $input _ $ttype:lower >] : $ttype : -$input); } )*
155 };
156 ( $( $ttype:ident ),+ : $input:literal ) => {
157 $( paste! { impl_case!([< case_ $input _ $ttype:lower >] : $ttype : $input); } )*
158 };
159 ($name:ident : $type:ident : $input:literal) => {
160 #[test]
161 fn $name() {
162 let expected = BigDecimal::from($input);
163 let token = Token::$type($input);
164 assert_de_tokens(&expected, &[token]);
165 }
166 };
167 }
168
169 impl_case!(I8, I16, I32, I64, U8, U16, U32, U64 : 0);
170 impl_case!(I8, I16, I32, I64, U8, U16, U32, U64 : 1);
171 impl_case!(I8, I16, I32, I64 : -1);
172 impl_case!(I64: -99999999999i64);
173 impl_case!(I64: -9_223_372_036_854_775_808i64);
174 }
175
176 #[cfg(not(feature = "string-only"))]
177 mod serde_deserialize_float {
178 use super::*;
179
180 macro_rules! impl_case {
181 ( $name:ident : $input:literal => $ttype:ident : $expected:literal ) => {
182 paste! {
183 #[test]
184 fn [< $name _ $ttype:lower >]() {
185 let expected: BigDecimal = $expected.parse().unwrap();
186 let token = Token::$ttype($input);
187 assert_de_tokens(&expected, &[token]);
188 }
189 }
190 };
191 ( $name:ident : $input:literal => $( $ttype:ident : $expected:literal )+ ) => {
192 $( impl_case!($name : $input => $ttype : $expected); )*
193 };
194 ( $name:ident : $input:literal => $( $ttype:ident ),+ : $expected:literal ) => {
195 $( impl_case!($name : $input => $ttype : $expected); )*
196 };
197 }
198
199 impl_case!(case_1d0 : 1.0 => F32, F64 : "1");
200 impl_case!(case_1d1 : 1.1 => F32 : "1.10000002384185791015625"
201 F64 : "1.100000000000000088817841970012523233890533447265625");
202
203 impl_case!(case_0d001834988943300:
204 0.001834988943300 => F32 : "0.001834988943301141262054443359375"
205 F64 : "0.00183498894330000003084768511740776375518180429935455322265625");
206
207 impl_case!(case_n869651d9131236838:
208 -869651.9131236838 => F32 : "-869651.9375"
209 F64 : "-869651.91312368377111852169036865234375");
210
211 impl_case!(case_n1en20:
212 -1e-20 => F32 : "-9.999999682655225388967887463487205224055287544615566730499267578125E-21"
213 F64 : "-999999999999999945153271454209571651729503702787392447107715776066783064379706047475337982177734375e-119");
214 }
215
216 #[cfg(not(feature = "string-only"))]
217 mod serde_deserialize_nan {
218 use super::*;
219
220 #[test]
221 fn case_f32() {
222 let tokens = [ Token::F32(f32::NAN) ];
223 assert_de_tokens_error::<BigDecimal>(&tokens, "NAN");
224 }
225
226 #[test]
227 fn case_f64() {
228 let tokens = [ Token::F64(f64::NAN) ];
229 assert_de_tokens_error::<BigDecimal>(&tokens, "NAN");
230 }
231 }
232
233
234 #[cfg(feature = "serde_json")]
235 mod json_support {
236 use super::*;
237 use impl_serde::{Serialize, Deserialize};
238 use serde_json;
239
240 #[derive(Serialize,Deserialize)]
241 struct TestStruct {
242 name: String,
243 value: BigDecimal,
244 #[serde(with = "crate::serde::json_num")]
245 number: BigDecimal,
246 }
247
248
249 #[test]
250 fn test_struct_parsing() {
251 let json_src = r#"
252 { "name": "foo", "value": 0.0008741329382918, "number": "12.34" }
253 "#;
254 let my_struct: TestStruct = serde_json::from_str(&json_src).unwrap();
255 assert_eq!(&my_struct.name, "foo");
256 assert_eq!(&my_struct.value, &"0.0008741329382918".parse().unwrap());
257 assert_eq!(&my_struct.number, &"12.34".parse().unwrap());
258
259 let s = serde_json::to_string(&my_struct).unwrap();
260 assert_eq!(s, r#"{"name":"foo","value":"0.0008741329382918","number":12.34}"#);
261 }
262
263 }
264}
265
266
267#[cfg(feature = "serde_json")]
290pub mod arbitrary_precision {
291 use super::*;
292
293 pub fn deserialize<'de, D>(deserializer: D) -> Result<BigDecimal, D::Error>
294 where
295 D: serde::de::Deserializer<'de>,
296 {
297 let n = BigDecimal::deserialize(deserializer)?;
298
299 if n.scale.abs() > SERDE_SCALE_LIMIT && SERDE_SCALE_LIMIT > 0 {
300 let msg = format!("Calculated exponent '{}' out of bounds", -n.scale);
301 Err(serde::de::Error::custom(msg))
302 } else {
303 Ok(n)
304 }
305 }
306
307 pub fn serialize<S>(value: &BigDecimal, serializer: S) -> Result<S::Ok, S::Error>
308 where
309 S: serde::Serializer,
310 {
311 serde_json::Number::from_str(&value.to_string())
312 .map_err(ser::Error::custom)?
313 .serialize(serializer)
314 }
315}
316
317
318#[cfg(feature = "serde_json")]
347pub mod arbitrary_precision_option {
348 use super::*;
349
350 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<BigDecimal>, D::Error>
351 where
352 D: serde::de::Deserializer<'de>,
353 {
354 Option::<serde_json::Number>::deserialize(deserializer)?
355 .map(|num| num.as_str().parse().map_err(serde::de::Error::custom))
356 .transpose()
357 }
358
359 pub fn serialize<S>(value: &Option<BigDecimal>, serializer: S) -> Result<S::Ok, S::Error>
360 where
361 S: serde::Serializer,
362 {
363 match *value {
364 Some(ref decimal) => {
365 serde_json::Number::from_str(&decimal.to_string())
366 .map_err(serde::ser::Error::custom)?
367 .serialize(serializer)
368 }
369 None => serializer.serialize_none(),
370 }
371 }
372}
373
374
375#[cfg(all(test, feature = "serde_json"))]
376mod test_jsonification {
377 use super::*;
378 extern crate serde_json;
379
380 mod deserialize_f64 {
381 use super::*;
382
383 macro_rules! impl_case {
384 ($name:ident : $input:expr) => {
385 impl_case!($name: $input => $input);
386 };
387 ($name:ident : $input:expr => $expected:literal) => {
388 #[test]
389 fn $name() {
390 let mut json_deserialize = serde_json::Deserializer::from_str($input);
391 let value = arbitrary_precision::deserialize(&mut json_deserialize)
392 .expect("should parse JSON");
393 let expected: BigDecimal = $expected.parse().unwrap();
394
395 assert_eq!(expected, value);
396 }
397 };
398 }
399
400 impl_case!(case_1d0: "1.0" => "1.0");
401 impl_case!(case_0d001: "0.001" => "0.001");
402 impl_case!(case_41009d2207etc: "41009.22075436852032769878903135430037010");
403 }
404
405 mod serde_struct_decimals {
406 use super::*;
407 use crate as bigdecimal;
408
409 #[derive(Serialize, Deserialize)]
410 pub struct TestExample {
411 #[serde(with = "bigdecimal::serde::json_num")]
412 value: BigDecimal,
413 }
414
415 macro_rules! impl_case {
416 ($name:ident : $input:expr => (error)) => {
417 #[test]
418 fn $name() {
419 let res = serde_json::from_str::<TestExample>($input);
420 assert!(res.is_err());
421 }
422 };
423 ($name:ident : $input:expr => $expected:expr) => {
424 #[test]
425 fn $name() {
426 let obj: TestExample = serde_json::from_str($input).unwrap();
427 let expected: BigDecimal = $expected.parse().unwrap();
428
429 assert_eq!(expected, obj.value);
430
431 let s = serde_json::to_string(&obj).unwrap();
433 let input_stripped = $input.replace(" ", "");
434
435 assert_eq!(&s, &input_stripped);
436 }
437 };
438 }
439
440 impl_case!(case_1d0: r#"{ "value": 1.0 }"# => "1.0" );
441 impl_case!(case_2d01: r#"{ "value": 2.01 }"# => "2.01" );
442 impl_case!(case_50: r#"{ "value": 50 }"# => "50" );
443 impl_case!(case_high_prec: r#"{ "value": 64771126779.35857825871133263810255301911 }"# => "64771126779.35857825871133263810255301911" );
444
445 impl_case!(case_nan: r#"{ "value": nan }"# => (error) );
446
447
448 #[test]
449 fn scale_out_of_bounds() {
450 use serde_crate::de::Error;
451
452 let src = r#"{ "value": 1e92233720392233 }"#;
453
454 let parse_err = serde_json::from_str::<TestExample>(&src).err().unwrap();
455 let err_str = parse_err.to_string();
456
457 assert!(err_str.starts_with("Calculated exponent '92233720392233' out of bounds"), "{}", err_str);
458 }
459 }
460}