1use crate::{error::Error, id::Id};
4
5pub mod builder;
6
7#[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
8pub struct Response {
10 #[serde(deserialize_with = "crate::version::version_deserialize")]
11 jsonrpc: String,
12 pub id: Id,
13 #[serde(flatten)]
14 pub status: Status,
15}
16
17#[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
18pub enum Status {
20 #[serde(rename = "result")]
21 Success(serde_json::Value),
22 #[serde(rename = "error")]
23 Error {
24 code: i32,
25 message: String,
26 data: Option<serde_json::Value>,
27 },
28}
29
30impl Response {
31 pub fn builder() -> builder::Builder<builder::IdNone> {
32 builder::Builder::new()
33 }
34}
35
36impl TryFrom<&str> for Response {
37 type Error = Error;
38
39 fn try_from(value: &str) -> Result<Self, Self::Error> {
40 serde_json::from_str(value).map_err(|e| e.into())
41 }
42}
43
44impl TryFrom<Response> for String {
45 type Error = Error;
46
47 fn try_from(value: Response) -> Result<Self, Self::Error> {
48 serde_json::to_string(&value).map_err(|e| e.into())
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn deserialize_spec_requests() {
58 let req = r#"{"jsonrpc": "2.0", "result": 19, "id": 1}"#;
59 let req_obj = TryInto::<Response>::try_into(req);
60 assert!(req_obj.is_ok());
61 let req_obj = req_obj.unwrap();
62 assert_eq!(req_obj.jsonrpc, "2.0");
63 assert!(matches!(
64 req_obj.status,
65 Status::Success(serde_json::Value::Number(_))
66 ));
67
68 let req = r#"{"jsonrpc": "2.0", "result": -19, "id": 2}"#;
69 let req_obj = TryInto::<Response>::try_into(req);
70 assert!(req_obj.is_ok());
71 let req_obj = req_obj.unwrap();
72 assert_eq!(req_obj.jsonrpc, "2.0");
73 assert!(matches!(
74 req_obj.status,
75 Status::Success(serde_json::Value::Number(_))
76 ));
77
78 let req = r#"{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}"#;
79 let req_obj = TryInto::<Response>::try_into(req);
80 assert!(req_obj.is_ok());
81 let req_obj = req_obj.unwrap();
82 assert_eq!(req_obj.jsonrpc, "2.0");
83 assert!(matches!(
84 req_obj.status,
85 Status::Error {
86 code: _,
87 message: _,
88 data: _
89 }
90 ));
91
92 let req = r#"{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}"#;
93 let req_obj = TryInto::<Response>::try_into(req);
94 assert!(req_obj.is_ok());
95 let req_obj = req_obj.unwrap();
96 assert_eq!(req_obj.jsonrpc, "2.0");
97 assert!(matches!(
98 req_obj.status,
99 Status::Error {
100 code: _,
101 message: _,
102 data: _
103 }
104 ));
105 }
106
107 #[test]
108 fn negative_serde_tests() {
109 let req = r#"{"jsonrpc": "2.1", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}"#; let req_obj = TryInto::<Response>::try_into(req);
111 assert!(req_obj.is_err());
112
113 let req = r#"{"jsonrpc": 2.1, "error": {"code": -32600, "message": "Invalid Request"}, "id": null}"#; let req_obj = TryInto::<Response>::try_into(req);
115 assert!(req_obj.is_err());
116
117 let req = r#"{"jsonrpc": "2.0", "id": null}"#; let req_obj = TryInto::<Response>::try_into(req);
119 assert!(req_obj.is_err());
120
121 let req = r#"{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}}"#; let req_obj = TryInto::<Response>::try_into(req);
123 assert!(req_obj.is_err());
124 }
125
126 #[test]
127 fn builder() {
128 let params = vec![10, 0];
129 let rsp = Response::builder()
130 .id(10)
131 .success()
132 .result(params)
133 .unwrap()
134 .build();
135 let rsp_str = TryInto::<String>::try_into(rsp).unwrap();
136 let new_req = TryInto::<Response>::try_into(rsp_str.as_str());
137 assert!(new_req.is_ok());
138
139 let rsp = Response::builder().error().invalid_params().id(10).build();
140 let rsp_str = TryInto::<String>::try_into(rsp).unwrap();
141 let new_req = TryInto::<Response>::try_into(rsp_str.as_str());
142 assert!(new_req.is_ok());
143 }
144}