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