opencore_jsonrpc_rust/
protocol.rs

1//! JSON-RPC protocol types for request/response communication.
2//!
3//! This module defines the core protocol structures used for communication
4//! between the TypeScript framework and Rust applications.
5
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9/// A JSON-RPC request from the client.
10///
11/// # Fields
12///
13/// * `id` - Unique identifier for the request, used to match responses
14/// * `action` - The name of the action/method to invoke
15/// * `params` - Array of JSON values representing the parameters
16///
17/// # Example JSON
18///
19/// ```json
20/// {
21///   "id": "req-123",
22///   "action": "sum",
23///   "params": [5, 10]
24/// }
25/// ```
26#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
27pub struct Request {
28    pub id: String,
29    pub action: String,
30    pub params: Vec<Value>,
31}
32
33/// A JSON-RPC response to the client.
34///
35/// Responses are tagged with a `status` field that indicates success or failure.
36///
37/// # Variants
38///
39/// * `Ok` - Successful response with a result value
40/// * `Error` - Error response with an error message
41///
42/// # Example JSON (Success)
43///
44/// ```json
45/// {
46///   "status": "ok",
47///   "id": "req-123",
48///   "result": 15
49/// }
50/// ```
51///
52/// # Example JSON (Error)
53///
54/// ```json
55/// {
56///   "status": "error",
57///   "id": "req-123",
58///   "error": "Invalid parameters"
59/// }
60/// ```
61#[derive(Debug, Serialize, Clone, PartialEq)]
62#[serde(tag = "status")]
63pub enum Response {
64    /// Successful response containing the result
65    #[serde(rename = "ok")]
66    Ok {
67        /// Request ID this response corresponds to
68        id: String,
69        /// The result value
70        result: Value,
71    },
72
73    /// Error response containing an error message
74    #[serde(rename = "error")]
75    Error {
76        /// Request ID this response corresponds to
77        id: String,
78        /// Human-readable error message
79        error: String,
80    },
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use serde_json::json;
87
88    #[test]
89    fn test_request_deserialization() {
90        let json_str = r#"{"id":"req-123","action":"sum","params":[5,10]}"#;
91        let req: Request = serde_json::from_str(json_str).unwrap();
92
93        assert_eq!(req.id, "req-123");
94        assert_eq!(req.action, "sum");
95        assert_eq!(req.params.len(), 2);
96        assert_eq!(req.params[0], json!(5));
97        assert_eq!(req.params[1], json!(10));
98    }
99
100    #[test]
101    fn test_request_with_empty_params() {
102        let json_str = r#"{"id":"req-456","action":"ping","params":[]}"#;
103        let req: Request = serde_json::from_str(json_str).unwrap();
104
105        assert_eq!(req.id, "req-456");
106        assert_eq!(req.action, "ping");
107        assert_eq!(req.params.len(), 0);
108    }
109
110    #[test]
111    fn test_response_ok_serialization() {
112        let response = Response::Ok {
113            id: "req-123".to_string(),
114            result: json!(15),
115        };
116
117        let json_str = serde_json::to_string(&response).unwrap();
118        let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
119
120        assert_eq!(parsed["status"], "ok");
121        assert_eq!(parsed["id"], "req-123");
122        assert_eq!(parsed["result"], 15);
123    }
124
125    #[test]
126    fn test_response_error_serialization() {
127        let response = Response::Error {
128            id: "req-456".to_string(),
129            error: "Invalid parameters".to_string(),
130        };
131
132        let json_str = serde_json::to_string(&response).unwrap();
133        let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
134
135        assert_eq!(parsed["status"], "error");
136        assert_eq!(parsed["id"], "req-456");
137        assert_eq!(parsed["error"], "Invalid parameters");
138    }
139
140    #[test]
141    fn test_request_clone() {
142        let req = Request {
143            id: "req-789".to_string(),
144            action: "test".to_string(),
145            params: vec![json!(1), json!(2)],
146        };
147
148        let cloned = req.clone();
149        assert_eq!(req, cloned);
150    }
151
152    #[test]
153    fn test_response_clone() {
154        let response = Response::Ok {
155            id: "req-999".to_string(),
156            result: json!("success"),
157        };
158
159        let cloned = response.clone();
160        assert_eq!(response, cloned);
161    }
162}