1use serde::{Deserialize, Deserializer};
2
3pub fn deserialize_null_as_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
4where
5 T: Default + Deserialize<'de>,
6 D: Deserializer<'de>,
7{
8 Option::deserialize(deserializer).map(Option::unwrap_or_default)
9}
10
11#[cfg(test)]
12mod tests {
13 use std::collections::HashMap;
14
15 use serde::Deserialize;
16
17 #[derive(Debug, Deserialize, PartialEq, Eq)]
18 struct TestData {
19 #[serde(deserialize_with = "crate::deserialize_null_as_default")]
20 pub string: String,
21
22 #[serde(deserialize_with = "crate::deserialize_null_as_default")]
23 pub number: i64,
24
25 #[serde(deserialize_with = "crate::deserialize_null_as_default")]
26 pub boolean: bool,
27
28 #[serde(deserialize_with = "crate::deserialize_null_as_default")]
29 pub list: Vec<String>,
30
31 #[serde(deserialize_with = "crate::deserialize_null_as_default")]
32 pub map: std::collections::HashMap<String, i64>,
33 }
34
35 #[test]
36 pub fn deserialize_null_as_default_deserializes_value() {
37 let input = r#"{"string":"data","number":42,"boolean":true,"list":["a","b","c"],"map":{"a":1,"b":2,"c":3}}"#;
38
39 let value = serde_json::from_str::<TestData>(input).unwrap();
40
41 assert_eq!(
42 value,
43 TestData {
44 string: "data".into(),
45 number: 42,
46 boolean: true,
47 list: vec!["a".into(), "b".into(), "c".into()],
48 map: HashMap::from([("a".into(), 1), ("b".into(), 2), ("c".into(), 3)])
49 }
50 )
51 }
52
53 #[test]
54 pub fn deserialize_null_as_default_deserializes_null_as_default() {
55 let input = r#"{"string":null,"number":null,"boolean":null,"list":null,"map":null}"#;
56
57 let value = serde_json::from_str::<TestData>(input).unwrap();
58
59 assert_eq!(
60 value,
61 TestData {
62 string: "".into(),
63 number: 0,
64 boolean: false,
65 list: vec![],
66 map: HashMap::new()
67 }
68 )
69 }
70}