1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
8#![warn(missing_docs)]
10
11pub extern crate serde;
13pub extern crate serde_json;
15
16#[cfg(feature = "base64")]
18pub extern crate base64;
19
20#[cfg(feature = "minreq")]
22pub extern crate minreq;
23
24pub mod client;
25pub mod error;
26pub mod http;
27
28#[cfg(feature = "simple_http")]
29pub use http::simple_http;
30
31#[cfg(feature = "minreq_http")]
32pub use http::minreq_http;
33
34#[cfg(feature = "simple_tcp")]
35pub mod simple_tcp;
36
37#[cfg(all(feature = "simple_uds", not(windows)))]
38pub mod simple_uds;
39
40use serde::{Deserialize, Serialize};
41use serde_json::value::RawValue;
42
43pub use crate::client::{Client, Transport};
44pub use crate::error::Error;
45
46pub fn try_arg<T: serde::Serialize>(arg: T) -> Result<Box<RawValue>, serde_json::Error> {
50 RawValue::from_string(serde_json::to_string(&arg)?)
51}
52
53pub fn arg<T: serde::Serialize>(arg: T) -> Box<RawValue> {
58 match try_arg(arg) {
59 Ok(v) => v,
60 Err(e) => RawValue::from_string(format!("<<ERROR SERIALIZING ARGUMENT: {}>>", e))
61 .unwrap_or_else(|_| {
62 RawValue::from_string("<<ERROR SERIALIZING ARGUMENT>>".to_owned()).unwrap()
63 }),
64 }
65}
66
67#[derive(Debug, Clone, Serialize)]
69pub struct Request<'a> {
70 pub method: &'a str,
72 pub params: Option<&'a RawValue>,
74 pub id: serde_json::Value,
76 pub jsonrpc: Option<&'a str>,
78}
79
80#[derive(Debug, Clone, Deserialize, Serialize)]
82pub struct Response {
83 pub result: Option<Box<RawValue>>,
85 pub error: Option<error::RpcError>,
87 pub id: serde_json::Value,
89 pub jsonrpc: Option<String>,
91}
92
93impl Response {
94 pub fn result<T: for<'a> serde::de::Deserialize<'a>>(&self) -> Result<T, Error> {
96 if let Some(ref e) = self.error {
97 return Err(Error::Rpc(e.clone()));
98 }
99
100 if let Some(ref res) = self.result {
101 serde_json::from_str(res.get()).map_err(Error::Json)
102 } else {
103 serde_json::from_value(serde_json::Value::Null).map_err(Error::Json)
104 }
105 }
106
107 pub fn check_error(self) -> Result<(), Error> {
109 if let Some(e) = self.error {
110 Err(Error::Rpc(e))
111 } else {
112 Ok(())
113 }
114 }
115
116 pub fn is_none(&self) -> bool {
118 self.result.is_none()
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 use serde_json::{
127 json,
128 value::{to_raw_value, RawValue},
129 };
130
131 #[test]
132 fn response_is_none() {
133 let joanna = Response {
134 result: Some(RawValue::from_string(serde_json::to_string(&true).unwrap()).unwrap()),
135 error: None,
136 id: From::from(81),
137 jsonrpc: Some(String::from("2.0")),
138 };
139
140 let bill = Response {
141 result: None,
142 error: None,
143 id: From::from(66),
144 jsonrpc: Some(String::from("2.0")),
145 };
146
147 assert!(!joanna.is_none());
148 assert!(bill.is_none());
149 }
150
151 #[test]
152 fn response_extract() {
153 let obj = vec!["Mary", "had", "a", "little", "lamb"];
154 let response = Response {
155 result: Some(RawValue::from_string(serde_json::to_string(&obj).unwrap()).unwrap()),
156 error: None,
157 id: serde_json::Value::Null,
158 jsonrpc: Some(String::from("2.0")),
159 };
160 let recovered1: Vec<String> = response.result().unwrap();
161 assert!(response.clone().check_error().is_ok());
162 let recovered2: Vec<String> = response.result().unwrap();
163 assert_eq!(obj, recovered1);
164 assert_eq!(obj, recovered2);
165 }
166
167 #[test]
168 fn null_result() {
169 let s = r#"{"result":null,"error":null,"id":"test"}"#;
170 let response: Response = serde_json::from_str(s).unwrap();
171 let recovered1: Result<(), _> = response.result();
172 let recovered2: Result<(), _> = response.result();
173 assert!(recovered1.is_ok());
174 assert!(recovered2.is_ok());
175
176 let recovered1: Result<String, _> = response.result();
177 let recovered2: Result<String, _> = response.result();
178 assert!(recovered1.is_err());
179 assert!(recovered2.is_err());
180 }
181
182 #[test]
183 fn batch_response() {
184 let s = r#"[
186 {"jsonrpc": "2.0", "result": 7, "id": "1"},
187 {"jsonrpc": "2.0", "result": 19, "id": "2"},
188 {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
189 {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
190 {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
191 ]"#;
192 let batch_response: Vec<Response> = serde_json::from_str(s).unwrap();
193 assert_eq!(batch_response.len(), 5);
194 }
195
196 #[test]
197 fn test_arg() {
198 macro_rules! test_arg {
199 ($val:expr, $t:ty) => {{
200 let val1: $t = $val;
201 let arg = super::arg(val1.clone());
202 let val2: $t = serde_json::from_str(arg.get()).expect(stringify!($val));
203 assert_eq!(val1, val2, "failed test for {}", stringify!($val));
204 }};
205 }
206
207 test_arg!(true, bool);
208 test_arg!(42, u8);
209 test_arg!(42, usize);
210 test_arg!(42, isize);
211 test_arg!(vec![42, 35], Vec<u8>);
212 test_arg!(String::from("test"), String);
213
214 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
215 struct Test {
216 v: String,
217 }
218 test_arg!(
219 Test {
220 v: String::from("test"),
221 },
222 Test
223 );
224 }
225
226 #[test]
227 fn test_request_list() {
228 let list = json!([0]);
229 let raw_value = Some(to_raw_value(&list).unwrap());
230
231 let request = Request {
232 method: "list",
233 params: raw_value.as_deref(),
234 id: serde_json::json!(2),
235 jsonrpc: Some("2.0"),
236 };
237 assert_eq!(
238 serde_json::to_string(&request).unwrap(),
239 r#"{"method":"list","params":[0],"id":2,"jsonrpc":"2.0"}"#
240 );
241 }
242
243 #[test]
244 fn test_request_object() {
245 let object = json!({ "height": 0 });
246 let raw_value = Some(to_raw_value(&object).unwrap());
247
248 let request = Request {
249 method: "object",
250 params: raw_value.as_deref(),
251 id: serde_json::json!(2),
252 jsonrpc: Some("2.0"),
253 };
254 assert_eq!(
255 serde_json::to_string(&request).unwrap(),
256 r#"{"method":"object","params":{"height":0},"id":2,"jsonrpc":"2.0"}"#
257 );
258 }
259}