lsp_max/jsonrpc/
base_protocol.rs1use std::borrow::Cow;
7
8use lsp_types_max::{
9 NotificationMessage, NumberOrString, RequestMessage, ResponseError, ResponseMessage,
10};
11use serde_json::Value;
12
13use super::{Error, ErrorCode, Id, Request, Response};
14
15pub trait IntoTower {
17 type Target;
19 fn into_tower(self) -> Self::Target;
21}
22
23pub trait IntoLsp {
25 type Target;
27 fn into_lsp(self) -> Self::Target;
29}
30
31impl IntoTower for RequestMessage {
32 type Target = Request;
33
34 fn into_tower(self) -> Self::Target {
35 Request::build(self.method)
36 .id(Id::from(self.id))
37 .params(self.params.unwrap_or(Value::Null))
38 .finish()
39 }
40}
41
42impl IntoTower for NotificationMessage {
43 type Target = Request;
44
45 fn into_tower(self) -> Self::Target {
46 Request::build(self.method)
47 .params(self.params.unwrap_or(Value::Null))
48 .finish()
49 }
50}
51
52impl IntoTower for ResponseError {
53 type Target = Error;
54
55 fn into_tower(self) -> Self::Target {
56 Error {
57 code: ErrorCode::from(self.code as i64),
58 message: Cow::Owned(self.message),
59 data: self.data,
60 }
61 }
62}
63
64impl IntoTower for ResponseMessage {
65 type Target = Response;
66
67 fn into_tower(self) -> Self::Target {
68 match self {
69 ResponseMessage::Success { id, result, .. } => {
70 Response::from_ok(id.map(Id::from).unwrap_or(Id::Null), result)
71 }
72 ResponseMessage::Error { id, error, .. } => {
73 Response::from_error(id.map(Id::from).unwrap_or(Id::Null), error.into_tower())
74 }
75 }
76 }
77}
78
79impl IntoLsp for Error {
80 type Target = ResponseError;
81
82 fn into_lsp(self) -> Self::Target {
83 ResponseError {
84 code: self.code.code() as i32,
85 message: self.message.into_owned(),
86 data: self.data,
87 }
88 }
89}
90
91impl IntoLsp for Response {
92 type Target = ResponseMessage;
93
94 fn into_lsp(self) -> Self::Target {
95 let (id, result) = self.into_parts();
96 match result {
97 Ok(result) => ResponseMessage::Success {
98 jsonrpc: "2.0".to_string(),
99 id: tower_id_to_lsp(id),
100 result,
101 },
102 Err(error) => ResponseMessage::Error {
103 jsonrpc: "2.0".to_string(),
104 id: tower_id_to_lsp(id),
105 error: error.into_lsp(),
106 },
107 }
108 }
109}
110
111fn tower_id_to_lsp(id: Id) -> Option<NumberOrString> {
113 match id {
114 Id::Number(n) => Some(NumberOrString::Number(n as i32)),
115 Id::String(s) => Some(NumberOrString::String(s)),
116 Id::Null => None,
117 }
118}
119
120#[derive(Debug, Clone, PartialEq)]
125pub enum BaseProtocolMessage {
126 Request(RequestMessage),
128 Notification(NotificationMessage),
130 Response(ResponseMessage),
132}
133
134impl BaseProtocolMessage {
135 pub fn from_request(request: Request) -> Self {
139 let (method, id, params) = request.into_parts();
140 if let Some(id) = id {
141 BaseProtocolMessage::Request(RequestMessage {
142 jsonrpc: "2.0".to_string(),
143 id: match id {
144 Id::Number(n) => NumberOrString::Number(n as i32),
145 Id::String(s) => NumberOrString::String(s),
146 Id::Null => NumberOrString::Number(0), },
148 method: method.into_owned(),
149 params,
150 })
151 } else {
152 BaseProtocolMessage::Notification(NotificationMessage {
153 jsonrpc: "2.0".to_string(),
154 method: method.into_owned(),
155 params,
156 })
157 }
158 }
159
160 pub fn from_response(response: Response) -> Self {
162 BaseProtocolMessage::Response(response.into_lsp())
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use serde_json::json;
170
171 #[test]
172 fn test_request_message_bridge() {
173 let lsp_req = RequestMessage {
174 jsonrpc: "2.0".to_string(),
175 id: NumberOrString::Number(42),
176 method: "test/method".to_string(),
177 params: Some(json!({"foo": "bar"})),
178 };
179
180 let tower_req = lsp_req.clone().into_tower();
181 assert_eq!(tower_req.method(), "test/method");
182 assert_eq!(tower_req.id(), Some(&Id::Number(42)));
183 assert_eq!(tower_req.params(), Some(&json!({"foo": "bar"})));
184
185 let bridge_msg = BaseProtocolMessage::from_request(tower_req);
186 if let BaseProtocolMessage::Request(back) = bridge_msg {
187 assert_eq!(back.id, lsp_req.id);
188 assert_eq!(back.method, lsp_req.method);
189 assert_eq!(back.params, lsp_req.params);
190 } else {
191 panic!("Expected RequestMessage variant");
192 }
193 }
194
195 #[test]
196 fn test_notification_message_bridge() {
197 let lsp_notif = NotificationMessage {
198 jsonrpc: "2.0".to_string(),
199 method: "test/notify".to_string(),
200 params: Some(json!([1, 2, 3])),
201 };
202
203 let tower_req = lsp_notif.clone().into_tower();
204 assert_eq!(tower_req.method(), "test/notify");
205 assert_eq!(tower_req.id(), None);
206 assert_eq!(tower_req.params(), Some(&json!([1, 2, 3])));
207
208 let bridge_msg = BaseProtocolMessage::from_request(tower_req);
209 if let BaseProtocolMessage::Notification(back) = bridge_msg {
210 assert_eq!(back.method, lsp_notif.method);
211 assert_eq!(back.params, lsp_notif.params);
212 } else {
213 panic!("Expected NotificationMessage variant");
214 }
215 }
216
217 #[test]
218 fn test_response_message_bridge() {
219 let lsp_res = ResponseMessage::Success {
220 jsonrpc: "2.0".to_string(),
221 id: Some(NumberOrString::String("req-1".to_string())),
222 result: json!({"status": "ok"}),
223 };
224
225 let tower_res = lsp_res.clone().into_tower();
226 assert_eq!(tower_res.id(), &Id::String("req-1".to_string()));
227 assert_eq!(tower_res.result(), Some(&json!({"status": "ok"})));
228
229 let bridge_msg = BaseProtocolMessage::from_response(tower_res);
230 if let BaseProtocolMessage::Response(back) = bridge_msg {
231 assert_eq!(back, lsp_res);
232 } else {
233 panic!("Expected ResponseMessage variant");
234 }
235 }
236
237 #[test]
238 fn test_error_bridge() {
239 let lsp_err = ResponseError {
240 code: -32601,
241 message: "Method not found".to_string(),
242 data: None,
243 };
244
245 let tower_err: Error = lsp_err.clone().into_tower();
246 assert_eq!(tower_err.code, ErrorCode::MethodNotFound);
247 assert_eq!(tower_err.message, "Method not found");
248
249 let back_lsp_err = tower_err.into_lsp();
250 assert_eq!(back_lsp_err, lsp_err);
251 }
252}