plexus_core/
serde_helpers.rs1use serde::{Deserialize, Deserializer};
6
7pub fn deserialize_null_as_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
28where
29 T: Deserialize<'de>,
30 D: Deserializer<'de>,
31{
32 let opt = Option::<T>::deserialize(deserializer)?;
35 Ok(opt)
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41 use serde::Deserialize;
42
43 #[derive(Debug, Deserialize, PartialEq)]
44 struct TestStruct {
45 #[serde(default, deserialize_with = "deserialize_null_as_none")]
46 optional_string: Option<String>,
47
48 #[serde(default, deserialize_with = "deserialize_null_as_none")]
49 optional_number: Option<i32>,
50
51 required: String,
52 }
53
54 #[test]
55 fn test_missing_field() {
56 let json = r#"{"required": "test"}"#;
57 let parsed: TestStruct = serde_json::from_str(json).unwrap();
58 assert_eq!(parsed.optional_string, None);
59 assert_eq!(parsed.optional_number, None);
60 assert_eq!(parsed.required, "test");
61 }
62
63 #[test]
64 fn test_explicit_null() {
65 let json = r#"{"optional_string": null, "optional_number": null, "required": "test"}"#;
66 let parsed: TestStruct = serde_json::from_str(json).unwrap();
67 assert_eq!(parsed.optional_string, None);
68 assert_eq!(parsed.optional_number, None);
69 assert_eq!(parsed.required, "test");
70 }
71
72 #[test]
73 fn test_present_value() {
74 let json = r#"{"optional_string": "hello", "optional_number": 42, "required": "test"}"#;
75 let parsed: TestStruct = serde_json::from_str(json).unwrap();
76 assert_eq!(parsed.optional_string, Some("hello".to_string()));
77 assert_eq!(parsed.optional_number, Some(42));
78 assert_eq!(parsed.required, "test");
79 }
80
81 #[test]
82 fn test_mixed_null_and_present() {
83 let json = r#"{"optional_string": null, "optional_number": 42, "required": "test"}"#;
84 let parsed: TestStruct = serde_json::from_str(json).unwrap();
85 assert_eq!(parsed.optional_string, None);
86 assert_eq!(parsed.optional_number, Some(42));
87 assert_eq!(parsed.required, "test");
88 }
89
90 #[derive(Debug, Deserialize, PartialEq)]
92 struct InnerType {
93 value: String,
94 }
95
96 #[derive(Debug, Deserialize, PartialEq)]
97 struct TestWithComplexInner {
98 #[serde(default, deserialize_with = "deserialize_null_as_none")]
99 complex: Option<InnerType>,
100 }
101
102 #[test]
103 fn test_complex_inner_missing() {
104 let json = r#"{}"#;
105 let parsed: TestWithComplexInner = serde_json::from_str(json).unwrap();
106 assert_eq!(parsed.complex, None);
107 }
108
109 #[test]
110 fn test_complex_inner_null() {
111 let json = r#"{"complex": null}"#;
112 let parsed: TestWithComplexInner = serde_json::from_str(json).unwrap();
113 assert_eq!(parsed.complex, None);
114 }
115
116 #[test]
117 fn test_complex_inner_present() {
118 let json = r#"{"complex": {"value": "hello"}}"#;
119 let parsed: TestWithComplexInner = serde_json::from_str(json).unwrap();
120 assert_eq!(
121 parsed.complex,
122 Some(InnerType {
123 value: "hello".to_string()
124 })
125 );
126 }
127}