serde_decimal/
nullable_arbitrary_precision.rs1use std::fmt;
4
5use rust_decimal::Decimal;
6use serde_core::{de, Deserialize, Deserializer, Serializer};
7
8struct OptionDecimalVisitor;
9
10impl<'de> de::Visitor<'de> for OptionDecimalVisitor {
11 type Value = Option<Decimal>;
12
13 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
14 formatter.write_str("a Decimal type representing a fixed-point number")
15 }
16
17 fn visit_none<E>(self) -> Result<Option<Decimal>, E>
18 where
19 E: de::Error,
20 {
21 Ok(None)
22 }
23
24 fn visit_some<D>(self, d: D) -> Result<Option<Decimal>, D::Error>
25 where
26 D: Deserializer<'de>,
27 {
28 <Decimal as Deserialize>::deserialize(d).map(Some)
29 }
30
31 fn visit_unit<E>(self) -> Result<Self::Value, E>
32 where
33 E: de::Error,
34 {
35 Ok(None)
36 }
37}
38
39pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<rust_decimal::Decimal>, D::Error>
43where
44 D: Deserializer<'de>,
45{
46 deserializer.deserialize_option(OptionDecimalVisitor)
47}
48
49pub fn serialize<S>(value: &Option<rust_decimal::Decimal>, serializer: S) -> Result<S::Ok, S::Error>
53where
54 S: Serializer,
55{
56 rust_decimal::serde::arbitrary_precision_option::serialize(value, serializer)
57}
58
59#[cfg(test)]
60mod tests {
61 use rust_decimal_macros::dec;
62
63 #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
64 struct Foo {
65 #[serde(with = "crate::nullable_arbitrary_precision")]
66 foo: Option<rust_decimal::Decimal>,
67 }
68
69 #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
70 struct Bar {
71 #[serde(flatten)]
72 foo: Foo,
73 }
74
75 #[test]
76 fn foo_serialize_some() {
77 let serialized = serde_json::to_string(&Foo {
78 foo: Some(dec!(0.1)),
79 })
80 .unwrap();
81 assert_eq!(serialized, r#"{"foo":0.1}"#);
82 }
83
84 #[test]
85 fn foo_serialize_none() {
86 let serialized = serde_json::to_string(&Foo { foo: None }).unwrap();
87 assert_eq!(serialized, r#"{"foo":null}"#);
88 }
89
90 #[test]
91 fn foo_deserialize_some() {
92 let deserialized: Foo = serde_json::from_str(r#"{"foo":0.1}"#).unwrap();
93 assert!(matches!(deserialized, Foo { foo: Some(_) }));
94 }
95
96 #[test]
97 #[should_panic]
98 fn foo_deserialize_missing() {
99 serde_json::from_str::<Foo>(r#"{}"#).unwrap();
100 }
101
102 #[test]
103 fn foo_deserialize_null() {
104 let deserialized: Foo = serde_json::from_str(r#"{"foo":null}"#).unwrap();
105 assert!(matches!(deserialized, Foo { foo: None }));
106 }
107
108 #[test]
109 fn bar_serialize_some() {
110 let serialized = serde_json::to_string(&Bar {
111 foo: Foo {
112 foo: Some(dec!(0.1)),
113 },
114 })
115 .unwrap();
116 assert_eq!(serialized, r#"{"foo":0.1}"#);
117 }
118
119 #[test]
120 fn bar_serialize_none() {
121 let serialized = serde_json::to_string(&Bar {
122 foo: Foo { foo: None },
123 })
124 .unwrap();
125 assert_eq!(serialized, r#"{"foo":null}"#);
126 }
127
128 #[test]
129 fn bar_deserialize_some() {
130 let deserialized: Bar = serde_json::from_str(r#"{"foo":0.1}"#).unwrap();
131 assert!(matches!(
132 deserialized,
133 Bar {
134 foo: Foo { foo: Some(_) }
135 }
136 ));
137 }
138
139 #[test]
140 #[should_panic]
141 fn bar_deserialize_missing() {
142 serde_json::from_str::<Bar>(r#"{}"#).unwrap();
143 }
144
145 #[test]
146 fn bar_deserialize_null() {
147 let deserialized: Bar = serde_json::from_str(r#"{"foo":null}"#).unwrap();
148 assert!(matches!(
149 deserialized,
150 Bar {
151 foo: Foo { foo: None }
152 }
153 ));
154 }
155}