tower_lsp/
jsonrpc.rs

1//! A subset of JSON-RPC types used by the Language Server Protocol.
2
3pub use self::error::{Error, ErrorCode};
4pub use self::router::{FromParams, IntoResponse, Method};
5
6pub(crate) use self::router::Router;
7
8use std::borrow::Cow;
9use std::fmt::{self, Debug, Display, Formatter};
10
11use lsp_types::NumberOrString;
12use serde::de::{self, Deserializer};
13use serde::ser::Serializer;
14use serde::{Deserialize, Serialize};
15use serde_json::Value;
16
17mod error;
18mod router;
19
20/// A specialized [`Result`] error type for JSON-RPC handlers.
21///
22/// [`Result`]: enum@std::result::Result
23pub type Result<T> = std::result::Result<T, Error>;
24
25/// A unique ID used to correlate requests and responses together.
26#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
27#[serde(untagged)]
28#[derive(Default)]
29pub enum Id {
30    /// Numeric ID.
31    Number(i64),
32    /// String ID.
33    String(String),
34    /// Null ID.
35    ///
36    /// While `null` is considered a valid request ID by the JSON-RPC 2.0 specification, its use is
37    /// _strongly_ discouraged because the specification also uses a `null` value to indicate an
38    /// unknown ID in the [`Response`] object.
39    #[default]
40    Null,
41}
42
43impl Display for Id {
44    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
45        match self {
46            Id::Number(id) => Display::fmt(id, f),
47            Id::String(id) => Debug::fmt(id, f),
48            Id::Null => f.write_str("null"),
49        }
50    }
51}
52
53impl From<i64> for Id {
54    fn from(n: i64) -> Self {
55        Id::Number(n)
56    }
57}
58
59impl From<&'_ str> for Id {
60    fn from(s: &'_ str) -> Self {
61        Id::String(s.to_string())
62    }
63}
64
65impl From<String> for Id {
66    fn from(s: String) -> Self {
67        Id::String(s)
68    }
69}
70
71impl From<NumberOrString> for Id {
72    fn from(num_or_str: NumberOrString) -> Self {
73        match num_or_str {
74            NumberOrString::Number(num) => Id::Number(num as i64),
75            NumberOrString::String(s) => Id::String(s),
76        }
77    }
78}
79
80fn deserialize_some<'de, T, D>(deserializer: D) -> std::result::Result<Option<T>, D::Error>
81where
82    T: Deserialize<'de>,
83    D: Deserializer<'de>,
84{
85    T::deserialize(deserializer).map(Some)
86}
87
88/// A JSON-RPC request or notification.
89#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
90pub struct Request {
91    jsonrpc: Version,
92    #[serde(default)]
93    method: Cow<'static, str>,
94    #[serde(default, deserialize_with = "deserialize_some")]
95    #[serde(skip_serializing_if = "Option::is_none")]
96    params: Option<Value>,
97    #[serde(default, deserialize_with = "deserialize_some")]
98    #[serde(skip_serializing_if = "Option::is_none")]
99    id: Option<Id>,
100}
101
102impl Request {
103    /// Starts building a JSON-RPC method call.
104    ///
105    /// Returns a `RequestBuilder`, which allows setting the `params` field or adding a request ID.
106    pub fn build<M>(method: M) -> RequestBuilder
107    where
108        M: Into<Cow<'static, str>>,
109    {
110        RequestBuilder {
111            method: method.into(),
112            params: None,
113            id: None,
114        }
115    }
116
117    /// Constructs a JSON-RPC request from its corresponding LSP type.
118    pub(crate) fn from_request<R>(id: Id, params: R::Params) -> Self
119    where
120        R: lsp_types::request::Request,
121    {
122        // Since `R::Params` come from the `lsp-types` crate and validity is enforced via the
123        // `Request` trait, the `unwrap()` call below should never fail.
124        Request {
125            jsonrpc: Version,
126            method: R::METHOD.into(),
127            params: Some(serde_json::to_value(params).unwrap()),
128            id: Some(id),
129        }
130    }
131
132    /// Constructs a JSON-RPC notification from its corresponding LSP type.
133    pub(crate) fn from_notification<N>(params: N::Params) -> Self
134    where
135        N: lsp_types::notification::Notification,
136    {
137        // Since `N::Params` comes from the `lsp-types` crate and validity is enforced via the
138        // `Notification` trait, the `unwrap()` call below should never fail.
139        Request {
140            jsonrpc: Version,
141            method: N::METHOD.into(),
142            params: Some(serde_json::to_value(params).unwrap()),
143            id: None,
144        }
145    }
146
147    /// Returns the name of the method to be invoked.
148    #[inline]
149    pub fn method(&self) -> &str {
150        self.method.as_ref()
151    }
152
153    /// Returns the unique ID of this request, if present.
154    #[inline]
155    pub fn id(&self) -> Option<&Id> {
156        self.id.as_ref()
157    }
158
159    /// Returns the `params` field, if present.
160    #[inline]
161    pub fn params(&self) -> Option<&Value> {
162        self.params.as_ref()
163    }
164
165    /// Splits this request into the method name, request ID, and the `params` field, if present.
166    #[inline]
167    pub fn into_parts(self) -> (Cow<'static, str>, Option<Id>, Option<Value>) {
168        (self.method, self.id, self.params)
169    }
170}
171
172impl Display for Request {
173    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
174        let mut w = WriterFormatter { inner: f };
175        serde_json::to_writer(&mut w, self).map_err(|_| fmt::Error)
176    }
177}
178
179struct WriterFormatter<'a, 'b: 'a> {
180    inner: &'a mut Formatter<'b>,
181}
182
183impl<'a, 'b> std::io::Write for WriterFormatter<'a, 'b> {
184    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
185        fn io_error<E>(_: E) -> std::io::Error {
186            // Error value does not matter because fmt::Display impl below just
187            // maps it to fmt::Error
188            std::io::Error::new(std::io::ErrorKind::Other, "fmt error")
189        }
190        let s = std::str::from_utf8(buf).map_err(io_error)?;
191        self.inner.write_str(s).map_err(io_error)?;
192        Ok(buf.len())
193    }
194
195    fn flush(&mut self) -> std::io::Result<()> {
196        Ok(())
197    }
198}
199
200/// A builder to construct the properties of a `Request`.
201///
202/// To construct a `RequestBuilder`, refer to [`Request::build`].
203#[derive(Debug)]
204pub struct RequestBuilder {
205    method: Cow<'static, str>,
206    params: Option<Value>,
207    id: Option<Id>,
208}
209
210impl RequestBuilder {
211    /// Sets the `id` member of the request to the given value.
212    ///
213    /// If this method is not called, the resulting `Request` will be assumed to be a notification.
214    pub fn id<I: Into<Id>>(mut self, id: I) -> Self {
215        self.id = Some(id.into());
216        self
217    }
218
219    /// Sets the `params` member of the request to the given value.
220    ///
221    /// This member is omitted from the request by default.
222    pub fn params<V: Into<Value>>(mut self, params: V) -> Self {
223        self.params = Some(params.into());
224        self
225    }
226
227    /// Constructs the JSON-RPC request and returns it.
228    pub fn finish(self) -> Request {
229        Request {
230            jsonrpc: Version,
231            method: self.method,
232            params: self.params,
233            id: self.id,
234        }
235    }
236}
237
238/// A successful or failed JSON-RPC response.
239#[derive(Clone, PartialEq, Deserialize, Serialize)]
240pub struct Response {
241    jsonrpc: Version,
242    #[serde(flatten)]
243    kind: ResponseKind,
244    id: Id,
245}
246
247impl Response {
248    /// Creates a new successful response from a request ID and `Error` object.
249    #[inline]
250    pub const fn from_ok(id: Id, result: Value) -> Self {
251        Response {
252            jsonrpc: Version,
253            kind: ResponseKind::Ok { result },
254            id,
255        }
256    }
257
258    /// Creates a new error response from a request ID and `Error` object.
259    #[inline]
260    pub const fn from_error(id: Id, error: Error) -> Self {
261        Response {
262            jsonrpc: Version,
263            kind: ResponseKind::Err { error },
264            id,
265        }
266    }
267
268    /// Creates a new response from a request ID and either an `Ok(Value)` or `Err(Error)` body.
269    pub fn from_parts(id: Id, body: Result<Value>) -> Self {
270        match body {
271            Ok(result) => Response::from_ok(id, result),
272            Err(error) => Response::from_error(id, error),
273        }
274    }
275
276    /// Splits the response into a request ID paired with either an `Ok(Value)` or `Err(Error)` to
277    /// signify whether the response is a success or failure.
278    pub fn into_parts(self) -> (Id, Result<Value>) {
279        match self.kind {
280            ResponseKind::Ok { result } => (self.id, Ok(result)),
281            ResponseKind::Err { error } => (self.id, Err(error)),
282        }
283    }
284
285    /// Returns `true` if the response indicates success.
286    #[inline]
287    pub const fn is_ok(&self) -> bool {
288        matches!(self.kind, ResponseKind::Ok { .. })
289    }
290
291    /// Returns `true` if the response indicates failure.
292    #[inline]
293    pub const fn is_error(&self) -> bool {
294        !self.is_ok()
295    }
296
297    /// Returns the `result` value, if it exists.
298    ///
299    /// This member only exists if the response indicates success.
300    #[inline]
301    pub const fn result(&self) -> Option<&Value> {
302        match &self.kind {
303            ResponseKind::Ok { result } => Some(result),
304            _ => None,
305        }
306    }
307
308    /// Returns the `error` value, if it exists.
309    ///
310    /// This member only exists if the response indicates failure.
311    #[inline]
312    pub const fn error(&self) -> Option<&Error> {
313        match &self.kind {
314            ResponseKind::Err { error } => Some(error),
315            _ => None,
316        }
317    }
318
319    /// Returns the corresponding request ID, if known.
320    #[inline]
321    pub const fn id(&self) -> &Id {
322        &self.id
323    }
324}
325
326impl Debug for Response {
327    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
328        let mut d = f.debug_struct("Response");
329        d.field("jsonrpc", &self.jsonrpc);
330
331        match &self.kind {
332            ResponseKind::Ok { result } => d.field("result", result),
333            ResponseKind::Err { error } => d.field("error", error),
334        };
335
336        d.field("id", &self.id).finish()
337    }
338}
339
340#[derive(Clone, PartialEq, Deserialize, Serialize)]
341#[serde(untagged)]
342enum ResponseKind {
343    Ok { result: Value },
344    Err { error: Error },
345}
346
347/// An incoming or outgoing JSON-RPC message.
348#[derive(Deserialize, Serialize)]
349#[cfg_attr(test, derive(Debug, PartialEq))]
350#[serde(untagged)]
351pub(crate) enum Message {
352    /// A response message.
353    Response(Response),
354    /// A request or notification message.
355    Request(Request),
356}
357
358#[derive(Clone, Copy, Debug, PartialEq)]
359pub(crate) struct Version;
360
361impl<'de> Deserialize<'de> for Version {
362    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
363    where
364        D: Deserializer<'de>,
365    {
366        match Cow::<'de, str>::deserialize(deserializer)?.as_ref() {
367            "2.0" => Ok(Version),
368            _ => Err(de::Error::custom("expected JSON-RPC version \"2.0\"")),
369        }
370    }
371}
372
373impl Serialize for Version {
374    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
375    where
376        S: Serializer,
377    {
378        "2.0".serialize(serializer)
379    }
380}
381
382/// Error response returned for every request received before the server is initialized.
383///
384/// See [here](https://microsoft.github.io/language-server-protocol/specification#initialize)
385/// for reference.
386pub(crate) fn not_initialized_error() -> Error {
387    Error {
388        code: ErrorCode::ServerError(-32002),
389        message: "Server not initialized".to_string(),
390        data: None,
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use serde_json::json;
397
398    use super::*;
399
400    #[test]
401    fn incoming_from_str_or_value() {
402        let v = json!({"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{}},"id":0});
403        let from_str: Message = serde_json::from_str(&v.to_string()).unwrap();
404        let from_value: Message = serde_json::from_value(v).unwrap();
405        assert_eq!(from_str, from_value);
406    }
407
408    #[test]
409    fn outgoing_from_str_or_value() {
410        let v = json!({"jsonrpc":"2.0","result":{},"id":1});
411        let from_str: Message = serde_json::from_str(&v.to_string()).unwrap();
412        let from_value: Message = serde_json::from_value(v).unwrap();
413        assert_eq!(from_str, from_value);
414    }
415
416    #[test]
417    fn parses_incoming_message() {
418        let server_request =
419            json!({"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{}},"id":0});
420        let incoming = serde_json::from_value(server_request).unwrap();
421        assert!(matches!(incoming, Message::Request(_)));
422
423        let server_notif = json!({"jsonrpc":"2.0","method":"initialized","params":{}});
424        let incoming = serde_json::from_value(server_notif).unwrap();
425        assert!(matches!(incoming, Message::Request(_)));
426
427        let client_request = json!({"jsonrpc":"2.0","id":0,"result":[null]});
428        let incoming = serde_json::from_value(client_request).unwrap();
429        assert!(matches!(incoming, Message::Response(_)));
430    }
431
432    #[test]
433    fn parses_outgoing_message() {
434        let client_request = json!({"jsonrpc":"2.0","method":"workspace/configuration","params":{"scopeUri":null,"section":"foo"},"id":0});
435        let outgoing = serde_json::from_value(client_request).unwrap();
436        assert!(matches!(outgoing, Message::Request(_)));
437
438        let client_notif = json!({"jsonrpc":"2.0","method":"window/logMessage","params":{"message":"foo","type":0}});
439        let outgoing = serde_json::from_value(client_notif).unwrap();
440        assert!(matches!(outgoing, Message::Request(_)));
441
442        let server_response = json!({"jsonrpc":"2.0","id":0,"result":[null]});
443        let outgoing = serde_json::from_value(server_response).unwrap();
444        assert!(matches!(outgoing, Message::Response(_)));
445    }
446
447    #[test]
448    fn parses_invalid_server_request() {
449        let unknown_method = json!({"jsonrpc":"2.0","method":"foo"});
450        let incoming = serde_json::from_value(unknown_method).unwrap();
451        assert!(matches!(incoming, Message::Request(_)));
452
453        let unknown_method_with_id = json!({"jsonrpc":"2.0","method":"foo","id":0});
454        let incoming = serde_json::from_value(unknown_method_with_id).unwrap();
455        assert!(matches!(incoming, Message::Request(_)));
456
457        let missing_method = json!({"jsonrpc":"2.0"});
458        let incoming = serde_json::from_value(missing_method).unwrap();
459        assert!(matches!(incoming, Message::Request(_)));
460
461        let missing_method_with_id = json!({"jsonrpc":"2.0","id":0});
462        let incoming = serde_json::from_value(missing_method_with_id).unwrap();
463        assert!(matches!(incoming, Message::Request(_)));
464    }
465
466    #[test]
467    fn accepts_null_request_id() {
468        let request_id: Id = serde_json::from_value(json!(null)).unwrap();
469        assert_eq!(request_id, Id::Null);
470    }
471
472    #[test]
473    fn accepts_negative_integer_request_id() {
474        let request_id: Id = serde_json::from_value(json!(-1)).unwrap();
475        assert_eq!(request_id, Id::Number(-1));
476    }
477}