use serde::{Deserialize, Serialize}; use serde_json::Value; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Request { pub jsonrpc: String, pub id: serde_json::Value, pub method: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub params: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Notification { pub jsonrpc: String, pub method: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub params: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Response { pub jsonrpc: String, pub id: serde_json::Value, #[serde(default, skip_serializing_if = "Option::is_none")] pub result: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub error: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RpcError { pub code: i32, pub message: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub data: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum Incoming { Request(Request), Response(Response), Notification(Notification), } pub const JSONRPC_VERSION: &str = "2.0"; pub fn request(id: u64, method: &str, params: Option) -> Request { Request { jsonrpc: JSONRPC_VERSION.into(), id: serde_json::json!(id), method: method.into(), params, } } pub fn notification(method: &str, params: Option) -> Notification { Notification { jsonrpc: JSONRPC_VERSION.into(), method: method.into(), params, } } pub fn ok_response(id: serde_json::Value, result: Value) -> Response { Response { jsonrpc: JSONRPC_VERSION.into(), id, result: Some(result), error: None, } } pub fn err_response(id: serde_json::Value, code: i32, message: String) -> Response { Response { jsonrpc: JSONRPC_VERSION.into(), id, result: None, error: Some(RpcError { code, message, data: None, }), } } #[cfg(test)] mod tests { use super::*; #[test] fn request_round_trip() { let r = request(7, "list", None); let s = serde_json::to_string(&r).unwrap(); let back: Request = serde_json::from_str(&s).unwrap(); assert_eq!(back.method, "list"); assert_eq!(back.id, serde_json::json!(7)); } #[test] fn incoming_is_response() { let s = r#"{"jsonrpc":"2.0","id":1,"result":{"ok":true}}"#; let i: Incoming = serde_json::from_str(s).unwrap(); assert!(matches!(i, Incoming::Response(_))); } #[test] fn incoming_is_notification() { let s = r#"{"jsonrpc":"2.0","method":"log","params":{}}"#; let i: Incoming = serde_json::from_str(s).unwrap(); assert!(matches!(i, Incoming::Notification(_))); } }