1use std::str::FromStr;
57
58use rust_decimal::Decimal;
59use serde::{
60 Deserialize, Deserializer, Serialize, Serializer,
61 de::{Error, MapAccess, Visitor, value::MapAccessDeserializer},
62};
63use serde_json::{Number, value::RawValue};
64
65use super::{DecimalVisitor, decimal_components, json_token_text};
66
67pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Decimal, D::Error> {
84 deserializer.deserialize_any(ExactDecimalVisitor)
85}
86
87pub fn deserialize_optional<'de, D: Deserializer<'de>>(
95 deserializer: D,
96) -> Result<Option<Decimal>, D::Error> {
97 deserializer.deserialize_option(OptionalExactDecimalVisitor)
98}
99
100pub fn deserialize_json<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Decimal, D::Error> {
111 let raw = Box::<RawValue>::deserialize(deserializer)?;
112 parse_json(&raw).map_err(D::Error::custom)
113}
114
115pub fn deserialize_optional_json<'de, D: Deserializer<'de>>(
123 deserializer: D,
124) -> Result<Option<Decimal>, D::Error> {
125 Option::<Box<RawValue>>::deserialize(deserializer)?
126 .map(|raw| parse_json(&raw).map_err(D::Error::custom))
127 .transpose()
128}
129
130pub fn serialize<S: Serializer>(value: &Decimal, serializer: S) -> Result<S::Ok, S::Error> {
148 let number = Number::from_str(&value.to_string()).map_err(serde::ser::Error::custom)?;
149 let represented = parse(&number.to_string()).map_err(serde::ser::Error::custom)?;
150 if represented != *value {
151 return Err(serde::ser::Error::custom(
152 "exact decimal number serialization requires serde_json/arbitrary_precision",
153 ));
154 }
155
156 number.serialize(serializer)
157}
158
159pub fn serialize_optional<S: Serializer>(
165 value: &Option<Decimal>,
166 serializer: S,
167) -> Result<S::Ok, S::Error> {
168 match value {
169 Some(value) => serialize(value, serializer),
170 None => serializer.serialize_none(),
171 }
172}
173
174pub fn parse(value: &str) -> Result<Decimal, rust_decimal::Error> {
187 if let Ok(value) = Decimal::from_str_exact(value) {
189 return Ok(value);
190 }
191
192 let (base, exponent) = match value.split_once(['e', 'E']) {
195 Some((base, exponent)) => (
196 base,
197 exponent
198 .parse::<i64>()
199 .map_err(|_| rust_decimal::Error::from("invalid decimal exponent"))?,
200 ),
201 None => (value, 0),
202 };
203
204 let negative = base.starts_with('-');
205 let base = base.strip_prefix(['-', '+']).unwrap_or(base);
206 if base.starts_with('_') || base.starts_with("._") {
207 return Err(rust_decimal::Error::from("invalid decimal significand"));
208 }
209
210 let base = base.replace('_', "");
211 let (whole, fraction) = decimal_components(&base)
212 .ok_or_else(|| rust_decimal::Error::from("invalid decimal significand"))?;
213 let mut digits = format!("{whole}{fraction}");
214 let mut scale = i64::try_from(fraction.len())
215 .ok()
216 .and_then(|scale| scale.checked_sub(exponent))
217 .ok_or_else(|| rust_decimal::Error::from("decimal scale out of range"))?;
218 digits = digits.trim_start_matches('0').to_string();
219 if digits.is_empty() {
220 return Ok(Decimal::ZERO);
221 }
222
223 while scale > 0 && digits.ends_with('0') {
224 digits.pop();
225 scale -= 1;
226 }
227
228 if scale < 0 {
229 let zeros = scale
230 .checked_neg()
231 .and_then(|scale| usize::try_from(scale).ok())
232 .filter(|zeros| digits.len().saturating_add(*zeros) <= 29)
233 .ok_or(rust_decimal::Error::ExceedsMaximumPossibleValue)?;
234 digits.extend(std::iter::repeat_n('0', zeros));
235 scale = 0;
236 }
237
238 let scale = u32::try_from(scale).map_err(|_| rust_decimal::Error::Underflow)?;
239 if scale > Decimal::MAX_SCALE {
240 return Err(rust_decimal::Error::Underflow);
241 }
242
243 let mantissa = digits
244 .parse::<i128>()
245 .map_err(|_| rust_decimal::Error::ExceedsMaximumPossibleValue)?;
246 Decimal::try_from_i128_with_scale(if negative { -mantissa } else { mantissa }, scale)
247}
248
249fn parse_json(raw: &RawValue) -> Result<Decimal, String> {
250 let text = json_token_text(raw).map_err(|e| e.to_string())?;
251 parse(&text).map_err(|e| e.to_string())
252}
253
254struct ExactDecimalVisitor;
255
256impl<'de> Visitor<'de> for ExactDecimalVisitor {
257 type Value = Decimal;
258
259 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
260 formatter
261 .write_str("an exact decimal string or integer, or an arbitrary-precision JSON number")
262 }
263
264 fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
265 parse(value).map_err(E::custom)
266 }
267
268 fn visit_i64<E: Error>(self, value: i64) -> Result<Self::Value, E> {
269 DecimalVisitor.visit_i64(value)
270 }
271
272 fn visit_u64<E: Error>(self, value: u64) -> Result<Self::Value, E> {
273 DecimalVisitor.visit_u64(value)
274 }
275
276 fn visit_i128<E: Error>(self, value: i128) -> Result<Self::Value, E> {
277 DecimalVisitor.visit_i128(value)
278 }
279
280 fn visit_u128<E: Error>(self, value: u128) -> Result<Self::Value, E> {
281 DecimalVisitor.visit_u128(value)
282 }
283
284 fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
285 let number = Number::deserialize(MapAccessDeserializer::new(map))?;
286 parse(&number.to_string()).map_err(A::Error::custom)
287 }
288}
289
290struct OptionalExactDecimalVisitor;
291
292impl<'de> Visitor<'de> for OptionalExactDecimalVisitor {
293 type Value = Option<Decimal>;
294
295 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
296 formatter.write_str("null or an exact decimal")
297 }
298
299 fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
300 Ok(None)
301 }
302
303 fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
304 Ok(None)
305 }
306
307 fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
308 deserialize(deserializer).map(Some)
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use std::{collections::BTreeMap, str::FromStr};
315
316 use proptest::prelude::*;
317 use rstest::rstest;
318 use rust_decimal::Decimal;
319 use rust_decimal_macros::dec;
320 use serde::{
321 Deserialize, Serialize,
322 de::value::{Error, F64Deserializer, I128Deserializer, U128Deserializer},
323 };
324 use serde_json::{Number, Value, value::RawValue};
325
326 use crate::serialization::{self, decimal};
327
328 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
329 struct Exact(#[serde(with = "decimal")] Decimal);
330
331 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
332 struct Raw(
333 #[serde(
334 deserialize_with = "decimal::deserialize_json",
335 serialize_with = "decimal::serialize"
336 )]
337 Decimal,
338 );
339
340 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
341 struct Optional {
342 #[serde(
343 default,
344 deserialize_with = "decimal::deserialize_optional",
345 serialize_with = "decimal::serialize_optional"
346 )]
347 value: Option<Decimal>,
348 }
349
350 #[derive(Debug, PartialEq, Eq, Deserialize)]
351 struct OptionalRaw {
352 #[serde(default, deserialize_with = "decimal::deserialize_optional_json")]
353 value: Option<Decimal>,
354 }
355
356 #[derive(Debug, Deserialize)]
357 struct Required {
358 #[serde(deserialize_with = "decimal::deserialize")]
359 value: Decimal,
360 }
361
362 #[derive(Debug, Deserialize)]
363 struct RequiredRaw {
364 #[serde(deserialize_with = "decimal::deserialize_json")]
365 value: Decimal,
366 }
367
368 #[derive(Debug, PartialEq, Eq, Deserialize)]
369 #[serde(tag = "kind")]
370 enum Tagged {
371 Amount {
372 #[serde(deserialize_with = "decimal::deserialize")]
373 value: Decimal,
374 },
375 }
376
377 #[derive(Debug, PartialEq, Eq, Deserialize)]
378 #[serde(untagged)]
379 enum Untagged {
380 Amount {
381 #[serde(deserialize_with = "decimal::deserialize")]
382 value: Decimal,
383 },
384 }
385
386 #[derive(Debug, Deserialize)]
387 #[serde(tag = "kind")]
388 enum TaggedRaw {
389 Amount {
390 #[serde(rename = "value", deserialize_with = "decimal::deserialize_json")]
391 _value: Decimal,
392 },
393 }
394
395 #[derive(Debug, Deserialize)]
396 #[serde(untagged)]
397 enum UntaggedRaw {
398 Amount {
399 #[serde(rename = "value", deserialize_with = "decimal::deserialize_json")]
400 _value: Decimal,
401 },
402 }
403
404 fn cases() -> [(&'static str, Decimal, bool); 22] {
405 [
406 ("123456789.123456789", dec!(123456789.123456789), false),
407 ("0.12345678901234568", dec!(0.12345678901234568), true),
408 ("9007199254740993", dec!(9007199254740993), true),
409 ("18446744073709551617", dec!(18446744073709551617), false),
410 (
411 "79228162514264337593543950335",
412 dec!(79228162514264337593543950335),
413 false,
414 ),
415 (
416 "-79228162514264337593543950335",
417 dec!(-79228162514264337593543950335),
418 false,
419 ),
420 ("1e-28", dec!(0.0000000000000000000000000001), false),
421 ("10e-29", dec!(0.0000000000000000000000000001), false),
422 ("1e28", dec!(10000000000000000000000000000), true),
423 ("0.1e29", dec!(10000000000000000000000000000), true),
424 (
425 "792281625142643375935439503350e-1",
426 dec!(79228162514264337593543950335),
427 false,
428 ),
429 (
430 "7.9228162514264337593543950335e28",
431 dec!(79228162514264337593543950335),
432 false,
433 ),
434 (
435 "0.00000000000000000000000000010",
436 dec!(0.0000000000000000000000000001),
437 false,
438 ),
439 (
440 "79228162514264337593543950335.0",
441 dec!(79228162514264337593543950335),
442 false,
443 ),
444 (
445 "1.234567890123456789012345678900E+1",
446 dec!(12.345678901234567890123456789),
447 false,
448 ),
449 ("-0.0", dec!(0), true),
450 ("0e1000000", dec!(0), true),
451 ("-3.75E+2", dec!(-375), true),
452 ("-375", dec!(-375), true),
453 (
454 "0.00000000000000000000000000001e1",
455 dec!(0.0000000000000000000000000001),
456 false,
457 ),
458 ("-12345e-4", dec!(-1.2345), true),
459 (
460 "1.234567890123456789012345678e-1",
461 dec!(0.1234567890123456789012345678),
462 false,
463 ),
464 ]
465 }
466
467 fn arbitrary_precision() -> bool {
468 Number::from_str(&Decimal::MAX.to_string())
469 .unwrap()
470 .to_string()
471 == Decimal::MAX.to_string()
472 }
473
474 fn object(token: &str, tagged: bool) -> String {
475 let mut fields = BTreeMap::new();
476 fields.insert("value", RawValue::from_string(token.to_string()).unwrap());
477
478 if tagged {
479 fields.insert(
480 "kind",
481 RawValue::from_string(serde_json::to_string("Amount").unwrap()).unwrap(),
482 );
483 }
484
485 serde_json::to_string(&fields).unwrap()
486 }
487
488 #[rstest]
489 fn exact_quoted_and_numeric_tokens() {
490 for (token, expected, _) in cases() {
491 let quoted = serde_json::to_string(&token).unwrap();
492 assert_eq!(decimal::parse(token).unwrap(), expected, "{token}");
493 assert_eq!(serde_json::from_str::<Raw>(token).unwrap(), Raw(expected));
494 assert_eq!(
495 serde_json::from_slice::<Raw>(token.as_bytes()).unwrap(),
496 Raw(expected)
497 );
498 assert_eq!(
499 serde_json::from_reader::<_, Raw>(token.as_bytes()).unwrap(),
500 Raw(expected)
501 );
502 assert_eq!(serde_json::from_str::<Raw>("ed).unwrap(), Raw(expected));
503 assert_eq!(
504 serde_json::from_str::<Exact>("ed).unwrap(),
505 Exact(expected)
506 );
507 let number: Number = serde_json::from_str(token).unwrap();
508 let direct = serde_json::from_str::<Exact>(token);
509 let buffered = serde_json::from_value::<Exact>(Value::Number(number.clone()));
510 let from_number = decimal::deserialize(number.clone());
511 if arbitrary_precision() || number.is_i64() || number.is_u64() {
512 assert_eq!(direct.unwrap(), Exact(expected));
513 assert_eq!(
514 serde_json::from_value::<Raw>(Value::Number(number.clone())).unwrap(),
515 Raw(expected)
516 );
517 assert_eq!(decimal::parse(&number.to_string()).unwrap(), expected);
518
519 match (buffered, from_number) {
520 (Ok(buffered), Ok(from_number)) => {
521 assert_eq!(buffered, Exact(expected));
522 assert_eq!(from_number, expected);
523 }
524 (Err(buffered), Err(from_number)) => {
525 assert!(buffered.to_string().contains("floating point"));
526 assert!(from_number.to_string().contains("floating point"));
527 }
528 results => panic!("buffered routes disagree: {results:?}"),
529 }
530 } else {
531 assert!(direct.is_err(), "{token}");
532 assert!(buffered.is_err(), "{token}");
533 assert!(from_number.is_err(), "{token}");
534 }
535 }
536 }
537
538 #[rstest]
539 fn invalid_values_and_shapes() {
540 for token in [
541 "79228162514264337593543950336",
542 "-79228162514264337593543950336",
543 "1e29",
544 "1e-29",
545 "-1e-29",
546 "0.00000000000000000000000000001",
547 "1.00000000000000000000000000001",
548 "79228162514264337593543950335.1",
549 "1e9223372036854775807",
550 "1e-9223372036854775808",
551 "1e9223372036854775808",
552 "1.2.3e1",
553 "",
554 "NaN",
555 "Infinity",
556 "1e",
557 "1e1e1",
558 "--1",
559 "0.12345678901234567890123456789e0",
560 "0.12345678901234567890123456789",
561 "--1e0",
562 "_1",
563 "._1",
564 "_1e1",
565 "._1e1",
566 ] {
567 assert!(decimal::parse(token).is_err(), "{token}");
568 let quoted = serde_json::to_string(&token).unwrap();
569 assert!(serde_json::from_str::<Raw>("ed).is_err(), "{token}");
570 assert!(serde_json::from_str::<Exact>("ed).is_err(), "{token}");
571 assert!(serde_json::from_str::<Raw>(token).is_err(), "{token}");
572 assert!(serde_json::from_str::<Exact>(token).is_err(), "{token}");
573 let json = object("ed, false);
574 assert!(serde_json::from_str::<Optional>(&json).is_err(), "{token}");
575 assert!(
576 serde_json::from_str::<OptionalRaw>(&json).is_err(),
577 "{token}"
578 );
579
580 if let Ok(value) = serde_json::from_str::<Value>(token) {
581 assert!(
582 serde_json::from_value::<Exact>(value.clone()).is_err(),
583 "{token}"
584 );
585
586 if arbitrary_precision() {
587 assert!(serde_json::from_value::<Raw>(value).is_err(), "{token}");
588 }
589 }
590 }
591
592 for token in ["null", "true", "false", "[]", "{}", "{\"amount\":1}"] {
593 assert!(serde_json::from_str::<Raw>(token).is_err(), "{token}");
594 assert!(serde_json::from_str::<Exact>(token).is_err(), "{token}");
595 }
596 }
597
598 #[rstest]
599 #[case("+1_234.50E-2", dec!(12.345))]
600 #[case("1.2_5", dec!(1.25))]
601 #[case(".5e1", dec!(5))]
602 fn quoted_decimal_syntax(#[case] token: &str, #[case] expected: Decimal) {
603 let json = serde_json::to_string(token).unwrap();
604 assert_eq!(decimal::parse(token).unwrap(), expected);
605 assert_eq!(serde_json::from_str::<Raw>(&json).unwrap(), Raw(expected));
606 assert_eq!(
607 serde_json::from_str::<Exact>(&json).unwrap(),
608 Exact(expected)
609 );
610 }
611
612 #[rstest]
613 fn quoted_json_escapes() {
614 assert_eq!(
615 serde_json::from_str::<Raw>(r#""\u0031.25""#).unwrap(),
616 Raw(dec!(1.25))
617 );
618 assert!(serde_json::from_str::<Raw>(r#""\uD800""#).is_err());
619 }
620
621 #[rstest]
622 fn private_number_map_requires_raw_shape_validation() {
623 let private_number = r#"{"$serde_json::private::Number":"123456789.123456789"}"#;
624 assert!(serde_json::from_str::<Raw>(private_number).is_err());
625 let direct = serde_json::from_str::<Exact>(private_number);
626 let value: Value = serde_json::from_str(private_number).unwrap();
627
628 if arbitrary_precision() {
629 assert_eq!(direct.unwrap(), Exact(dec!(123456789.123456789)));
630 assert!(value.is_number());
631 assert_eq!(
632 serde_json::from_value::<Raw>(value).unwrap(),
633 Raw(dec!(123456789.123456789))
634 );
635 } else {
636 assert!(direct.is_err());
637 assert!(value.is_object());
638 assert!(serde_json::from_value::<Raw>(value).is_err());
639 }
640
641 for token in [
642 "{\"$serde_json::private::Number\":\"not-a-number\"}",
643 "{\"$serde_json::private::Number\":\"1e-29\"}",
644 "{\"$serde_json::private::Number\":\"79228162514264337593543950336\"}",
645 ] {
646 assert!(serde_json::from_str::<Raw>(token).is_err());
647 assert!(serde_json::from_str::<Exact>(token).is_err());
648 }
649 }
650
651 #[rstest]
652 fn presence_semantics() {
653 for json in ["{}", r#"{"value":null}"#] {
654 assert!(serde_json::from_str::<Required>(json).is_err());
655 assert!(serde_json::from_str::<RequiredRaw>(json).is_err());
656 assert_eq!(
657 serde_json::from_str::<Optional>(json).unwrap(),
658 Optional { value: None }
659 );
660 assert_eq!(
661 serde_json::from_str::<OptionalRaw>(json).unwrap(),
662 OptionalRaw { value: None }
663 );
664 }
665
666 let empty = r#"{"value":""}"#;
667 assert!(serde_json::from_str::<Required>(empty).is_err());
668 assert!(serde_json::from_str::<RequiredRaw>(empty).is_err());
669 assert!(serde_json::from_str::<Optional>(empty).is_err());
670 assert!(serde_json::from_str::<OptionalRaw>(empty).is_err());
671
672 for (token, expected, _) in cases() {
673 let json = object(&serde_json::to_string(&token).unwrap(), false);
674 assert_eq!(
675 serde_json::from_str::<Required>(&json).unwrap().value,
676 expected
677 );
678 assert_eq!(
679 serde_json::from_str::<RequiredRaw>(&json).unwrap().value,
680 expected
681 );
682 assert_eq!(
683 serde_json::from_str::<Optional>(&json).unwrap().value,
684 Some(expected)
685 );
686 assert_eq!(
687 serde_json::from_str::<OptionalRaw>(&json).unwrap().value,
688 Some(expected)
689 );
690 let numeric = object(token, false);
691 assert_eq!(
692 serde_json::from_str::<OptionalRaw>(&numeric).unwrap().value,
693 Some(expected)
694 );
695 let optional = serde_json::from_str::<Optional>(&numeric);
696 let number = Number::from_str(token).unwrap();
697 if arbitrary_precision() || number.is_i64() || number.is_u64() {
698 assert_eq!(optional.unwrap().value, Some(expected));
699 } else {
700 assert!(optional.is_err());
701 }
702 }
703 }
704
705 #[rstest]
706 fn serde_enum_buffering() {
707 for (token, expected, _) in cases() {
708 let quoted = serde_json::to_string(&token).unwrap();
709 let tagged = object("ed, true);
710 let untagged = object("ed, false);
711 assert_eq!(
712 serde_json::from_str::<Tagged>(&tagged).unwrap(),
713 Tagged::Amount { value: expected }
714 );
715 assert_eq!(
716 serde_json::from_str::<Untagged>(&untagged).unwrap(),
717 Untagged::Amount { value: expected }
718 );
719 assert!(serde_json::from_str::<TaggedRaw>(&tagged).is_err());
720 assert!(serde_json::from_str::<UntaggedRaw>(&untagged).is_err());
721 let tagged = serde_json::from_str::<Tagged>(&object(token, true));
722 let untagged = serde_json::from_str::<Untagged>(&object(token, false));
723 let number = Number::from_str(token).unwrap();
724 if arbitrary_precision() || number.is_i64() || number.is_u64() {
725 assert_eq!(tagged.unwrap(), Tagged::Amount { value: expected });
726 assert_eq!(untagged.unwrap(), Untagged::Amount { value: expected });
727 } else {
728 assert!(tagged.is_err());
729 assert!(untagged.is_err());
730 }
731 }
732 }
733
734 #[rstest]
735 #[case(Decimal::MAX.mantissa(), Some(Decimal::MAX))]
736 #[case(Decimal::MIN.mantissa(), Some(Decimal::MIN))]
737 #[case(Decimal::MAX.mantissa() + 1, None)]
738 #[case(Decimal::MIN.mantissa() - 1, None)]
739 #[case(i128::MAX, None)]
740 #[case(i128::MIN, None)]
741 fn signed_integer_bounds(#[case] value: i128, #[case] expected: Option<Decimal>) {
742 assert_eq!(
743 decimal::deserialize(I128Deserializer::<Error>::new(value)).ok(),
744 expected
745 );
746 assert_eq!(
747 serialization::deserialize_decimal(I128Deserializer::<Error>::new(value)).ok(),
748 expected
749 );
750 assert_eq!(
751 serialization::deserialize_optional_decimal(I128Deserializer::<Error>::new(value)).ok(),
752 expected.map(Some)
753 );
754 }
755
756 #[rstest]
757 #[case(9_007_199_254_740_993, Some(dec!(9007199254740993)))]
758 #[case(18_446_744_073_709_551_617, Some(dec!(18446744073709551617)))]
759 #[case(Decimal::MAX.mantissa().unsigned_abs(), Some(Decimal::MAX))]
760 #[case(Decimal::MAX.mantissa().unsigned_abs() + 1, None)]
761 #[case(u128::MAX, None)]
762 fn unsigned_integer_bounds(#[case] value: u128, #[case] expected: Option<Decimal>) {
763 assert_eq!(
764 decimal::deserialize(U128Deserializer::<Error>::new(value)).ok(),
765 expected
766 );
767 assert_eq!(
768 serialization::deserialize_decimal(U128Deserializer::<Error>::new(value)).ok(),
769 expected
770 );
771 assert_eq!(
772 serialization::deserialize_optional_decimal(U128Deserializer::<Error>::new(value)).ok(),
773 expected.map(Some)
774 );
775 }
776
777 #[rstest]
778 #[case(0.5)]
779 #[case(f64::NAN)]
780 #[case(f64::INFINITY)]
781 fn buffered_floats_are_rejected(#[case] value: f64) {
782 assert!(decimal::deserialize(F64Deserializer::<Error>::new(value)).is_err());
783 }
784
785 #[rstest]
786 fn exact_numeric_serialization() {
787 for (token, expected, default_numeric) in cases() {
788 let text = serde_json::to_string(&Exact(expected));
789 let value = serde_json::to_value(Exact(expected));
790
791 let optional = serde_json::to_value(Optional {
792 value: Some(expected),
793 });
794
795 let supported = arbitrary_precision() || default_numeric;
796 assert_eq!(text.is_ok(), supported, "{token}: {text:?}");
797 assert_eq!(value.is_ok(), supported);
798 assert_eq!(optional.is_ok(), supported);
799
800 if supported {
801 let value = value.unwrap();
802 assert!(value.is_number());
803 assert_eq!(
804 serde_json::from_str::<Raw>(&text.unwrap()).unwrap(),
805 Raw(expected)
806 );
807 assert_eq!(
808 serde_json::from_value::<Raw>(value.clone()).unwrap(),
809 Raw(expected)
810 );
811 assert_eq!(decimal::parse(&value.to_string()).unwrap(), expected);
812 assert_eq!(optional.unwrap()["value"], value);
813 }
814 }
815
816 assert_eq!(
817 serde_json::to_value(Optional { value: None }).unwrap(),
818 serde_json::json!({"value": null})
819 );
820 }
821
822 #[rstest]
823 fn buffered_precision_boundary() {
824 let token = "0.12345678901234568";
825 let number = Number::from_str(token).unwrap();
826 let value = Value::Number(number.clone());
827 assert!(
828 decimal::deserialize(number.clone())
829 .unwrap_err()
830 .to_string()
831 .contains("floating point")
832 );
833 assert!(
834 serde_json::from_value::<Exact>(value.clone())
835 .unwrap_err()
836 .to_string()
837 .contains("floating point")
838 );
839 assert_eq!(
840 decimal::parse(&number.to_string()).unwrap(),
841 dec!(0.12345678901234568)
842 );
843 assert_eq!(
844 serde_json::from_value::<Raw>(value).unwrap(),
845 Raw(dec!(0.12345678901234568))
846 );
847
848 let original = "123456789.123456789";
849 let value: Value = serde_json::from_str(original).unwrap();
850 let buffered = serde_json::from_value::<Raw>(value).unwrap();
851
852 let expected = if arbitrary_precision() {
853 dec!(123456789.123456789)
854 } else {
855 dec!(123456789.12345679)
856 };
857
858 assert_eq!(buffered, Raw(expected));
859 assert_eq!(
860 serde_json::from_str::<Raw>(original).unwrap(),
861 Raw(dec!(123456789.123456789))
862 );
863 }
864
865 #[rstest]
866 fn permissive_buffered_overflow_returns_error() {
867 for token in [
868 "79228162514264337593543950336",
869 "-79228162514264337593543950336",
870 ] {
871 let mut direct = serde_json::Deserializer::from_str(token);
872 assert!(serialization::deserialize_decimal(&mut direct).is_err());
873 let value: Value = serde_json::from_str(token).unwrap();
874 assert!(serialization::deserialize_decimal(value.clone()).is_err());
875 assert!(serialization::deserialize_optional_decimal(value).is_err());
876 }
877 }
878
879 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
880 struct StringDecimal(
881 #[serde(
882 deserialize_with = "decimal::deserialize",
883 serialize_with = "serialization::serialize_decimal_as_str"
884 )]
885 Decimal,
886 );
887
888 proptest! {
889 #[rstest]
890 fn prop_checked_integer_visitors(
891 signed in prop_oneof![Decimal::MIN.mantissa()..=Decimal::MAX.mantissa(), any::<i128>()],
892 unsigned in prop_oneof![0..=Decimal::MAX.mantissa().unsigned_abs(), any::<u128>()],
893 ) {
894 let expected = Decimal::from_str_exact(&signed.to_string()).ok();
895 prop_assert_eq!(decimal::deserialize(I128Deserializer::<Error>::new(signed)).ok(), expected);
896 prop_assert_eq!(serialization::deserialize_decimal(I128Deserializer::<Error>::new(signed)).ok(), expected);
897 let expected = Decimal::from_str_exact(&unsigned.to_string()).ok();
898 prop_assert_eq!(decimal::deserialize(U128Deserializer::<Error>::new(unsigned)).ok(), expected);
899 prop_assert_eq!(serialization::deserialize_decimal(U128Deserializer::<Error>::new(unsigned)).ok(), expected);
900 }
901
902 #[rstest]
903 fn prop_roundtrips_and_exponent_rescaling(
904 mantissa in Decimal::MIN.mantissa()..=Decimal::MAX.mantissa(),
905 scale in 0u32..=Decimal::MAX_SCALE,
906 zeros in 0usize..=35,
907 ) {
908 let expected = Decimal::try_from_i128_with_scale(mantissa, scale).unwrap();
909 let scientific = format!("{mantissa}{}e-{}", "0".repeat(zeros), scale as usize + zeros);
910 prop_assert_eq!(decimal::parse(&scientific).unwrap(), expected);
911 prop_assert_eq!(serde_json::from_str::<Raw>(&scientific).unwrap(), Raw(expected));
912 let mut plain = expected.to_string();
913 if !plain.contains('.') { plain.push('.'); }
914 plain.push_str(&"0".repeat(zeros));
915 prop_assert_eq!(decimal::parse(&plain).unwrap(), expected);
916 let string = serde_json::to_value(StringDecimal(expected)).unwrap();
917 prop_assert_eq!(serde_json::from_value::<StringDecimal>(string).unwrap(), StringDecimal(expected));
918 if let Ok(number) = serde_json::to_value(Exact(expected)) {
919 prop_assert_eq!(decimal::parse(&number.to_string()).unwrap(), expected);
920 prop_assert_eq!(serde_json::from_value::<Raw>(number).unwrap(), Raw(expected));
921 } else {
922 prop_assert!(!arbitrary_precision());
923 }
924 }
925
926 #[rstest]
927 fn prop_parse_never_panics(value in "\\PC{0,128}") {
928 let _ = decimal::parse(&value);
929 }
930 }
931}