1use crate::{error::Error, id::Id, params::Params};
4
5pub mod builder;
6
7#[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
8pub struct Request {
10 #[serde(deserialize_with = "crate::version::version_deserialize")]
11 jsonrpc: String,
12 pub method: String,
13 pub params: Option<Params>,
14 pub id: Id,
15}
16
17impl Request {
18 pub fn builder() -> builder::Builder<builder::MethodNone, builder::IdNone> {
19 builder::Builder::new()
20 }
21}
22
23impl TryFrom<&str> for Request {
24 type Error = Error;
25
26 fn try_from(value: &str) -> Result<Self, Self::Error> {
27 serde_json::from_str(value).map_err(|e| e.into())
28 }
29}
30
31impl TryFrom<Request> for String {
32 type Error = Error;
33
34 fn try_from(value: Request) -> Result<Self, Self::Error> {
35 serde_json::to_string(&value).map_err(|e| e.into())
36 }
37}
38
39impl From<&Request> for Id {
42 fn from(value: &Request) -> Self {
43 value.id.clone()
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn deserialize_spec_requests() {
53 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}"#;
54 let req_obj = TryInto::<Request>::try_into(req);
55 assert!(req_obj.is_ok());
56 let req_obj = req_obj.unwrap();
57 assert_eq!(req_obj.jsonrpc, "2.0");
58 assert_eq!(req_obj.method, "subtract");
59
60 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2}"#;
61 let req_obj = TryInto::<Request>::try_into(req);
62 assert!(req_obj.is_ok());
63 let req_obj = req_obj.unwrap();
64 assert_eq!(req_obj.jsonrpc, "2.0");
65 assert_eq!(req_obj.method, "subtract");
66
67 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}"#;
68 let req_obj = TryInto::<Request>::try_into(req);
69 assert!(req_obj.is_ok());
70 let req_obj = req_obj.unwrap();
71 assert_eq!(req_obj.jsonrpc, "2.0");
72 assert_eq!(req_obj.method, "subtract");
73
74 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}"#;
75 let req_obj = TryInto::<Request>::try_into(req);
76 assert!(req_obj.is_ok());
77 let req_obj = req_obj.unwrap();
78 assert_eq!(req_obj.jsonrpc, "2.0");
79 assert_eq!(req_obj.method, "subtract");
80
81 let req = r#"{"jsonrpc": "2.0", "method": "foobar", "id": "1"}"#;
82 let req_obj = TryInto::<Request>::try_into(req);
83 assert!(req_obj.is_ok());
84 let req_obj = req_obj.unwrap();
85 assert_eq!(req_obj.jsonrpc, "2.0");
86 assert_eq!(req_obj.method, "foobar");
87
88 let req = r#"{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]"#;
89 let req_obj = TryInto::<Request>::try_into(req);
90 assert!(req_obj.is_err());
91
92 let req = r#"{"jsonrpc": "2.0", "method": 1, "params": "bar"}"#;
93 let req_obj = TryInto::<Request>::try_into(req);
94 assert!(req_obj.is_err());
95 }
96
97 #[test]
98 fn negative_serde_tests() {
99 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23]}"#; let req_obj = TryInto::<Request>::try_into(req);
101 assert!(req_obj.is_err());
102
103 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id":{}}"#; let req_obj = TryInto::<Request>::try_into(req);
105 assert!(req_obj.is_err());
106
107 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id":[]}"#; let req_obj = TryInto::<Request>::try_into(req);
109 assert!(req_obj.is_err());
110
111 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": 1, "id":2}"#; let req_obj = TryInto::<Request>::try_into(req);
113 assert!(req_obj.is_err());
114
115 let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": "hello", "id":2}"#; let req_obj = TryInto::<Request>::try_into(req);
117 assert!(req_obj.is_err());
118
119 let req = r#"{"jsonrpc": "2.1", "method": "subtract", "id":2}"#; let req_obj = TryInto::<Request>::try_into(req);
121 assert!(req_obj.is_err());
122
123 let req = r#"{"jsonrpc": 2.0, "method": "subtract", "id":2}"#; let req_obj = TryInto::<Request>::try_into(req);
125 assert!(req_obj.is_err());
126 }
127
128 #[test]
129 fn builder() {
130 let params = vec![10, 0];
131 let req = Request::builder()
132 .id(10)
133 .method("test-method")
134 .params_serialize(params)
135 .unwrap()
136 .build();
137 let req_str = TryInto::<String>::try_into(req).unwrap();
138 let new_req = TryInto::<Request>::try_into(req_str.as_str());
139 assert!(new_req.is_ok());
140 }
141}