json_result/
struct.rs

1use std::ops::{Deref, DerefMut};
2
3use serde::de::{DeserializeOwned, Error as DeError};
4use serde::{Deserialize, Serialize};
5
6/// JsonResult<T, E>
7///
8/// A small serde-compatible wrapper that serializes either the Ok(T) value or the Err(E) value,
9/// and deserializes by attempting to parse the payload as `T` first and `E` second.
10///
11/// This is useful when a response payload may be either a success object or an error object
12/// and you want to round-trip that semantics with serde.
13///
14/// # Examples
15///
16/// Serialize an Ok value:
17/// ```rust
18/// use json_result::r#struct::JsonResult;
19/// let jr = JsonResult::<i32, &str>(Ok(100));
20/// let s = serde_json::to_string(&jr).unwrap();
21/// assert_eq!(s, "100");
22/// ```
23///
24/// Deserialize into JsonResult:
25/// ```rust
26/// use json_result::r#struct::JsonResult;
27/// let jr: JsonResult<i32, String> = serde_json::from_str("42").unwrap();
28/// match jr.0 {
29///     Ok(v) => assert_eq!(v, 42),
30///     Err(_) => panic!("expected Ok"),
31/// }
32/// ```
33#[derive(Debug)]
34pub struct JsonResult<T, E>(pub Result<T, E>);
35
36impl<T, E> Serialize for JsonResult<T, E>
37where
38    T: Serialize,
39    E: Serialize,
40{
41    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42    where
43        S: serde::Serializer,
44    {
45        match &self.0 {
46            Ok(v) => v.serialize(serializer),
47            Err(e) => e.serialize(serializer),
48        }
49    }
50}
51
52impl<'de, T, E> Deserialize<'de> for JsonResult<T, E>
53where
54    T: DeserializeOwned,
55    E: DeserializeOwned,
56{
57    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
58    where
59        D: serde::Deserializer<'de>,
60    {
61        // First try to deserialize as T (Ok)
62        let value = serde_json::Value::deserialize(deserializer)?;
63
64        let try_t: Result<T, _> = serde_json::from_value(value.clone());
65        let try_e: Result<E, _> = serde_json::from_value(value.clone());
66
67        match (try_t, try_e) {
68            (Ok(v), _) => Ok(JsonResult(Ok(v))),
69            (_, Ok(e)) => Ok(JsonResult(Err(e))),
70            (Err(t_err), Err(e_err)) => {
71                let t_name = std::any::type_name::<T>();
72                let e_name = std::any::type_name::<E>();
73
74                let msg = format!(
75                    "Failed to parse as {}: {}\nFailed to parse as {}: {}",
76                    t_name, t_err, e_name, e_err
77                );
78
79                Err(DeError::custom(msg))
80            }
81        }
82    }
83}
84
85impl<T, E> From<JsonResult<T, E>> for serde_json::Value
86where
87    T: Serialize,
88    E: Serialize,
89{
90    fn from(value: JsonResult<T, E>) -> Self {
91        match value.0 {
92            Ok(v) => serde_json::json!(v),
93            Err(e) => serde_json::json!(e),
94        }
95    }
96}
97
98// Deref to Result<T, E>
99impl<T, E> Deref for JsonResult<T, E> {
100    type Target = Result<T, E>;
101
102    fn deref(&self) -> &Self::Target {
103        &self.0
104    }
105}
106
107impl<T, E> DerefMut for JsonResult<T, E> {
108    fn deref_mut(&mut self) -> &mut Self::Target {
109        &mut self.0
110    }
111}
112
113impl<T, E> From<Result<T, E>> for JsonResult<T, E> {
114    fn from(r: Result<T, E>) -> Self {
115        JsonResult(r)
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use std::ops::DerefMut;
122
123    use super::JsonResult;
124    use serde::{Deserialize, Serialize};
125
126    #[derive(Debug, Serialize, Deserialize, PartialEq)]
127    struct GoodT {
128        v: u32,
129    }
130
131    #[derive(Debug, Serialize, Deserialize, PartialEq)]
132    struct BadE {
133        msg: String,
134    }
135
136    #[test]
137    fn test_ok_serialization() {
138        let jr = JsonResult::<i32, String>(Ok(100));
139        let s = serde_json::to_string(&jr).unwrap();
140        assert_eq!(s, "100");
141    }
142
143    #[test]
144    fn test_err_serialization() {
145        let jr = JsonResult::<i32, &str>(Err("boom"));
146        let s = serde_json::to_string(&jr).unwrap();
147        assert_eq!(s, "\"boom\"");
148    }
149
150    #[test]
151    fn test_deserialize_ok() {
152        let json = "42";
153        let jr: JsonResult<i32, String> = serde_json::from_str(json).unwrap();
154        assert_eq!(jr.0, Ok(42));
155    }
156
157    #[test]
158    fn test_deserialize_err() {
159        let json = "\"error occurred\"";
160        let jr: JsonResult<i32, String> = serde_json::from_str(json).unwrap();
161        assert_eq!(jr.0, Err("error occurred".to_string()));
162    }
163
164    #[test]
165    fn test_struct_ok_case() {
166        let json = serde_json::json!({ "v": 123 });
167        let jr: JsonResult<GoodT, BadE> = serde_json::from_value(json).unwrap();
168
169        assert_eq!(jr.0, Ok(GoodT { v: 123 }));
170    }
171
172    #[test]
173    fn test_struct_err_case() {
174        let json = serde_json::json!({ "msg": "fail" });
175        let jr: JsonResult<GoodT, BadE> = serde_json::from_value(json).unwrap();
176
177        assert_eq!(jr.0, Err(BadE { msg: "fail".into() }));
178    }
179
180    #[test]
181    fn test_round_trip_ok() {
182        let original = JsonResult::<GoodT, BadE>(Ok(GoodT { v: 55 }));
183        let json = serde_json::to_value(&original).unwrap();
184        let parsed: JsonResult<GoodT, BadE> = serde_json::from_value(json).unwrap();
185
186        assert_eq!(parsed.0, Ok(GoodT { v: 55 }));
187    }
188
189    #[test]
190    fn test_round_trip_err() {
191        let original = JsonResult::<GoodT, BadE>(Err(BadE { msg: "x".into() }));
192        let json = serde_json::to_value(&original).unwrap();
193        let parsed: JsonResult<GoodT, BadE> = serde_json::from_value(json).unwrap();
194
195        assert_eq!(parsed.0, Err(BadE { msg: "x".into() }));
196    }
197
198    #[test]
199    fn test_invalid_json_fails() {
200        let json = serde_json::json!([1, 2, 3]); // neither T nor E matches
201        let result = serde_json::from_value::<JsonResult<GoodT, BadE>>(json);
202        assert!(result.is_err());
203    }
204
205    #[test]
206    fn test_error_message_contains_type_names() {
207        #[derive(Debug, Serialize, Deserialize)]
208        struct Complex {
209            a: String,
210        }
211
212        let json = serde_json::json!(12345);
213
214        let result = serde_json::from_value::<JsonResult<Complex, Complex>>(json);
215        assert!(result.is_err());
216
217        let msg = result.unwrap_err().to_string();
218        assert!(msg.contains("Complex"));
219        assert!(msg.contains("Failed to parse"));
220    }
221
222    #[test]
223    fn test_ambiguous_matches_t_first() {
224        #[derive(Debug, Serialize, Deserialize, PartialEq)]
225        struct Amb {
226            x: u32,
227        }
228
229        let json = serde_json::json!({ "x": 10 });
230
231        let jr: JsonResult<Amb, Amb> = serde_json::from_value(json).unwrap();
232
233        // Ok should win because T is tried first
234        assert_eq!(jr.0, Ok(Amb { x: 10 }));
235    }
236
237    #[test]
238    fn test_null_fails() {
239        let json = serde_json::json!(null);
240        let result = serde_json::from_value::<JsonResult<GoodT, BadE>>(json);
241        assert!(result.is_err());
242    }
243
244    #[test]
245    fn test_value_into_serde_value_ok() {
246        let jr = JsonResult::<i32, &str>(Ok(7));
247        let v: serde_json::Value = jr.into();
248        assert_eq!(v, serde_json::json!(7));
249    }
250
251    #[test]
252    fn test_value_into_serde_value_err() {
253        let jr = JsonResult::<i32, &str>(Err("oops"));
254        let v: serde_json::Value = jr.into();
255        assert_eq!(v, serde_json::json!("oops"));
256    }
257
258    #[test]
259    fn deref_allows_calling_result_methods() {
260        let jr = JsonResult::<u32, &'static str>(Ok(42));
261
262        // Calling Result methods directly on JsonResult
263        assert!(jr.is_ok());
264        assert_eq!(jr.as_ref().unwrap(), &42);
265    }
266
267    #[test]
268    fn deref_works_with_pattern_matching() {
269        let jr = JsonResult::<u32, &'static str>(Ok(7));
270
271        // Should behave like a Result in patterns
272        match *jr {
273            Ok(v) => assert_eq!(v, 7),
274            Err(_) => panic!("Expected Ok"),
275        }
276    }
277
278    #[test]
279    fn deref_mut_allows_modifying_result() {
280        let mut jr = JsonResult::<u32, &'static str>(Ok(10));
281
282        // Modify the inner value via DerefMut
283        if let Ok(v) = jr.deref_mut() {
284            *v = 99;
285        }
286
287        assert_eq!(jr.unwrap(), 99);
288    }
289
290    #[test]
291    fn deref_mut_replaces_result() {
292        let mut jr = JsonResult::<u32, &'static str>(Ok(1));
293
294        // Replace whole Result<T,E>
295        *jr = Err("failed");
296
297        assert!(jr.is_err());
298        assert_eq!(jr.unwrap_err(), "failed");
299    }
300
301    #[test]
302    fn can_be_used_like_result_in_functions() {
303        fn take_result(r: &Result<u32, &'static str>) -> u32 {
304            *r.as_ref().unwrap()
305        }
306
307        let jr = JsonResult(Ok(55));
308
309        // JsonResult derefs to Result
310        assert_eq!(take_result(&jr), 55);
311    }
312
313    #[derive(Debug, PartialEq)]
314    struct OKData(i32);
315
316    #[derive(Debug, PartialEq)]
317    struct ErrData(&'static str);
318
319    #[test]
320    fn from_result_ok() {
321        let r: Result<OKData, ErrData> = Ok(OKData(99));
322
323        let jr: JsonResult<OKData, ErrData> = r.into();
324
325        assert!(jr.0.is_ok());
326        assert_eq!(jr.0.unwrap(), OKData(99));
327    }
328
329    #[test]
330    fn from_result_err() {
331        let r: Result<OKData, ErrData> = Err(ErrData("error"));
332
333        let jr: JsonResult<OKData, ErrData> = r.into();
334
335        assert!(jr.0.is_err());
336        assert_eq!(jr.0.unwrap_err(), ErrData("error"));
337    }
338
339    #[test]
340    fn from_result_type_inference_ok() {
341        let r = Ok::<i32, &str>(123);
342        let jr: JsonResult<i32, &str> = r.into();
343
344        assert_eq!(jr.0.unwrap(), 123);
345    }
346
347    #[test]
348    fn from_result_type_inference_err() {
349        let r = Err::<i32, &str>("bad");
350        let jr: JsonResult<i32, &str> = r.into();
351
352        assert_eq!(jr.0.unwrap_err(), "bad");
353    }
354
355    #[test]
356    fn from_result_does_not_clone() {
357        // Ensure we are not accidentally cloning
358        // (this test checks pointer identity)
359        let msg = String::from("boom");
360        let ptr = msg.as_ptr();
361
362        let r: Result<(), String> = Err(msg);
363        let jr: JsonResult<(), String> = r.into();
364
365        let inner = jr.0.unwrap_err();
366        assert_eq!(inner.as_ptr(), ptr); // SAME pointer = no clone
367    }
368
369    #[test]
370    fn from_result_owned_types() {
371        let r: Result<String, String> = Ok("hello".to_string());
372        let jr: JsonResult<String, String> = r.into();
373        assert_eq!(jr.0.unwrap(), "hello");
374    }
375
376    #[test]
377    fn from_result_reference_error() {
378        let r: Result<i32, &str> = Err("fail");
379        let jr: JsonResult<i32, &str> = r.into();
380        assert_eq!(jr.0.unwrap_err(), "fail");
381    }
382}