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