ricecoder_external_lsp/client/
protocol.rs1use serde::{Deserialize, Serialize};
4#[allow(unused_imports)]
5use serde_json::{json, Value};
6use std::sync::atomic::{AtomicU64, Ordering};
7use std::sync::Arc;
8
9pub type RequestId = u64;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct JsonRpcRequest {
15 pub jsonrpc: String,
17 pub method: String,
19 #[serde(skip_serializing_if = "Option::is_none")]
21 pub params: Option<Value>,
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub id: Option<RequestId>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct JsonRpcResponse {
30 pub jsonrpc: String,
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub result: Option<Value>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub error: Option<JsonRpcError>,
38 pub id: RequestId,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct JsonRpcError {
45 pub code: i32,
47 pub message: String,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub data: Option<Value>,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct JsonRpcNotification {
57 pub jsonrpc: String,
59 pub method: String,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub params: Option<Value>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68#[serde(untagged)]
69pub enum JsonRpcMessage {
70 Request(JsonRpcRequest),
72 Response(JsonRpcResponse),
74 Notification(JsonRpcNotification),
76}
77
78pub struct JsonRpcHandler {
80 next_id: Arc<AtomicU64>,
82}
83
84impl JsonRpcHandler {
85 pub fn new() -> Self {
87 Self {
88 next_id: Arc::new(AtomicU64::new(1)),
89 }
90 }
91
92 pub fn next_request_id(&self) -> RequestId {
94 self.next_id.fetch_add(1, Ordering::SeqCst)
95 }
96
97 pub fn create_request(
99 &self,
100 method: impl Into<String>,
101 params: Option<Value>,
102 ) -> JsonRpcRequest {
103 JsonRpcRequest {
104 jsonrpc: "2.0".to_string(),
105 method: method.into(),
106 params,
107 id: Some(self.next_request_id()),
108 }
109 }
110
111 pub fn create_notification(
113 &self,
114 method: impl Into<String>,
115 params: Option<Value>,
116 ) -> JsonRpcNotification {
117 JsonRpcNotification {
118 jsonrpc: "2.0".to_string(),
119 method: method.into(),
120 params,
121 }
122 }
123
124 pub fn serialize_request(&self, request: &JsonRpcRequest) -> crate::error::Result<String> {
126 serde_json::to_string(request)
127 .map_err(|e| crate::error::ExternalLspError::ProtocolError(e.to_string()))
128 }
129
130 pub fn serialize_notification(&self, notification: &JsonRpcNotification) -> crate::error::Result<String> {
132 serde_json::to_string(notification)
133 .map_err(|e| crate::error::ExternalLspError::ProtocolError(e.to_string()))
134 }
135
136 pub fn parse_response(&self, json: &str) -> crate::error::Result<JsonRpcResponse> {
138 serde_json::from_str(json)
139 .map_err(|e| crate::error::ExternalLspError::ProtocolError(format!("Failed to parse response: {}", e)))
140 }
141
142 pub fn parse_notification(&self, json: &str) -> crate::error::Result<JsonRpcNotification> {
144 serde_json::from_str(json)
145 .map_err(|e| crate::error::ExternalLspError::ProtocolError(format!("Failed to parse notification: {}", e)))
146 }
147
148 pub fn parse_message(&self, json: &str) -> crate::error::Result<JsonRpcMessage> {
150 serde_json::from_str(json)
151 .map_err(|e| crate::error::ExternalLspError::ProtocolError(format!("Failed to parse message: {}", e)))
152 }
153
154 pub fn is_error_response(response: &JsonRpcResponse) -> bool {
156 response.error.is_some()
157 }
158
159 pub fn extract_error_message(response: &JsonRpcResponse) -> Option<String> {
161 response.error.as_ref().map(|e| e.message.clone())
162 }
163
164 pub fn create_error_response(
166 id: RequestId,
167 code: i32,
168 message: impl Into<String>,
169 ) -> JsonRpcResponse {
170 JsonRpcResponse {
171 jsonrpc: "2.0".to_string(),
172 result: None,
173 error: Some(JsonRpcError {
174 code,
175 message: message.into(),
176 data: None,
177 }),
178 id,
179 }
180 }
181}
182
183impl Default for JsonRpcHandler {
184 fn default() -> Self {
185 Self::new()
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_create_request() {
195 let handler = JsonRpcHandler::new();
196 let request = handler.create_request("initialize", Some(json!({"processId": 1234})));
197
198 assert_eq!(request.jsonrpc, "2.0");
199 assert_eq!(request.method, "initialize");
200 assert!(request.id.is_some());
201 assert!(request.params.is_some());
202 }
203
204 #[test]
205 fn test_create_notification() {
206 let handler = JsonRpcHandler::new();
207 let notification = handler.create_notification("initialized", None);
208
209 assert_eq!(notification.jsonrpc, "2.0");
210 assert_eq!(notification.method, "initialized");
211 assert!(notification.params.is_none());
212 }
213
214 #[test]
215 fn test_serialize_request() {
216 let handler = JsonRpcHandler::new();
217 let request = handler.create_request("test", None);
218 let json = handler.serialize_request(&request).unwrap();
219
220 assert!(json.contains("\"jsonrpc\":\"2.0\""));
221 assert!(json.contains("\"method\":\"test\""));
222 }
223
224 #[test]
225 fn test_parse_response() {
226 let handler = JsonRpcHandler::new();
227 let json = r#"{"jsonrpc":"2.0","result":{"key":"value"},"id":1}"#;
228 let response = handler.parse_response(json).unwrap();
229
230 assert_eq!(response.jsonrpc, "2.0");
231 assert_eq!(response.id, 1);
232 assert!(response.result.is_some());
233 assert!(response.error.is_none());
234 }
235
236 #[test]
237 fn test_parse_error_response() {
238 let handler = JsonRpcHandler::new();
239 let json = r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request"},"id":1}"#;
240 let response = handler.parse_response(json).unwrap();
241
242 assert_eq!(response.jsonrpc, "2.0");
243 assert_eq!(response.id, 1);
244 assert!(response.result.is_none());
245 assert!(response.error.is_some());
246 assert_eq!(response.error.unwrap().code, -32600);
247 }
248
249 #[test]
250 fn test_request_id_increments() {
251 let handler = JsonRpcHandler::new();
252 let id1 = handler.next_request_id();
253 let id2 = handler.next_request_id();
254 let id3 = handler.next_request_id();
255
256 assert_eq!(id1, 1);
257 assert_eq!(id2, 2);
258 assert_eq!(id3, 3);
259 }
260
261 #[test]
262 fn test_is_error_response() {
263 let error_response = JsonRpcResponse {
264 jsonrpc: "2.0".to_string(),
265 result: None,
266 error: Some(JsonRpcError {
267 code: -32600,
268 message: "Invalid Request".to_string(),
269 data: None,
270 }),
271 id: 1,
272 };
273
274 assert!(JsonRpcHandler::is_error_response(&error_response));
275
276 let success_response = JsonRpcResponse {
277 jsonrpc: "2.0".to_string(),
278 result: Some(json!({"key": "value"})),
279 error: None,
280 id: 1,
281 };
282
283 assert!(!JsonRpcHandler::is_error_response(&success_response));
284 }
285}