openzeppelin_relayer/models/rpc/
json_rpc.rs1use serde::{Deserialize, Serialize};
6use utoipa::ToSchema;
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
12#[serde(untagged)]
13pub enum JsonRpcId {
14 String(String),
16 Number(i64),
18}
19
20impl JsonRpcId {
21 pub fn number(n: i64) -> Self {
23 JsonRpcId::Number(n)
24 }
25
26 pub fn string<S: Into<String>>(s: S) -> Self {
28 JsonRpcId::String(s.into())
29 }
30
31 pub fn as_number(&self) -> Option<i64> {
33 match self {
34 JsonRpcId::Number(n) => Some(*n),
35 _ => None,
36 }
37 }
38
39 pub fn as_string(&self) -> Option<&str> {
41 match self {
42 JsonRpcId::String(s) => Some(s),
43 _ => None,
44 }
45 }
46}
47
48impl From<i64> for JsonRpcId {
49 fn from(n: i64) -> Self {
50 JsonRpcId::Number(n)
51 }
52}
53
54impl From<u64> for JsonRpcId {
55 fn from(n: u64) -> Self {
56 JsonRpcId::Number(n as i64)
57 }
58}
59
60impl From<String> for JsonRpcId {
61 fn from(s: String) -> Self {
62 JsonRpcId::String(s)
63 }
64}
65
66impl From<&str> for JsonRpcId {
67 fn from(s: &str) -> Self {
68 JsonRpcId::String(s.to_string())
69 }
70}
71
72#[derive(Serialize, Deserialize, ToSchema)]
78pub struct JsonRpcRequest<T> {
79 pub jsonrpc: String,
80 #[serde(flatten)]
81 pub params: T,
82 #[serde(default)]
83 pub id: Option<JsonRpcId>,
84}
85
86#[derive(Debug, Serialize, Deserialize, ToSchema)]
90pub struct JsonRpcResponse<T> {
91 pub jsonrpc: String,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 #[schema(nullable = false)]
94 pub result: Option<T>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 #[schema(nullable = false)]
97 pub error: Option<JsonRpcError>,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 #[schema(nullable = false)]
100 pub id: Option<JsonRpcId>,
101}
102
103impl<T> JsonRpcResponse<T> {
104 pub fn result(id: Option<JsonRpcId>, result: T) -> Self {
113 Self {
114 jsonrpc: "2.0".to_string(),
115 result: Some(result),
116 error: None,
117 id,
118 }
119 }
120
121 pub fn error(code: i32, message: &str, description: &str) -> Self {
131 Self {
132 jsonrpc: "2.0".to_string(),
133 result: None,
134 error: Some(JsonRpcError {
135 code,
136 message: message.to_string(),
137 description: description.to_string(),
138 }),
139 id: None,
140 }
141 }
142}
143
144#[derive(Debug, Serialize, Deserialize, ToSchema)]
148pub struct JsonRpcError {
149 pub code: i32,
150 pub message: String,
151 pub description: String,
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use serde_json::json;
158
159 #[test]
160 fn test_json_rpc_id_serialization() {
161 let id_number = JsonRpcId::Number(42);
163 let serialized = serde_json::to_value(&id_number).unwrap();
164 assert_eq!(serialized, json!(42));
165
166 let id_string = JsonRpcId::String("test-id".to_string());
168 let serialized = serde_json::to_value(&id_string).unwrap();
169 assert_eq!(serialized, json!("test-id"));
170 }
171
172 #[test]
173 fn test_json_rpc_id_deserialization() {
174 let id: JsonRpcId = serde_json::from_value(json!(123)).unwrap();
176 assert_eq!(id, JsonRpcId::Number(123));
177
178 let id: JsonRpcId = serde_json::from_value(json!("example-id")).unwrap();
180 assert_eq!(id, JsonRpcId::String("example-id".to_string()));
181 }
182
183 #[test]
184 fn test_json_rpc_id_helper_methods() {
185 let number_id = JsonRpcId::Number(100);
186 assert_eq!(number_id.as_number(), Some(100));
187 assert_eq!(number_id.as_string(), None);
188
189 let string_id = JsonRpcId::String("hello".to_string());
190 assert_eq!(string_id.as_number(), None);
191 assert_eq!(string_id.as_string(), Some("hello"));
192 }
193
194 #[test]
195 fn test_json_rpc_id_from_implementations() {
196 let id: JsonRpcId = 42i64.into();
198 assert_eq!(id, JsonRpcId::Number(42));
199
200 let id: JsonRpcId = 42u64.into();
202 assert_eq!(id, JsonRpcId::Number(42));
203
204 let id: JsonRpcId = "test".to_string().into();
206 assert_eq!(id, JsonRpcId::String("test".to_string()));
207
208 let id: JsonRpcId = "test".into();
210 assert_eq!(id, JsonRpcId::String("test".to_string()));
211 }
212
213 #[test]
214 fn test_json_rpc_request_with_different_id_types() {
215 let request_with_number = JsonRpcRequest {
217 jsonrpc: "2.0".to_string(),
218 params: json!({"method": "test"}),
219 id: Some(JsonRpcId::Number(1)),
220 };
221 let serialized = serde_json::to_value(&request_with_number).unwrap();
222 assert_eq!(serialized["id"], json!(1));
223
224 let request_with_string = JsonRpcRequest {
226 jsonrpc: "2.0".to_string(),
227 params: json!({"method": "test"}),
228 id: Some(JsonRpcId::String("abc123".to_string())),
229 };
230 let serialized = serde_json::to_value(&request_with_string).unwrap();
231 assert_eq!(serialized["id"], json!("abc123"));
232
233 let request_with_null = JsonRpcRequest {
235 jsonrpc: "2.0".to_string(),
236 params: json!({"method": "test"}),
237 id: None,
238 };
239 let serialized = serde_json::to_value(&request_with_null).unwrap();
240 assert_eq!(serialized["id"], json!(null));
241 assert!(serialized.as_object().unwrap().contains_key("id")); }
243
244 #[test]
245 fn test_json_rpc_request_deserialization_with_option() {
246 let json_with_number = json!({
248 "jsonrpc": "2.0",
249 "method": "test",
250 "id": 42
251 });
252 let request: JsonRpcRequest<serde_json::Value> =
253 serde_json::from_value(json_with_number).unwrap();
254 assert_eq!(request.id, Some(JsonRpcId::Number(42)));
255
256 let json_with_string = json!({
258 "jsonrpc": "2.0",
259 "method": "test",
260 "id": "req-123"
261 });
262 let request: JsonRpcRequest<serde_json::Value> =
263 serde_json::from_value(json_with_string).unwrap();
264 assert_eq!(request.id, Some(JsonRpcId::String("req-123".to_string())));
265
266 let json_with_null = json!({
268 "jsonrpc": "2.0",
269 "method": "test",
270 "id": null
271 });
272 let request: JsonRpcRequest<serde_json::Value> =
273 serde_json::from_value(json_with_null).unwrap();
274 assert_eq!(request.id, None);
275
276 let json_notification = json!({
278 "jsonrpc": "2.0",
279 "method": "test"
280 });
281 let request: JsonRpcRequest<serde_json::Value> =
282 serde_json::from_value(json_notification).unwrap();
283 assert_eq!(request.id, None);
284 }
285
286 #[test]
287 fn test_option_json_rpc_id_serialization() {
288 let id_some_number = Some(JsonRpcId::Number(100));
290 let serialized = serde_json::to_value(&id_some_number).unwrap();
291 assert_eq!(serialized, json!(100));
292
293 let id_some_string = Some(JsonRpcId::String("test".to_string()));
295 let serialized = serde_json::to_value(&id_some_string).unwrap();
296 assert_eq!(serialized, json!("test"));
297
298 let id_none: Option<JsonRpcId> = None;
300 let serialized = serde_json::to_value(&id_none).unwrap();
301 assert_eq!(serialized, json!(null));
302 }
303
304 #[test]
305 fn test_json_rpc_response_with_option_id() {
306 let response_with_number =
308 JsonRpcResponse::result(Some(JsonRpcId::Number(42)), json!("success"));
309 assert_eq!(response_with_number.id, Some(JsonRpcId::Number(42)));
310
311 let response_with_string = JsonRpcResponse::result(
313 Some(JsonRpcId::String("req-123".to_string())),
314 json!("success"),
315 );
316 assert_eq!(
317 response_with_string.id,
318 Some(JsonRpcId::String("req-123".to_string()))
319 );
320
321 let response_with_null = JsonRpcResponse::result(None, json!("success"));
323 assert_eq!(response_with_null.id, None);
324 }
325}