json_result/lib.rs
1use serde::de::{DeserializeOwned, Error};
2
3/// A generic enum representing a JSON result that can either be a success (`Ok`) with a value of type `T`
4/// or an error (`Err`) with a value of type `E`.
5///
6/// This enum is designed to be serialized and deserialized using Serde's untagged enum representation,
7/// allowing it to seamlessly handle JSON values that could match either type.
8#[derive(Debug, serde::Serialize, serde::Deserialize)]
9#[serde(untagged)]
10pub enum JsonResult<T, E> {
11 /// Variant representing a successful result containing a value of type `T`.
12 Ok(T),
13 /// Variant representing an error result containing a value of type `E`.
14 Err(E),
15}
16
17impl<T, E> From<JsonResult<T, E>> for serde_json::Value
18where
19 T: serde::Serialize,
20 E: serde::Serialize,
21{
22 /// Converts a `JsonResult<T, E>` into a `serde_json::Value`.
23 ///
24 /// Serializes the contained value in either the `Ok` or `Err` variant into a JSON value.
25 ///
26 /// # Examples
27 ///
28 /// ```
29 /// # use serde_json::json;
30 /// # use json_result::JsonResult;
31 /// let res: JsonResult<i32, String> = JsonResult::Ok(42);
32 /// let json_value: serde_json::Value = res.into();
33 /// assert_eq!(json_value, json!(42));
34 /// ```
35 fn from(res: JsonResult<T, E>) -> Self {
36 match res {
37 JsonResult::Ok(v) => serde_json::json!(v),
38 JsonResult::Err(e) => serde_json::json!(e),
39 }
40 }
41}
42
43impl<T, E> TryFrom<serde_json::Value> for JsonResult<T, E>
44where
45 T: DeserializeOwned,
46 E: DeserializeOwned,
47{
48 type Error = serde_json::Error;
49
50 /// Attempts to convert a `serde_json::Value` into a `JsonResult<T, E>` by
51 /// trying to deserialize it first into `T` (success variant), then into `E` (error variant).
52 ///
53 /// If deserialization into both types fails, returns a combined error message detailing both failures.
54 ///
55 /// # Errors
56 ///
57 /// Returns a `serde_json::Error` if the input JSON value cannot be parsed as either `T` or `E`.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// # use serde_json::json;
63 /// # use json_result::JsonResult;
64 /// let json_val = json!(42);
65 /// let res: JsonResult<i32, String> = json_val.try_into().unwrap();
66 /// match res {
67 /// JsonResult::Ok(val) => assert_eq!(val, 42),
68 /// JsonResult::Err(_) => panic!("Expected Ok variant"),
69 /// }
70 /// ```
71 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
72 let t_res = serde_json::from_value::<T>(value.clone());
73 let e_res = serde_json::from_value::<E>(value);
74
75 match (t_res, e_res) {
76 (Ok(v), _) => Ok(JsonResult::Ok(v)),
77 (_, Ok(e)) => Ok(JsonResult::Err(e)),
78 (Err(t_err), Err(e_err)) => {
79 let t_name = std::any::type_name::<T>();
80 let e_name = std::any::type_name::<E>();
81 let message = format!(
82 "Failed to parse as {}: {}\nFailed to parse as {}: {}",
83 t_name, t_err, e_name, e_err
84 );
85 Err(serde_json::Error::custom(message))
86 }
87 }
88 }
89}
90
91#[cfg(test)]
92mod test;
93
94pub use serde;
95pub use serde_json;