Skip to main content

lsp_max/
jsonrpc.rs

1//! A subset of JSON-RPC types used by the Language Server Protocol.
2
3pub(crate) use self::error::not_initialized_error;
4pub use self::error::{Error, ErrorCode, Result};
5pub use self::request::{Request, RequestBuilder};
6pub use self::response::Response;
7pub(crate) use self::router::Router;
8pub use self::router::{FromParams, IntoResponse, Method};
9
10use std::borrow::Cow;
11use std::fmt::{self, Debug, Display, Formatter};
12
13use lsp_types_max::NumberOrString;
14use serde::de::{self, Deserializer};
15use serde::ser::Serializer;
16use serde::{Deserialize, Serialize};
17
18pub mod base_protocol;
19mod error;
20mod request;
21mod response;
22mod router;
23
24/// A unique ID used to correlate requests and responses together.
25#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Deserialize, Serialize)]
26#[serde(untagged)]
27pub enum Id {
28    /// Numeric ID.
29    Number(i64),
30    /// String ID.
31    String(String),
32    /// Null ID.
33    ///
34    /// While `null` is considered a valid request ID by the JSON-RPC 2.0 specification, its use is
35    /// _strongly_ discouraged because the specification also uses a `null` value to indicate an
36    /// unknown ID in the [`Response`] object.
37    #[default]
38    Null,
39}
40
41impl Display for Id {
42    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
43        match self {
44            Id::Number(id) => Display::fmt(id, f),
45            Id::String(id) => Debug::fmt(id, f),
46            Id::Null => f.write_str("null"),
47        }
48    }
49}
50
51impl From<i64> for Id {
52    fn from(n: i64) -> Self {
53        Id::Number(n)
54    }
55}
56
57impl From<&'_ str> for Id {
58    fn from(s: &'_ str) -> Self {
59        Id::String(s.to_string())
60    }
61}
62
63impl From<String> for Id {
64    fn from(s: String) -> Self {
65        Id::String(s)
66    }
67}
68
69impl From<NumberOrString> for Id {
70    fn from(num_or_str: NumberOrString) -> Self {
71        match num_or_str {
72            NumberOrString::Number(num) => Id::Number(num as i64),
73            NumberOrString::String(s) => Id::String(s),
74        }
75    }
76}
77
78#[derive(Clone, Debug, PartialEq)]
79struct Version;
80
81impl<'de> Deserialize<'de> for Version {
82    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
83    where
84        D: Deserializer<'de>,
85    {
86        #[derive(Deserialize)]
87        struct Inner<'a>(#[serde(borrow)] Cow<'a, str>);
88
89        let Inner(ver) = Inner::deserialize(deserializer)?;
90
91        match ver.as_ref() {
92            "2.0" => Ok(Version),
93            _ => Err(de::Error::custom("expected JSON-RPC version \"2.0\"")),
94        }
95    }
96}
97
98impl Serialize for Version {
99    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
100    where
101        S: Serializer,
102    {
103        serializer.serialize_str("2.0")
104    }
105}
106
107/// An incoming or outgoing JSON-RPC message.
108#[derive(Deserialize, Serialize)]
109#[cfg_attr(test, derive(Debug, PartialEq))]
110#[serde(untagged)]
111pub(crate) enum Message {
112    /// A response message.
113    Response(Response),
114    /// A request or notification message.
115    Request(Request),
116}
117
118impl From<self::base_protocol::BaseProtocolMessage> for Message {
119    fn from(msg: self::base_protocol::BaseProtocolMessage) -> Self {
120        match msg {
121            self::base_protocol::BaseProtocolMessage::Request(r) => {
122                Message::Request(Request::from_message(r))
123            }
124            self::base_protocol::BaseProtocolMessage::Notification(n) => {
125                Message::Request(Request::from_notification_message(n))
126            }
127            self::base_protocol::BaseProtocolMessage::Response(r) => {
128                Message::Response(Response::from_message(r))
129            }
130        }
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use serde_json::json;
137
138    use super::*;
139
140    #[test]
141    fn incoming_from_str_or_value() {
142        let v = json!({"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{}},"id":0});
143        let from_str: Message = serde_json::from_str(&v.to_string()).unwrap();
144        let from_value: Message = serde_json::from_value(v).unwrap();
145        assert_eq!(from_str, from_value);
146    }
147
148    #[test]
149    fn outgoing_from_str_or_value() {
150        let v = json!({"jsonrpc":"2.0","result":{},"id":1});
151        let from_str: Message = serde_json::from_str(&v.to_string()).unwrap();
152        let from_value: Message = serde_json::from_value(v).unwrap();
153        assert_eq!(from_str, from_value);
154    }
155
156    #[test]
157    fn parses_incoming_message() {
158        let server_request =
159            json!({"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{}},"id":0});
160        let incoming = serde_json::from_value(server_request).unwrap();
161        assert!(matches!(incoming, Message::Request(_)));
162
163        let server_notif = json!({"jsonrpc":"2.0","method":"initialized","params":{}});
164        let incoming = serde_json::from_value(server_notif).unwrap();
165        assert!(matches!(incoming, Message::Request(_)));
166
167        let client_request = json!({"jsonrpc":"2.0","id":0,"result":[null]});
168        let incoming = serde_json::from_value(client_request).unwrap();
169        assert!(matches!(incoming, Message::Response(_)));
170    }
171
172    #[test]
173    fn parses_outgoing_message() {
174        let client_request = json!({"jsonrpc":"2.0","method":"workspace/configuration","params":{"scopeUri":null,"section":"foo"},"id":0});
175        let outgoing = serde_json::from_value(client_request).unwrap();
176        assert!(matches!(outgoing, Message::Request(_)));
177
178        let client_notif = json!({"jsonrpc":"2.0","method":"window/logMessage","params":{"message":"foo","type":0}});
179        let outgoing = serde_json::from_value(client_notif).unwrap();
180        assert!(matches!(outgoing, Message::Request(_)));
181
182        let server_response = json!({"jsonrpc":"2.0","id":0,"result":[null]});
183        let outgoing = serde_json::from_value(server_response).unwrap();
184        assert!(matches!(outgoing, Message::Response(_)));
185    }
186
187    #[test]
188    fn parses_invalid_server_request() {
189        let unknown_method = json!({"jsonrpc":"2.0","method":"foo"});
190        let incoming = serde_json::from_value(unknown_method).unwrap();
191        assert!(matches!(incoming, Message::Request(_)));
192
193        let unknown_method_with_id = json!({"jsonrpc":"2.0","method":"foo","id":0});
194        let incoming = serde_json::from_value(unknown_method_with_id).unwrap();
195        assert!(matches!(incoming, Message::Request(_)));
196
197        let missing_method = json!({"jsonrpc":"2.0"});
198        let incoming = serde_json::from_value(missing_method).unwrap();
199        assert!(matches!(incoming, Message::Request(_)));
200
201        let missing_method_with_id = json!({"jsonrpc":"2.0","id":0});
202        let incoming = serde_json::from_value(missing_method_with_id).unwrap();
203        assert!(matches!(incoming, Message::Request(_)));
204    }
205
206    #[test]
207    fn accepts_null_request_id() {
208        let request_id: Id = serde_json::from_value(json!(null)).unwrap();
209        assert_eq!(request_id, Id::Null);
210    }
211
212    #[test]
213    fn accepts_negative_integer_request_id() {
214        let request_id: Id = serde_json::from_value(json!(-1)).unwrap();
215        assert_eq!(request_id, Id::Number(-1));
216    }
217}