1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(deny_unknown_fields)]
7pub struct RpcMethodCall {
8 pub jsonrpc: Version,
10 pub method: String,
12 #[serde(default = "no_params")]
14 pub params: RequestParams,
15 pub id: Id,
19}
20
21impl RpcMethodCall {
22 pub fn id(&self) -> Id {
23 self.id.clone()
24 }
25}
26
27#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
30#[serde(deny_unknown_fields)]
31pub struct RpcNotification {
32 pub jsonrpc: Option<Version>,
33 pub method: String,
34 #[serde(default = "no_params")]
35 pub params: RequestParams,
36}
37
38#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(untagged)]
41pub enum RpcCall {
42 MethodCall(RpcMethodCall),
44 Notification(RpcNotification),
46 Invalid {
48 #[serde(default = "null_id")]
50 id: Id,
51 },
52}
53
54#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
56#[serde(deny_unknown_fields)]
57#[serde(untagged)]
58pub enum Request {
59 Single(RpcCall),
61 Batch(Vec<RpcCall>),
63}
64
65#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
67#[serde(untagged, deny_unknown_fields)]
68pub enum RequestParams {
69 None,
71 Array(Vec<serde_json::Value>),
73 Object(serde_json::Map<String, serde_json::Value>),
75}
76
77impl From<RequestParams> for serde_json::Value {
78 fn from(params: RequestParams) -> Self {
79 match params {
80 RequestParams::None => Self::Null,
81 RequestParams::Array(arr) => arr.into(),
82 RequestParams::Object(obj) => obj.into(),
83 }
84 }
85}
86
87fn no_params() -> RequestParams {
88 RequestParams::None
89}
90
91#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
93pub enum Version {
94 #[serde(rename = "2.0")]
95 V2,
96}
97
98#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(untagged)]
100pub enum Id {
101 String(String),
102 Number(i64),
103 Null,
104}
105
106impl fmt::Display for Id {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 match self {
109 Self::String(s) => s.fmt(f),
110 Self::Number(n) => n.fmt(f),
111 Self::Null => f.write_str("null"),
112 }
113 }
114}
115
116fn null_id() -> Id {
117 Id::Null
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn can_serialize_batch() {
126 let batch = Request::Batch(vec![
127 RpcCall::MethodCall(RpcMethodCall {
128 jsonrpc: Version::V2,
129 method: "eth_method".to_owned(),
130 params: RequestParams::Array(vec![
131 serde_json::Value::from(999),
132 serde_json::Value::from(1337),
133 ]),
134 id: Id::Number(1),
135 }),
136 RpcCall::Notification(RpcNotification {
137 jsonrpc: Some(Version::V2),
138 method: "eth_method".to_owned(),
139 params: RequestParams::Array(vec![serde_json::Value::from(999)]),
140 }),
141 ]);
142
143 let obj = serde_json::to_string(&batch).unwrap();
144 assert_eq!(
145 obj,
146 r#"[{"jsonrpc":"2.0","method":"eth_method","params":[999,1337],"id":1},{"jsonrpc":"2.0","method":"eth_method","params":[999]}]"#
147 );
148 }
149
150 #[test]
151 fn can_deserialize_batch() {
152 let s = r#"[{}, {"jsonrpc": "2.0", "method": "eth_call", "params": [1337,420], "id": 1},{"jsonrpc": "2.0", "method": "notify", "params": [999]}]"#;
153 let obj: Request = serde_json::from_str(s).unwrap();
154 assert_eq!(
155 obj,
156 Request::Batch(vec![
157 RpcCall::Invalid { id: Id::Null },
158 RpcCall::MethodCall(RpcMethodCall {
159 jsonrpc: Version::V2,
160 method: "eth_call".to_owned(),
161 params: RequestParams::Array(vec![
162 serde_json::Value::from(1337),
163 serde_json::Value::from(420)
164 ]),
165 id: Id::Number(1)
166 }),
167 RpcCall::Notification(RpcNotification {
168 jsonrpc: Some(Version::V2),
169 method: "notify".to_owned(),
170 params: RequestParams::Array(vec![serde_json::Value::from(999)])
171 })
172 ])
173 )
174 }
175
176 #[test]
177 fn can_serialize_method() {
178 let m = RpcMethodCall {
179 jsonrpc: Version::V2,
180 method: "eth_method".to_owned(),
181 params: RequestParams::Array(vec![
182 serde_json::Value::from(999),
183 serde_json::Value::from(1337),
184 ]),
185 id: Id::Number(1),
186 };
187
188 let obj = serde_json::to_string(&m).unwrap();
189 assert_eq!(obj, r#"{"jsonrpc":"2.0","method":"eth_method","params":[999,1337],"id":1}"#);
190 }
191
192 #[test]
193 fn can_serialize_call_notification() {
194 let n = RpcCall::Notification(RpcNotification {
195 jsonrpc: Some(Version::V2),
196 method: "eth_method".to_owned(),
197 params: RequestParams::Array(vec![serde_json::Value::from(999)]),
198 });
199 let obj = serde_json::to_string(&n).unwrap();
200 assert_eq!(obj, r#"{"jsonrpc":"2.0","method":"eth_method","params":[999]}"#);
201 }
202
203 #[test]
204 fn can_serialize_notification() {
205 let n = RpcNotification {
206 jsonrpc: Some(Version::V2),
207 method: "eth_method".to_owned(),
208 params: RequestParams::Array(vec![
209 serde_json::Value::from(999),
210 serde_json::Value::from(1337),
211 ]),
212 };
213 let obj = serde_json::to_string(&n).unwrap();
214 assert_eq!(obj, r#"{"jsonrpc":"2.0","method":"eth_method","params":[999,1337]}"#);
215 }
216
217 #[test]
218 fn can_deserialize_notification() {
219 let s = r#"{"jsonrpc": "2.0", "method": "eth_method", "params": [999,1337]}"#;
220 let obj: RpcNotification = serde_json::from_str(s).unwrap();
221
222 assert_eq!(
223 obj,
224 RpcNotification {
225 jsonrpc: Some(Version::V2),
226 method: "eth_method".to_owned(),
227 params: RequestParams::Array(vec![
228 serde_json::Value::from(999),
229 serde_json::Value::from(1337)
230 ])
231 }
232 );
233 let s = r#"{"jsonrpc": "2.0", "method": "foobar"}"#;
234 let obj: RpcNotification = serde_json::from_str(s).unwrap();
235 assert_eq!(
236 obj,
237 RpcNotification {
238 jsonrpc: Some(Version::V2),
239 method: "foobar".to_owned(),
240 params: RequestParams::None,
241 }
242 );
243 let s = r#"{"jsonrpc": "2.0", "method": "eth_method", "params": [999,1337], "id": 1}"#;
244 let obj: Result<RpcNotification, _> = serde_json::from_str(s);
245 assert!(obj.is_err());
246 }
247
248 #[test]
249 fn can_deserialize_call() {
250 let s = r#"{"jsonrpc": "2.0", "method": "eth_method", "params": [999]}"#;
251 let obj: RpcCall = serde_json::from_str(s).unwrap();
252 assert_eq!(
253 obj,
254 RpcCall::Notification(RpcNotification {
255 jsonrpc: Some(Version::V2),
256 method: "eth_method".to_owned(),
257 params: RequestParams::Array(vec![serde_json::Value::from(999)])
258 })
259 );
260
261 let s = r#"{"jsonrpc": "2.0", "method": "eth_method", "params": [999], "id": 1}"#;
262 let obj: RpcCall = serde_json::from_str(s).unwrap();
263 assert_eq!(
264 obj,
265 RpcCall::MethodCall(RpcMethodCall {
266 jsonrpc: Version::V2,
267 method: "eth_method".to_owned(),
268 params: RequestParams::Array(vec![serde_json::Value::from(999)]),
269 id: Id::Number(1)
270 })
271 );
272
273 let s = r#"{"jsonrpc": "2.0", "method": "eth_method", "params": [], "id": 1}"#;
274 let obj: RpcCall = serde_json::from_str(s).unwrap();
275 assert_eq!(
276 obj,
277 RpcCall::MethodCall(RpcMethodCall {
278 jsonrpc: Version::V2,
279 method: "eth_method".to_owned(),
280 params: RequestParams::Array(vec![]),
281 id: Id::Number(1)
282 })
283 );
284
285 let s = r#"{"jsonrpc": "2.0", "method": "eth_method", "params": null, "id": 1}"#;
286 let obj: RpcCall = serde_json::from_str(s).unwrap();
287 assert_eq!(
288 obj,
289 RpcCall::MethodCall(RpcMethodCall {
290 jsonrpc: Version::V2,
291 method: "eth_method".to_owned(),
292 params: RequestParams::None,
293 id: Id::Number(1)
294 })
295 );
296
297 let s = r#"{"jsonrpc": "2.0", "method": "eth_method", "id": 1}"#;
298 let obj: RpcCall = serde_json::from_str(s).unwrap();
299 assert_eq!(
300 obj,
301 RpcCall::MethodCall(RpcMethodCall {
302 jsonrpc: Version::V2,
303 method: "eth_method".to_owned(),
304 params: RequestParams::None,
305 id: Id::Number(1)
306 })
307 );
308 }
309}