1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::error::Error;
use crate::version::Version;
use crate::id::Id;
use crate::utils::Key;

use core::mem;

///Response representation.
///
///When omitting `id`, it shall be serialized as `null` and means you're unable to identify `id` of
///`Request`.
///Note that JSON-RPCv2 specifies that `id` must be always present, therefore you're encouraged to
///treat missing `id` as error, unless response is error itself, in which case it might be
///indication that server treats request as invalid (e.g. unable to parse request's id).
///
///`jsonrpc` may be omitted during deserialization and defaults to v2.
///
///Type parameters:
///
///- `R`  - Type of payload for successful response
///- `E`  - Type of optional data for `Error`.
///- `EM` - Type of `E::M`, which is used for `message` field of error.
#[derive(Clone, Debug, PartialEq)]
pub struct Response<R, E, EM=crate::error::StrBuf> {
    ///A String specifying the version of the JSON-RPC protocol.
    pub jsonrpc: Version,

    ///Content of response, depending on whether it is success or failure.
    pub payload: Result<R, Error<E, EM>>,

    ///An identifier established by the Client.
    ///
    ///If not present, it is sent in response to invalid request (e.g. unable to recognize id).
    ///
    ///Must be present always, so `None` is serialized as `null`
    pub id: Option<Id>,
}

impl<R: Serialize, E: Serialize, EM: Serialize> Serialize for Response<R, E, EM> {
    fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeMap;

        let mut state = ser.serialize_map(Some(3))?;

        state.serialize_entry("jsonrpc", &self.jsonrpc)?;
        match self.payload {
            Ok(ref result) => state.serialize_entry("result", result),
            Err(ref error) => state.serialize_entry("error", error),
        }?;
        match self.id {
            Some(ref id) => state.serialize_entry("id", id),
            None => state.serialize_entry("id", &()),
        }?;

        state.end()
    }
}

impl<'de, R: Deserialize<'de>, E: Deserialize<'de>, EM: Deserialize<'de>> Deserialize<'de> for Response<R, E, EM> {
    fn deserialize<D: Deserializer<'de>>(der: D) -> Result<Self, D::Error> {
        use core::marker::PhantomData;
        use serde::de::{self, Visitor};

        struct MapVisit<R, E, EM>(PhantomData<(R, E, EM)>);

        impl<'de, R: Deserialize<'de>, E: Deserialize<'de>, EM: Deserialize<'de>> Visitor<'de> for MapVisit<R, E, EM> {
            type Value = Response<R, E, EM>;

            #[inline]
            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
                formatter.write_str("Object resembling JSON-RPC response type")
            }

            fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
                //Normally you'd use unitialized struct, but it is highly unlikely to guarantee
                //safety of field-by-field initialization
                let mut version = None;
                let mut result = None;
                let mut id = None;

                while let Some(key) = map.next_key::<Key>()? {
                    match key {
                        Key::JsonRpc => {
                            version = Some(map.next_value::<Version>()?);
                        },
                        //If for some reason user wishes to convey success with NULL, we need to respect that.
                        //This cannot be the case for error as its format is well defined
                        //And while spec does say `result` field MUST be object, theoretically NULL should qualify too.
                        //This is hack because bitch cannot have specialization stabilized forever
                        Key::Result if mem::size_of::<R>() == 0 => {
                            if result.is_none() {
                                result = Some(Ok(map.next_value::<R>()?));
                            } else {
                                return Err(serde::de::Error::custom("JSON-RPC Response contains both result and error field"));
                            }
                        }
                        Key::Result => match map.next_value::<Option<R>>()? {
                            Some(value) => if result.is_none() {
                                result = Some(Ok(value));
                            } else {
                                return Err(serde::de::Error::custom("JSON-RPC Response contains both result and error field"));
                            }
                            None => continue,
                        },
                        Key::Error => match map.next_value::<Option<Error<E, EM>>>()? {
                            Some(error) => if result.is_none() {
                                result = Some(Err(error));
                            } else {
                                return Err(serde::de::Error::custom("JSON-RPC Response contains both error and result field"));
                            }
                            None => continue,
                        },
                        Key::Id => {
                            id = map.next_value::<Option<Id>>()?;
                        },
                    }
                }

                Ok(Self::Value {
                    jsonrpc: match version {
                        Some(version) => version,
                        None => Version::V2,
                    },
                    payload: match result {
                        Some(payload) => payload,
                        None => {
                            return Err(serde::de::Error::custom("JSON-RPC Response is missing either result or error field."));
                        }
                    },
                    id,
                })
            }
        }

        der.deserialize_map(MapVisit(PhantomData))
    }
}

impl<R, E, EM> Response<R, E, EM> {
    #[inline]
    ///Creates successful response.
    pub const fn result(jsonrpc: Version, result: R, id: Option<Id>) -> Self {
        Self {
            jsonrpc,
            payload: Ok(result),
            id,
        }
    }

    #[inline]
    ///Creates error response.
    pub const fn error(jsonrpc: Version, error: Error<E, EM>, id: Option<Id>) -> Self {
        Self {
            jsonrpc,
            payload: Err(error),
            id,
        }
    }
}