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;