1use std::str::FromStr;
26
27use bytes::Bytes;
28use rust_decimal::Decimal;
29use serde::{
30 Deserialize, Deserializer, Serialize, Serializer,
31 de::{Error, Unexpected, Visitor},
32 ser::SerializeSeq,
33};
34use ustr::Ustr;
35
36struct BoolVisitor;
37
38struct DecimalVisitor;
43
44impl Visitor<'_> for DecimalVisitor {
45 type Value = Decimal;
46
47 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
48 formatter.write_str("a decimal number as string, integer, or float")
49 }
50
51 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
53 if v.is_empty() {
54 return Ok(Decimal::ZERO);
55 }
56 if v.contains('e') || v.contains('E') {
58 Decimal::from_scientific(v).map_err(E::custom)
59 } else {
60 Decimal::from_str(v).map_err(E::custom)
61 }
62 }
63
64 fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
66 self.visit_str(&v)
67 }
68
69 fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
71 Ok(Decimal::from(v))
72 }
73
74 fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
75 Ok(Decimal::from(v))
76 }
77
78 fn visit_i128<E: Error>(self, v: i128) -> Result<Self::Value, E> {
79 Ok(Decimal::from(v))
80 }
81
82 fn visit_u128<E: Error>(self, v: u128) -> Result<Self::Value, E> {
83 Ok(Decimal::from(v))
84 }
85
86 fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
88 if v.is_nan() {
89 return Err(E::invalid_value(Unexpected::Float(v), &self));
90 }
91 if v.is_infinite() {
92 return Err(E::invalid_value(Unexpected::Float(v), &self));
93 }
94 Decimal::try_from(v).map_err(E::custom)
95 }
96
97 fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
99 Ok(Decimal::ZERO)
100 }
101
102 fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
103 Ok(Decimal::ZERO)
104 }
105}
106
107struct OptionalDecimalVisitor;
112
113impl Visitor<'_> for OptionalDecimalVisitor {
114 type Value = Option<Decimal>;
115
116 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
117 formatter.write_str("null or a decimal number as string, integer, or float")
118 }
119
120 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
123 if v.is_empty() {
124 return Ok(None);
125 }
126 DecimalVisitor.visit_str(v).map(Some)
127 }
128
129 fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
130 self.visit_str(&v)
131 }
132
133 fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
134 DecimalVisitor.visit_i64(v).map(Some)
135 }
136
137 fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
138 DecimalVisitor.visit_u64(v).map(Some)
139 }
140
141 fn visit_i128<E: Error>(self, v: i128) -> Result<Self::Value, E> {
142 DecimalVisitor.visit_i128(v).map(Some)
143 }
144
145 fn visit_u128<E: Error>(self, v: u128) -> Result<Self::Value, E> {
146 DecimalVisitor.visit_u128(v).map(Some)
147 }
148
149 fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
150 DecimalVisitor.visit_f64(v).map(Some)
151 }
152
153 fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
155 Ok(None)
156 }
157
158 fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
159 Ok(None)
160 }
161}
162
163pub trait Serializable: Serialize + for<'de> Deserialize<'de> {
165 fn from_json_bytes(data: &[u8]) -> Result<Self, serde_json::Error> {
171 serde_json::from_slice(data)
172 }
173
174 fn to_json_bytes(&self) -> Result<Bytes, serde_json::Error> {
180 serde_json::to_vec(self).map(Bytes::from)
181 }
182}
183
184pub use self::msgpack::{FromMsgPack, MsgPackSerializable, ToMsgPack};
185
186pub mod msgpack {
191 use bytes::Bytes;
192 use serde::{Deserialize, Serialize};
193
194 use super::Serializable;
195
196 pub trait FromMsgPack: for<'de> Deserialize<'de> + Sized {
198 fn from_msgpack_bytes(data: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
204 rmp_serde::from_slice(data)
205 }
206 }
207
208 pub trait ToMsgPack: Serialize {
210 fn to_msgpack_bytes(&self) -> Result<Bytes, rmp_serde::encode::Error> {
216 rmp_serde::to_vec_named(self).map(Bytes::from)
217 }
218 }
219
220 pub trait MsgPackSerializable: Serializable + FromMsgPack + ToMsgPack {}
224
225 impl<T> FromMsgPack for T where T: Serializable {}
226
227 impl<T> ToMsgPack for T where T: Serializable {}
228
229 impl<T> MsgPackSerializable for T where T: Serializable {}
230}
231
232impl Visitor<'_> for BoolVisitor {
233 type Value = u8;
234
235 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 formatter.write_str("a boolean as u8")
237 }
238
239 fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
240 where
241 E: serde::de::Error,
242 {
243 Ok(u8::from(value))
244 }
245
246 #[allow(
247 clippy::cast_possible_truncation,
248 reason = "Intentional for parsing, value range validated"
249 )]
250 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
251 where
252 E: serde::de::Error,
253 {
254 if value > 1 {
259 Err(E::invalid_value(Unexpected::Unsigned(value), &self))
260 } else {
261 Ok(value as u8)
262 }
263 }
264}
265
266#[must_use]
270pub const fn default_true() -> bool {
271 true
272}
273
274#[must_use]
278pub const fn default_false() -> bool {
279 false
280}
281
282pub fn from_bool_as_u8<'de, D>(deserializer: D) -> Result<u8, D::Error>
288where
289 D: Deserializer<'de>,
290{
291 deserializer.deserialize_any(BoolVisitor)
292}
293
294pub fn deserialize_decimal<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
316where
317 D: Deserializer<'de>,
318{
319 deserializer.deserialize_any(DecimalVisitor)
320}
321
322pub fn deserialize_optional_decimal<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
345where
346 D: Deserializer<'de>,
347{
348 deserializer.deserialize_any(OptionalDecimalVisitor)
351}
352
353pub fn serialize_decimal<S: Serializer>(d: &Decimal, s: S) -> Result<S::Ok, S::Error> {
361 rust_decimal::serde::float::serialize(d, s)
362}
363
364pub fn serialize_optional_decimal<S: Serializer>(
370 d: &Option<Decimal>,
371 s: S,
372) -> Result<S::Ok, S::Error> {
373 match d {
374 Some(decimal) => rust_decimal::serde::float::serialize(decimal, s),
375 None => s.serialize_none(),
376 }
377}
378
379pub fn deserialize_decimal_from_str<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
388where
389 D: Deserializer<'de>,
390{
391 let s = String::deserialize(deserializer)?;
392 Decimal::from_str(&s).map_err(D::Error::custom)
393}
394
395pub fn deserialize_decimal_or_zero<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
403where
404 D: Deserializer<'de>,
405{
406 let s: String = Deserialize::deserialize(deserializer)?;
407 if s.is_empty() || s == "0" {
408 Ok(Decimal::ZERO)
409 } else {
410 Decimal::from_str(&s).map_err(D::Error::custom)
411 }
412}
413
414pub fn deserialize_optional_decimal_str<'de, D>(
424 deserializer: D,
425) -> Result<Option<Decimal>, D::Error>
426where
427 D: Deserializer<'de>,
428{
429 let s: String = Deserialize::deserialize(deserializer)?;
430 if s.is_empty() || s == "0" {
431 Ok(None)
432 } else {
433 Decimal::from_str(&s).map(Some).map_err(D::Error::custom)
434 }
435}
436
437pub fn deserialize_optional_decimal_from_str<'de, D>(
446 deserializer: D,
447) -> Result<Option<Decimal>, D::Error>
448where
449 D: Deserializer<'de>,
450{
451 let opt = Option::<String>::deserialize(deserializer)?;
452 match opt {
453 Some(s) if !s.is_empty() => Decimal::from_str(&s).map(Some).map_err(D::Error::custom),
454 _ => Ok(None),
455 }
456}
457
458pub fn deserialize_optional_decimal_or_zero<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
466where
467 D: Deserializer<'de>,
468{
469 let opt: Option<String> = Deserialize::deserialize(deserializer)?;
470 match opt {
471 None => Ok(Decimal::ZERO),
472 Some(s) if s.is_empty() || s == "0" => Ok(Decimal::ZERO),
473 Some(s) => Decimal::from_str(&s).map_err(D::Error::custom),
474 }
475}
476
477pub fn deserialize_vec_decimal_from_str<'de, D>(deserializer: D) -> Result<Vec<Decimal>, D::Error>
483where
484 D: Deserializer<'de>,
485{
486 let strings = Vec::<String>::deserialize(deserializer)?;
487 strings
488 .into_iter()
489 .map(|s| Decimal::from_str(&s).map_err(D::Error::custom))
490 .collect()
491}
492
493pub fn serialize_decimal_as_str<S>(decimal: &Decimal, serializer: S) -> Result<S::Ok, S::Error>
499where
500 S: Serializer,
501{
502 serializer.serialize_str(&decimal.to_string())
503}
504
505pub fn serialize_optional_decimal_as_str<S>(
511 decimal: &Option<Decimal>,
512 serializer: S,
513) -> Result<S::Ok, S::Error>
514where
515 S: Serializer,
516{
517 match decimal {
518 Some(d) => serializer.serialize_str(&d.to_string()),
519 None => serializer.serialize_none(),
520 }
521}
522
523pub fn serialize_vec_decimal_as_str<S>(
529 decimals: &Vec<Decimal>,
530 serializer: S,
531) -> Result<S::Ok, S::Error>
532where
533 S: Serializer,
534{
535 let mut seq = serializer.serialize_seq(Some(decimals.len()))?;
536 for decimal in decimals {
537 seq.serialize_element(&decimal.to_string())?;
538 }
539 seq.end()
540}
541
542pub fn parse_decimal(s: &str) -> anyhow::Result<Decimal> {
548 Decimal::from_str(s).map_err(|e| anyhow::anyhow!("Failed to parse decimal from '{s}': {e}"))
549}
550
551pub fn parse_optional_decimal(s: &Option<String>) -> anyhow::Result<Option<Decimal>> {
557 match s {
558 None => Ok(None),
559 Some(s) if s.is_empty() => Ok(None),
560 Some(s) => parse_decimal(s).map(Some),
561 }
562}
563
564pub fn deserialize_empty_string_as_none<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
576where
577 D: Deserializer<'de>,
578{
579 let opt = Option::<String>::deserialize(deserializer)?;
580 Ok(opt.filter(|s| !s.is_empty()))
581}
582
583pub fn deserialize_empty_ustr_as_none<'de, D>(deserializer: D) -> Result<Option<Ustr>, D::Error>
589where
590 D: Deserializer<'de>,
591{
592 let opt = Option::<Ustr>::deserialize(deserializer)?;
593 Ok(opt.filter(|s| !s.is_empty()))
594}
595
596pub fn deserialize_string_to_u8<'de, D>(deserializer: D) -> Result<u8, D::Error>
604where
605 D: Deserializer<'de>,
606{
607 let s: String = Deserialize::deserialize(deserializer)?;
608 if s.is_empty() {
609 return Ok(0);
610 }
611 s.parse::<u8>().map_err(D::Error::custom)
612}
613
614pub fn deserialize_string_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
622where
623 D: Deserializer<'de>,
624{
625 let s = String::deserialize(deserializer)?;
626 if s.is_empty() {
627 Ok(0)
628 } else {
629 s.parse::<u64>().map_err(D::Error::custom)
630 }
631}
632
633pub fn deserialize_optional_string_to_u64<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
641where
642 D: Deserializer<'de>,
643{
644 let s: Option<String> = Option::deserialize(deserializer)?;
645 match s {
646 Some(s) if s.is_empty() => Ok(None),
647 Some(s) => s.parse().map(Some).map_err(D::Error::custom),
648 None => Ok(None),
649 }
650}
651
652#[cfg(test)]
653mod tests {
654 use rstest::*;
655 use rust_decimal::Decimal;
656 use rust_decimal_macros::dec;
657 use serde::{Deserialize, Serialize};
658 use ustr::Ustr;
659
660 use super::{
661 Serializable, deserialize_decimal, deserialize_decimal_from_str,
662 deserialize_decimal_or_zero, deserialize_empty_string_as_none,
663 deserialize_empty_ustr_as_none, deserialize_optional_decimal,
664 deserialize_optional_decimal_or_zero, deserialize_optional_decimal_str,
665 deserialize_optional_string_to_u64, deserialize_string_to_u8, deserialize_string_to_u64,
666 deserialize_vec_decimal_from_str, from_bool_as_u8,
667 msgpack::{FromMsgPack, ToMsgPack},
668 parse_decimal, parse_optional_decimal, serialize_decimal, serialize_decimal_as_str,
669 serialize_optional_decimal, serialize_optional_decimal_as_str,
670 serialize_vec_decimal_as_str,
671 };
672
673 #[derive(Deserialize)]
674 pub struct TestStruct {
675 #[serde(deserialize_with = "from_bool_as_u8")]
676 pub value: u8,
677 }
678
679 #[rstest]
680 #[case(r#"{"value": true}"#, 1)]
681 #[case(r#"{"value": false}"#, 0)]
682 fn test_deserialize_bool_as_u8_with_boolean(#[case] json_str: &str, #[case] expected: u8) {
683 let test_struct: TestStruct = serde_json::from_str(json_str).unwrap();
684 assert_eq!(test_struct.value, expected);
685 }
686
687 #[rstest]
688 #[case(r#"{"value": 1}"#, 1)]
689 #[case(r#"{"value": 0}"#, 0)]
690 fn test_deserialize_bool_as_u8_with_u64(#[case] json_str: &str, #[case] expected: u8) {
691 let test_struct: TestStruct = serde_json::from_str(json_str).unwrap();
692 assert_eq!(test_struct.value, expected);
693 }
694
695 #[rstest]
696 fn test_deserialize_bool_as_u8_with_invalid_integer() {
697 let json = r#"{"value": 2}"#;
699 let result: Result<TestStruct, _> = serde_json::from_str(json);
700 assert!(result.is_err());
701 }
702
703 #[derive(Serialize, Deserialize, PartialEq, Debug)]
704 struct SerializableTestStruct {
705 id: u32,
706 name: String,
707 value: f64,
708 }
709
710 impl Serializable for SerializableTestStruct {}
711
712 #[rstest]
713 fn test_serializable_json_roundtrip() {
714 let original = SerializableTestStruct {
715 id: 42,
716 name: "test".to_string(),
717 value: std::f64::consts::PI,
718 };
719
720 let json_bytes = original.to_json_bytes().unwrap();
721 let deserialized = SerializableTestStruct::from_json_bytes(&json_bytes).unwrap();
722
723 assert_eq!(original, deserialized);
724 }
725
726 #[rstest]
727 fn test_serializable_msgpack_roundtrip() {
728 let original = SerializableTestStruct {
729 id: 123,
730 name: "msgpack_test".to_string(),
731 value: std::f64::consts::E,
732 };
733
734 let msgpack_bytes = original.to_msgpack_bytes().unwrap();
735 let deserialized = SerializableTestStruct::from_msgpack_bytes(&msgpack_bytes).unwrap();
736
737 assert_eq!(original, deserialized);
738 }
739
740 #[rstest]
741 fn test_serializable_json_invalid_data() {
742 let invalid_json = b"invalid json data";
743 let result = SerializableTestStruct::from_json_bytes(invalid_json);
744 assert!(result.is_err());
745 }
746
747 #[rstest]
748 fn test_serializable_msgpack_invalid_data() {
749 let invalid_msgpack = b"invalid msgpack data";
750 let result = SerializableTestStruct::from_msgpack_bytes(invalid_msgpack);
751 assert!(result.is_err());
752 }
753
754 #[rstest]
755 fn test_serializable_json_empty_values() {
756 let test_struct = SerializableTestStruct {
757 id: 0,
758 name: String::new(),
759 value: 0.0,
760 };
761
762 let json_bytes = test_struct.to_json_bytes().unwrap();
763 let deserialized = SerializableTestStruct::from_json_bytes(&json_bytes).unwrap();
764
765 assert_eq!(test_struct, deserialized);
766 }
767
768 #[rstest]
769 fn test_serializable_msgpack_empty_values() {
770 let test_struct = SerializableTestStruct {
771 id: 0,
772 name: String::new(),
773 value: 0.0,
774 };
775
776 let msgpack_bytes = test_struct.to_msgpack_bytes().unwrap();
777 let deserialized = SerializableTestStruct::from_msgpack_bytes(&msgpack_bytes).unwrap();
778
779 assert_eq!(test_struct, deserialized);
780 }
781
782 #[derive(Deserialize)]
783 struct TestOptionalDecimalStr {
784 #[serde(deserialize_with = "deserialize_optional_decimal_str")]
785 value: Option<Decimal>,
786 }
787
788 #[derive(Deserialize)]
789 struct TestDecimalOrZero {
790 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
791 value: Decimal,
792 }
793
794 #[derive(Deserialize)]
795 struct TestOptionalDecimalOrZero {
796 #[serde(deserialize_with = "deserialize_optional_decimal_or_zero")]
797 value: Decimal,
798 }
799
800 #[derive(Serialize, Deserialize, PartialEq, Debug)]
801 struct TestDecimalRoundtrip {
802 #[serde(
803 serialize_with = "serialize_decimal_as_str",
804 deserialize_with = "deserialize_decimal_from_str"
805 )]
806 value: Decimal,
807 #[serde(
808 serialize_with = "serialize_optional_decimal_as_str",
809 deserialize_with = "super::deserialize_optional_decimal_from_str"
810 )]
811 optional_value: Option<Decimal>,
812 }
813
814 #[rstest]
815 #[case(r#"{"value":"123.45"}"#, Some(dec!(123.45)))]
816 #[case(r#"{"value":"0"}"#, None)]
817 #[case(r#"{"value":""}"#, None)]
818 fn test_deserialize_optional_decimal_str(
819 #[case] json: &str,
820 #[case] expected: Option<Decimal>,
821 ) {
822 let result: TestOptionalDecimalStr = serde_json::from_str(json).unwrap();
823 assert_eq!(result.value, expected);
824 }
825
826 #[rstest]
827 #[case(r#"{"value":"123.45"}"#, dec!(123.45))]
828 #[case(r#"{"value":"0"}"#, Decimal::ZERO)]
829 #[case(r#"{"value":""}"#, Decimal::ZERO)]
830 fn test_deserialize_decimal_or_zero(#[case] json: &str, #[case] expected: Decimal) {
831 let result: TestDecimalOrZero = serde_json::from_str(json).unwrap();
832 assert_eq!(result.value, expected);
833 }
834
835 #[rstest]
836 #[case(r#"{"value":"123.45"}"#, dec!(123.45))]
837 #[case(r#"{"value":"0"}"#, Decimal::ZERO)]
838 #[case(r#"{"value":null}"#, Decimal::ZERO)]
839 fn test_deserialize_optional_decimal_or_zero(#[case] json: &str, #[case] expected: Decimal) {
840 let result: TestOptionalDecimalOrZero = serde_json::from_str(json).unwrap();
841 assert_eq!(result.value, expected);
842 }
843
844 #[rstest]
845 fn test_decimal_serialization_roundtrip() {
846 let original = TestDecimalRoundtrip {
847 value: dec!(123.456789012345678),
848 optional_value: Some(dec!(0.000000001)),
849 };
850
851 let json = serde_json::to_string(&original).unwrap();
852
853 assert!(json.contains("\"123.456789012345678\""));
855 assert!(json.contains("\"0.000000001\""));
856
857 let deserialized: TestDecimalRoundtrip = serde_json::from_str(&json).unwrap();
858 assert_eq!(original.value, deserialized.value);
859 assert_eq!(original.optional_value, deserialized.optional_value);
860 }
861
862 #[rstest]
863 fn test_decimal_optional_none_handling() {
864 let test_struct = TestDecimalRoundtrip {
865 value: dec!(42.0),
866 optional_value: None,
867 };
868
869 let json = serde_json::to_string(&test_struct).unwrap();
870 assert!(json.contains("null"));
871
872 let parsed: TestDecimalRoundtrip = serde_json::from_str(&json).unwrap();
873 assert_eq!(test_struct.value, parsed.value);
874 assert_eq!(None, parsed.optional_value);
875 }
876
877 #[derive(Deserialize)]
878 struct TestEmptyStringAsNone {
879 #[serde(deserialize_with = "deserialize_empty_string_as_none")]
880 value: Option<String>,
881 }
882
883 #[rstest]
884 #[case(r#"{"value":"hello"}"#, Some("hello".to_string()))]
885 #[case(r#"{"value":""}"#, None)]
886 #[case(r#"{"value":null}"#, None)]
887 fn test_deserialize_empty_string_as_none(#[case] json: &str, #[case] expected: Option<String>) {
888 let result: TestEmptyStringAsNone = serde_json::from_str(json).unwrap();
889 assert_eq!(result.value, expected);
890 }
891
892 #[derive(Deserialize)]
893 struct TestEmptyUstrAsNone {
894 #[serde(deserialize_with = "deserialize_empty_ustr_as_none")]
895 value: Option<Ustr>,
896 }
897
898 #[rstest]
899 #[case(r#"{"value":"hello"}"#, Some(Ustr::from("hello")))]
900 #[case(r#"{"value":""}"#, None)]
901 #[case(r#"{"value":null}"#, None)]
902 fn test_deserialize_empty_ustr_as_none(#[case] json: &str, #[case] expected: Option<Ustr>) {
903 let result: TestEmptyUstrAsNone = serde_json::from_str(json).unwrap();
904 assert_eq!(result.value, expected);
905 }
906
907 #[derive(Serialize, Deserialize, PartialEq, Debug)]
908 struct TestVecDecimal {
909 #[serde(
910 serialize_with = "serialize_vec_decimal_as_str",
911 deserialize_with = "deserialize_vec_decimal_from_str"
912 )]
913 values: Vec<Decimal>,
914 }
915
916 #[rstest]
917 fn test_vec_decimal_roundtrip() {
918 let original = TestVecDecimal {
919 values: vec![dec!(1.5), dec!(2.25), dec!(100.001)],
920 };
921
922 let json = serde_json::to_string(&original).unwrap();
923 assert!(json.contains("[\"1.5\",\"2.25\",\"100.001\"]"));
924
925 let parsed: TestVecDecimal = serde_json::from_str(&json).unwrap();
926 assert_eq!(original.values, parsed.values);
927 }
928
929 #[rstest]
930 fn test_vec_decimal_empty() {
931 let original = TestVecDecimal { values: vec![] };
932
933 let json = serde_json::to_string(&original).unwrap();
934 let parsed: TestVecDecimal = serde_json::from_str(&json).unwrap();
935 assert_eq!(original.values, parsed.values);
936 }
937
938 #[derive(Deserialize)]
939 struct TestStringToU8 {
940 #[serde(deserialize_with = "deserialize_string_to_u8")]
941 value: u8,
942 }
943
944 #[rstest]
945 #[case(r#"{"value":"42"}"#, 42)]
946 #[case(r#"{"value":"0"}"#, 0)]
947 #[case(r#"{"value":""}"#, 0)]
948 fn test_deserialize_string_to_u8(#[case] json: &str, #[case] expected: u8) {
949 let result: TestStringToU8 = serde_json::from_str(json).unwrap();
950 assert_eq!(result.value, expected);
951 }
952
953 #[derive(Deserialize)]
954 struct TestStringToU64 {
955 #[serde(deserialize_with = "deserialize_string_to_u64")]
956 value: u64,
957 }
958
959 #[rstest]
960 #[case(r#"{"value":"12345678901234"}"#, 12345678901234)]
961 #[case(r#"{"value":"0"}"#, 0)]
962 #[case(r#"{"value":""}"#, 0)]
963 fn test_deserialize_string_to_u64(#[case] json: &str, #[case] expected: u64) {
964 let result: TestStringToU64 = serde_json::from_str(json).unwrap();
965 assert_eq!(result.value, expected);
966 }
967
968 #[derive(Deserialize)]
969 struct TestOptionalStringToU64 {
970 #[serde(deserialize_with = "deserialize_optional_string_to_u64")]
971 value: Option<u64>,
972 }
973
974 #[rstest]
975 #[case(r#"{"value":"12345678901234"}"#, Some(12345678901234))]
976 #[case(r#"{"value":"0"}"#, Some(0))]
977 #[case(r#"{"value":""}"#, None)]
978 #[case(r#"{"value":null}"#, None)]
979 fn test_deserialize_optional_string_to_u64(#[case] json: &str, #[case] expected: Option<u64>) {
980 let result: TestOptionalStringToU64 = serde_json::from_str(json).unwrap();
981 assert_eq!(result.value, expected);
982 }
983
984 #[rstest]
985 #[case("123.45", dec!(123.45))]
986 #[case("0", Decimal::ZERO)]
987 #[case("0.0", Decimal::ZERO)]
988 fn test_parse_decimal(#[case] input: &str, #[case] expected: Decimal) {
989 let result = parse_decimal(input).unwrap();
990 assert_eq!(result, expected);
991 }
992
993 #[rstest]
994 fn test_parse_decimal_invalid() {
995 assert!(parse_decimal("invalid").is_err());
996 assert!(parse_decimal("").is_err());
997 }
998
999 #[rstest]
1000 #[case(&Some("123.45".to_string()), Some(dec!(123.45)))]
1001 #[case(&Some("0".to_string()), Some(Decimal::ZERO))]
1002 #[case(&Some(String::new()), None)]
1003 #[case(&None, None)]
1004 fn test_parse_optional_decimal(
1005 #[case] input: &Option<String>,
1006 #[case] expected: Option<Decimal>,
1007 ) {
1008 let result = parse_optional_decimal(input).unwrap();
1009 assert_eq!(result, expected);
1010 }
1011
1012 #[derive(Debug, Serialize, Deserialize, PartialEq)]
1015 struct TestFlexibleDecimal {
1016 #[serde(
1017 serialize_with = "serialize_decimal",
1018 deserialize_with = "deserialize_decimal"
1019 )]
1020 value: Decimal,
1021 #[serde(
1022 serialize_with = "serialize_optional_decimal",
1023 deserialize_with = "deserialize_optional_decimal"
1024 )]
1025 optional_value: Option<Decimal>,
1026 }
1027
1028 #[rstest]
1029 #[case(r#"{"value": 123.456, "optional_value": 789.012}"#, dec!(123.456), Some(dec!(789.012)))]
1030 #[case(r#"{"value": "123.456", "optional_value": "789.012"}"#, dec!(123.456), Some(dec!(789.012)))]
1031 #[case(r#"{"value": 100, "optional_value": null}"#, dec!(100), None)]
1032 #[case(r#"{"value": null, "optional_value": null}"#, Decimal::ZERO, None)]
1033 fn test_deserialize_flexible_decimal(
1034 #[case] json: &str,
1035 #[case] expected_value: Decimal,
1036 #[case] expected_optional: Option<Decimal>,
1037 ) {
1038 let result: TestFlexibleDecimal = serde_json::from_str(json).unwrap();
1039 assert_eq!(result.value, expected_value);
1040 assert_eq!(result.optional_value, expected_optional);
1041 }
1042
1043 #[rstest]
1044 fn test_flexible_decimal_roundtrip() {
1045 let original = TestFlexibleDecimal {
1046 value: dec!(123.456),
1047 optional_value: Some(dec!(789.012)),
1048 };
1049
1050 let json = serde_json::to_string(&original).unwrap();
1051 let deserialized: TestFlexibleDecimal = serde_json::from_str(&json).unwrap();
1052
1053 assert_eq!(original.value, deserialized.value);
1054 assert_eq!(original.optional_value, deserialized.optional_value);
1055 }
1056
1057 #[rstest]
1058 fn test_flexible_decimal_scientific_notation() {
1059 let json = r#"{"value": 0.00000001, "optional_value": 12345678.12345}"#;
1063 let parsed: TestFlexibleDecimal = serde_json::from_str(json).unwrap();
1064 assert_eq!(parsed.value, dec!(0.00000001));
1065 assert_eq!(parsed.optional_value, Some(dec!(12345678.12345)));
1066 }
1067
1068 #[rstest]
1069 fn test_flexible_decimal_empty_string_optional() {
1070 let json = r#"{"value": 100, "optional_value": ""}"#;
1071 let parsed: TestFlexibleDecimal = serde_json::from_str(json).unwrap();
1072 assert_eq!(parsed.value, dec!(100));
1073 assert_eq!(parsed.optional_value, None);
1074 }
1075
1076 #[derive(Debug, Deserialize)]
1079 struct TestDecimalOnly {
1080 #[serde(deserialize_with = "deserialize_decimal")]
1081 value: Decimal,
1082 }
1083
1084 #[rstest]
1085 #[case(r#"{"value": "1.5e-8"}"#, dec!(0.000000015))]
1086 #[case(r#"{"value": "1E10"}"#, dec!(10000000000))]
1087 #[case(r#"{"value": "-1.23e5"}"#, dec!(-123000))]
1088 fn test_deserialize_decimal_scientific_string(#[case] json: &str, #[case] expected: Decimal) {
1089 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1090 assert_eq!(result.value, expected);
1091 }
1092
1093 #[rstest]
1094 #[case(r#"{"value": 9223372036854775807}"#, dec!(9223372036854775807))] #[case(r#"{"value": -9223372036854775808}"#, dec!(-9223372036854775808))] #[case(r#"{"value": 0}"#, Decimal::ZERO)]
1097 fn test_deserialize_decimal_large_integers(#[case] json: &str, #[case] expected: Decimal) {
1098 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1099 assert_eq!(result.value, expected);
1100 }
1101
1102 #[rstest]
1103 #[case(r#"{"value": "-123.456789"}"#, dec!(-123.456789))]
1104 #[case(r#"{"value": -999.99}"#, dec!(-999.99))]
1105 fn test_deserialize_decimal_negative(#[case] json: &str, #[case] expected: Decimal) {
1106 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1107 assert_eq!(result.value, expected);
1108 }
1109
1110 #[rstest]
1111 #[case(r#"{"value": "123456789.123456789012345678"}"#)] fn test_deserialize_decimal_high_precision(#[case] json: &str) {
1113 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1114 assert_eq!(result.value, dec!(123456789.123456789012345678));
1115 }
1116
1117 #[derive(Debug, Deserialize)]
1118 struct TestOptionalDecimalOnly {
1119 #[serde(deserialize_with = "deserialize_optional_decimal")]
1120 value: Option<Decimal>,
1121 }
1122
1123 #[rstest]
1124 #[case(r#"{"value": "1.5e-8"}"#, Some(dec!(0.000000015)))]
1125 #[case(r#"{"value": null}"#, None)]
1126 #[case(r#"{"value": ""}"#, None)]
1127 #[case(r#"{"value": 42}"#, Some(dec!(42)))]
1128 #[case(r#"{"value": -100.5}"#, Some(dec!(-100.5)))]
1129 fn test_deserialize_optional_decimal_various(
1130 #[case] json: &str,
1131 #[case] expected: Option<Decimal>,
1132 ) {
1133 let result: TestOptionalDecimalOnly = serde_json::from_str(json).unwrap();
1134 assert_eq!(result.value, expected);
1135 }
1136}