batch_mode_process_response/
deserialize_json_with_optional_fields_wrapper.rs1crate::ix!();
2
3#[instrument(level = "trace", skip(json_value))]
9pub fn deserialize_json_with_optional_fields_wrapper<T>(
10 json_value: &serde_json::Value,
11) -> Result<T, serde_json::Error>
12where
13 T: DeserializeOwned,
14{
15 trace!("Attempting direct deserialization into target struct …");
16 match serde_json::from_value::<T>(json_value.clone()) {
17 Ok(t) => {
18 debug!("Direct deserialization succeeded.");
19 return Ok(t);
20 }
21 Err(e_direct) => {
22 debug!("Direct deserialization failed: {:?}", e_direct);
23
24 trace!("Checking for `fields` wrapper …");
25 if let Some(inner) = json_value.get("fields") {
26 trace!("`fields` wrapper found — trying inner value deserialization …");
27 match serde_json::from_value::<T>(inner.clone()) {
28 Ok(t) => {
29 info!("Deserialization succeeded after unwrapping `fields`.");
30 Ok(t)
31 }
32 Err(e_inner) => {
33 error!(
34 "Deserialization failed after unwrapping `fields`: {:?}",
35 e_inner
36 );
37 Err(e_inner)
39 }
40 }
41 } else {
42 error!("No `fields` wrapper present; cannot recover.");
43 Err(e_direct)
45 }
46 }
47 }
48}
49
50#[cfg(test)]
51mod deserialize_json_with_optional_fields_wrapper_tests {
52 use super::*;
53
54 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59 struct TestStruct {
60 crate_name: String,
61 answer: u32,
62 }
63
64 fn json_val(s: &str) -> serde_json::Value {
67 serde_json::from_str::<serde_json::Value>(s).expect("JSON must parse for test setup")
68 }
69
70 #[traced_test]
71 fn direct_deserialization_succeeds() {
72 trace!("===== BEGIN TEST: direct_deserialization_succeeds =====");
73
74 let input = json_val(r#"{ "crate_name": "foo", "answer": 42 }"#);
76
77 let result = deserialize_json_with_optional_fields_wrapper::<TestStruct>(&input);
78
79 assert!(
80 result.is_ok(),
81 "Direct deserialization should succeed when keys are at the top level"
82 );
83 assert_eq!(
84 result.unwrap(),
85 TestStruct {
86 crate_name: "foo".into(),
87 answer: 42
88 }
89 );
90
91 trace!("===== END TEST: direct_deserialization_succeeds =====");
92 }
93
94 #[traced_test]
95 fn fields_wrapper_deserialization_succeeds() {
96 trace!("===== BEGIN TEST: fields_wrapper_deserialization_succeeds =====");
97
98 let input = json_val(
100 r#"
101 {
102 "struct_name":"Whatever",
103 "fields": {
104 "crate_name":"bar",
105 "answer":1337
106 }
107 }"#,
108 );
109
110 let result = deserialize_json_with_optional_fields_wrapper::<TestStruct>(&input);
111
112 assert!(
113 result.is_ok(),
114 "`fields` wrapper should be detected and unwrapped automatically"
115 );
116 assert_eq!(
117 result.unwrap(),
118 TestStruct {
119 crate_name: "bar".into(),
120 answer: 1337
121 }
122 );
123
124 trace!("===== END TEST: fields_wrapper_deserialization_succeeds =====");
125 }
126
127 #[traced_test]
128 fn fails_when_neither_top_level_nor_wrapper_matches() {
129 trace!("===== BEGIN TEST: fails_when_neither_top_level_nor_wrapper_matches =====");
130
131 let input = json_val(r#"{ "not_it": true }"#);
133
134 let result = deserialize_json_with_optional_fields_wrapper::<TestStruct>(&input);
135
136 assert!(
137 result.is_err(),
138 "Should fail because required keys are missing and no wrapper is present"
139 );
140
141 trace!("===== END TEST: fails_when_neither_top_level_nor_wrapper_matches =====");
142 }
143
144 #[traced_test]
145 fn fails_when_wrapper_present_but_incorrect() {
146 trace!("===== BEGIN TEST: fails_when_wrapper_present_but_incorrect =====");
147
148 let input = json_val(
150 r#"
151 {
152 "fields": {
153 "wrong":"shape"
154 }
155 }"#,
156 );
157
158 let result = deserialize_json_with_optional_fields_wrapper::<TestStruct>(&input);
159
160 assert!(
161 result.is_err(),
162 "Should fail because inner object lacks required keys"
163 );
164
165 trace!("===== END TEST: fails_when_wrapper_present_but_incorrect =====");
166 }
167
168 #[traced_test]
169 fn succeeds_with_additional_unrelated_top_level_keys() {
170 trace!("===== BEGIN TEST: succeeds_with_additional_unrelated_top_level_keys =====");
171
172 let input = json_val(
174 r#"
175 {
176 "crate_name": "baz",
177 "answer": 7,
178 "extraneous": "ignored"
179 }"#,
180 );
181
182 let result = deserialize_json_with_optional_fields_wrapper::<TestStruct>(&input);
183
184 assert!(
185 result.is_ok(),
186 "Serde should ignore unrelated top‑level keys when `deny_unknown_fields` is not used"
187 );
188 assert_eq!(
189 result.unwrap(),
190 TestStruct {
191 crate_name: "baz".into(),
192 answer: 7
193 }
194 );
195
196 trace!("===== END TEST: succeeds_with_additional_unrelated_top_level_keys =====");
197 }
198}