serde_decimal/
double_option_float.rs

1//! Combination of the serde rules from [rust_decimal::serde::float] and `serde_with::rust::double_option`.
2//!
3//! This is necessary because it is not possible to apply multiple `#[serde(with = ...)]` attributes:
4//! * `#[serde(with = "serde_with::rust::double_option")]`
5//! * `#[serde(with = "rust_decimal::serde::float")]`
6
7use serde_core::{Deserializer, Serializer};
8
9/// Double-option float-form decimal deserializer.
10///
11/// See [module docs](self) for more.
12pub fn deserialize<'de, D>(
13    deserializer: D,
14) -> Result<Option<Option<rust_decimal::Decimal>>, D::Error>
15where
16    D: Deserializer<'de>,
17{
18    crate::nullable_float::deserialize(deserializer).map(Some)
19}
20
21/// Double-option float-form decimal serializer.
22///
23/// See [module docs](self) for more.
24pub fn serialize<S>(
25    value: &Option<Option<rust_decimal::Decimal>>,
26    serializer: S,
27) -> Result<S::Ok, S::Error>
28where
29    S: Serializer,
30{
31    match value {
32        None => serializer.serialize_unit(),
33        Some(v) => crate::nullable_float::serialize(v, serializer),
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use rust_decimal_macros::dec;
40
41    #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
42    struct Foo {
43        #[serde(skip_serializing_if = "Option::is_none")]
44        #[serde(default)]
45        #[serde(with = "crate::double_option_float")]
46        foo: Option<Option<rust_decimal::Decimal>>,
47    }
48
49    #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
50    struct Bar {
51        #[serde(flatten)]
52        foo: Foo,
53    }
54
55    #[test]
56    fn foo_serialize_some_some() {
57        let serialized = serde_json::to_string(&Foo {
58            foo: Some(Some(dec!(0.1))),
59        })
60        .unwrap();
61        assert_eq!(serialized, r#"{"foo":0.1}"#);
62    }
63
64    #[test]
65    fn foo_serialize_some_none() {
66        let serialized = serde_json::to_string(&Foo { foo: Some(None) }).unwrap();
67        assert_eq!(serialized, r#"{"foo":null}"#);
68    }
69
70    #[test]
71    fn foo_serialize_none() {
72        let serialized = serde_json::to_string(&Foo { foo: None }).unwrap();
73        assert_eq!(serialized, r#"{}"#);
74    }
75
76    #[test]
77    fn foo_deserialize_value() {
78        let deserialized: Foo = serde_json::from_str(r#"{"foo":0.1}"#).unwrap();
79        assert!(matches!(deserialized, Foo { foo: Some(Some(_)) }));
80    }
81
82    #[test]
83    fn foo_deserialize_null() {
84        let deserialized: Foo = serde_json::from_str(r#"{"foo":null}"#).unwrap();
85        assert!(matches!(deserialized, Foo { foo: Some(None) }));
86    }
87
88    #[test]
89    fn foo_deserialize_missing() {
90        let deserialized: Foo = serde_json::from_str(r#"{}"#).unwrap();
91        assert!(matches!(deserialized, Foo { foo: None }));
92    }
93
94    #[test]
95    fn bar_serialize_some_some() {
96        let serialized = serde_json::to_string(&Bar {
97            foo: Foo {
98                foo: Some(Some(dec!(0.1))),
99            },
100        })
101        .unwrap();
102        assert_eq!(serialized, r#"{"foo":0.1}"#);
103    }
104
105    #[test]
106    fn bar_serialize_some_none() {
107        let serialized = serde_json::to_string(&Bar {
108            foo: Foo { foo: Some(None) },
109        })
110        .unwrap();
111        assert_eq!(serialized, r#"{"foo":null}"#);
112    }
113
114    #[test]
115    fn bar_serialize_none() {
116        let serialized = serde_json::to_string(&Bar {
117            foo: Foo { foo: None },
118        })
119        .unwrap();
120        assert_eq!(serialized, r#"{}"#);
121    }
122
123    #[test]
124    fn bar_deserialize_value() {
125        let deserialized: Bar = serde_json::from_str(r#"{"foo":0.1}"#).unwrap();
126        assert!(matches!(
127            deserialized,
128            Bar {
129                foo: Foo { foo: Some(Some(_)) }
130            }
131        ));
132    }
133
134    #[test]
135    fn bar_deserialize_null() {
136        let deserialized: Bar = serde_json::from_str(r#"{"foo":null}"#).unwrap();
137        assert!(matches!(
138            deserialized,
139            Bar {
140                foo: Foo { foo: Some(None) }
141            }
142        ));
143    }
144
145    #[test]
146    fn bar_deserialize_missing() {
147        let deserialized: Bar = serde_json::from_str(r#"{}"#).unwrap();
148        assert!(matches!(
149            deserialized,
150            Bar {
151                foo: Foo { foo: None }
152            }
153        ));
154    }
155}