jsonrpc_lite/
jsonrpc.rs

1use Error as RpcError;
2use serde_json::{Map, Value, Result as SerdeResult};
3
4/// An identifier established by the Client that MUST contain a String, Number,
5/// or NULL value if included. If it is not included it is assumed to be a notification.
6/// The value SHOULD normally not be Null and Numbers SHOULD NOT contain fractional parts
7#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize, Hash)]
8#[serde(untagged)]
9pub enum Id {
10    Num(i64),
11    Str(String),
12    None(()),
13}
14
15impl From<()> for Id {
16    fn from(val: ()) -> Self {
17        Id::None(val)
18    }
19}
20
21impl From<i64> for Id {
22    fn from(val: i64) -> Self {
23        Id::Num(val)
24    }
25}
26
27impl From<String> for Id {
28    fn from(val: String) -> Self {
29        Id::Str(val)
30    }
31}
32
33/// A Structured value that holds the parameter values
34/// to be used during the invocation of the method.
35/// This member MAY be omitted.
36#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
37#[serde(untagged)]
38pub enum Params {
39    Array(Vec<Value>),
40    Map(Map<String, Value>),
41    None(()),
42}
43
44impl From<Value> for Params {
45    fn from(val: Value) -> Self {
46        match val {
47            Value::Array(v) => Params::Array(v),
48            Value::Object(v) => Params::Map(v),
49            _ => Params::None(()),
50        }
51    }
52}
53
54impl From<Vec<Value>> for Params {
55    fn from(val: Vec<Value>) -> Self {
56        Params::Array(val)
57    }
58}
59
60impl From<Map<String, Value>> for Params {
61    fn from(val: Map<String, Value>) -> Self {
62        Params::Map(val)
63    }
64}
65
66#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
67pub struct Request {
68    jsonrpc: String,
69    method: String,
70    #[serde(default)]
71    #[serde(skip_serializing_if = "Option::is_none")]
72    params: Option<Params>,
73    id: Id,
74}
75
76#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
77pub struct Notification {
78    jsonrpc: String,
79    method: String,
80    #[serde(default)]
81    #[serde(skip_serializing_if = "Option::is_none")]
82    params: Option<Params>,
83}
84
85#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
86pub struct Success {
87    jsonrpc: String,
88    result: Value,
89    id: Id,
90}
91
92#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
93pub struct Error {
94    jsonrpc: String,
95    error: RpcError,
96    id: Id,
97}
98
99/// JSON-RPC 2.0 Request object and Response object
100/// [JSON-RPC 2.0 Specification](http://www.jsonrpc.org/specification).
101#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
102#[serde(untagged)]
103pub enum JsonRpc {
104    /// Request object
105    Request(Request),
106    /// Notification object
107    Notification(Notification),
108    /// Success Response
109    Success(Success),
110    /// Error Response
111    Error(Error),
112}
113
114impl JsonRpc {
115    /// Creates a JSON-RPC 2.0 request object without params
116    pub fn request<I: Into<Id>>(id: I, method: &str) -> Self {
117        JsonRpc::Request(Request {
118            jsonrpc: String::from("2.0"),
119            method: String::from(method),
120            params: None,
121            id: id.into(),
122        })
123    }
124
125    /// Creates a JSON-RPC 2.0 request object with params
126    pub fn request_with_params<I: Into<Id>, P: Into<Params>>(
127        id: I,
128        method: &str,
129        params: P,
130    ) -> Self {
131        JsonRpc::Request(Request {
132            jsonrpc: String::from("2.0"),
133            method: String::from(method),
134            params: Some(params.into()),
135            id: id.into(),
136        })
137    }
138
139    /// Creates a JSON-RPC 2.0 notification object without params
140    pub fn notification(method: &str) -> Self {
141        JsonRpc::Notification(Notification {
142            jsonrpc: String::from("2.0"),
143            method: String::from(method),
144            params: None,
145        })
146    }
147
148    /// Creates a JSON-RPC 2.0 notification object with params
149    pub fn notification_with_params<P: Into<Params>>(method: &str, params: P) -> Self {
150        JsonRpc::Notification(Notification {
151            jsonrpc: String::from("2.0"),
152            method: String::from(method),
153            params: Some(params.into()),
154        })
155    }
156
157    /// Creates a JSON-RPC 2.0 success response object
158    pub fn success<I: Into<Id>>(id: I, result: &Value) -> Self {
159        JsonRpc::Success(Success {
160            jsonrpc: String::from("2.0"),
161            result: result.clone(),
162            id: id.into(),
163        })
164    }
165
166    /// Creates a JSON-RPC 2.0 error response object
167    pub fn error<I: Into<Id>>(id: I, error: RpcError) -> Self {
168        JsonRpc::Error(Error {
169            jsonrpc: String::from("2.0"),
170            error,
171            id: id.into(),
172        })
173    }
174
175    pub fn get_version(&self) -> Option<&str> {
176        match self {
177            JsonRpc::Notification(ref v) => Some(&v.jsonrpc),
178            JsonRpc::Request(ref v) => Some(&v.jsonrpc),
179            JsonRpc::Success(ref v) => Some(&v.jsonrpc),
180            JsonRpc::Error(ref v) => Some(&v.jsonrpc),
181        }
182    }
183
184    pub fn get_id(&self) -> Option<Id> {
185        match *self {
186            JsonRpc::Request(ref v) => Some(v.id.clone()),
187            JsonRpc::Success(ref v) => Some(v.id.clone()),
188            JsonRpc::Error(ref v) => Some(v.id.clone()),
189            _ => None,
190        }
191    }
192
193    pub fn get_method(&self) -> Option<&str> {
194        match *self {
195            JsonRpc::Notification(ref v) => Some(&v.method),
196            JsonRpc::Request(ref v) => Some(&v.method),
197            _ => None,
198        }
199    }
200
201    pub fn get_params(&self) -> Option<Params> {
202        match *self {
203            JsonRpc::Notification(ref v) => v.params.as_ref().cloned(),
204            JsonRpc::Request(ref v) => v.params.as_ref().cloned(),
205            _ => None,
206        }
207    }
208
209    pub fn get_result(&self) -> Option<&Value> {
210        match *self {
211            JsonRpc::Success(ref v) => Some(&v.result),
212            _ => None,
213        }
214    }
215
216    pub fn get_error(&self) -> Option<&RpcError> {
217        match *self {
218            JsonRpc::Error(ref v) => Some(&v.error),
219            _ => None,
220        }
221    }
222
223    pub fn parse(input: &str) -> SerdeResult<Self> {
224        use serde_json::from_str;
225        from_str(input)
226    }
227
228    pub fn parse_vec(input: &str) -> SerdeResult<Vec<Self>> {
229        use serde_json::from_str;
230        from_str(input)
231    }
232}
233
234#[cfg(test)]
235mod tests {
236    use super::*;
237    use serde_json::to_value;
238
239    #[test]
240    fn request() {
241        let jsonrpc = to_value(JsonRpc::request((), "test"))
242            .expect("Unable to turn request into a Json Value");
243        assert_eq!(
244            jsonrpc,
245            json!({
246                "id": null,
247                "jsonrpc": "2.0",
248                "method": "test"
249            })
250        );
251    }
252
253    #[test]
254    fn request_with_params_vec() {
255        let jsonrpc = to_value(JsonRpc::request_with_params(
256            46714,
257            "test",
258            json!([true, false, false, true]),
259        )).expect("Unable to turn request_with_params_vec into a Json Value");
260        assert_eq!(
261            jsonrpc,
262            json!({
263                "id": 46714,
264                "jsonrpc": "2.0",
265                "method": "test",
266                "params": [true, false, false, true]
267            })
268        );
269    }
270
271    #[test]
272    fn request_with_params_map() {
273        let jsonrpc = to_value(JsonRpc::request_with_params(
274            String::from("alpha-gamma-06714"),
275            "test",
276            json!({
277                "key": "94151351-5651651658-56151351351",
278                "n": 5158,
279                "mean": 454.54
280            }),
281        )).expect("Unable to turn request_with_params_map into a Json Value");
282        assert_eq!(
283            jsonrpc,
284            json!({
285                "id": "alpha-gamma-06714",
286                "jsonrpc": "2.0",
287                "method": "test",
288                "params": {
289                    "key": "94151351-5651651658-56151351351",
290                    "n": 5158,
291                    "mean": 454.54
292                }
293            })
294        );
295    }
296}