tower_lsp_server/jsonrpc/
error.rs

1//! Error types defined by the JSON-RPC specification.
2
3use std::borrow::Cow;
4use std::fmt::{self, Display, Formatter};
5
6use ls_types::LSPAny;
7use serde::{Deserialize, Serialize};
8
9/// A specialized [`Result`] error type for JSON-RPC handlers.
10///
11/// [`Result`]: enum@std::result::Result
12pub type Result<T> = std::result::Result<T, Error>;
13
14/// A list of numeric error codes used in JSON-RPC responses.
15#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
16#[serde(into = "i64", from = "i64")]
17pub enum ErrorCode {
18    /// Invalid JSON was received by the server.
19    ParseError,
20    /// The JSON sent is not a valid Request object.
21    InvalidRequest,
22    /// The method does not exist / is not available.
23    MethodNotFound,
24    /// Invalid method parameter(s).
25    InvalidParams,
26    /// Internal JSON-RPC error.
27    InternalError,
28    /// Reserved for implementation-defined server errors.
29    ServerError(i64),
30
31    /// The request was cancelled by the client.
32    ///
33    /// # Compatibility
34    ///
35    /// This error code is defined by the Language Server Protocol.
36    RequestCancelled,
37    /// The request was invalidated by another incoming request.
38    ///
39    /// # Compatibility
40    ///
41    /// This error code is specific to the Language Server Protocol.
42    ContentModified,
43}
44
45impl ErrorCode {
46    /// Returns the integer error code value.
47    #[must_use]
48    pub const fn code(&self) -> i64 {
49        match *self {
50            Self::ParseError => -32700,
51            Self::InvalidRequest => -32600,
52            Self::MethodNotFound => -32601,
53            Self::InvalidParams => -32602,
54            Self::InternalError => -32603,
55            Self::RequestCancelled => -32800,
56            Self::ContentModified => -32801,
57            Self::ServerError(code) => code,
58        }
59    }
60
61    /// Returns a human-readable description of the error.
62    #[must_use]
63    pub const fn description(&self) -> &'static str {
64        match *self {
65            Self::ParseError => "Parse error",
66            Self::InvalidRequest => "Invalid request",
67            Self::MethodNotFound => "Method not found",
68            Self::InvalidParams => "Invalid params",
69            Self::InternalError => "Internal error",
70            Self::RequestCancelled => "Canceled",
71            Self::ContentModified => "Content modified",
72            Self::ServerError(_) => "Server error",
73        }
74    }
75}
76
77impl From<i64> for ErrorCode {
78    fn from(code: i64) -> Self {
79        match code {
80            -32700 => Self::ParseError,
81            -32600 => Self::InvalidRequest,
82            -32601 => Self::MethodNotFound,
83            -32602 => Self::InvalidParams,
84            -32603 => Self::InternalError,
85            -32800 => Self::RequestCancelled,
86            -32801 => Self::ContentModified,
87            code => Self::ServerError(code),
88        }
89    }
90}
91
92impl From<ErrorCode> for i64 {
93    fn from(code: ErrorCode) -> Self {
94        code.code()
95    }
96}
97
98impl Display for ErrorCode {
99    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
100        Display::fmt(&self.code(), f)
101    }
102}
103
104/// A JSON-RPC error object.
105#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
106#[serde(deny_unknown_fields)]
107pub struct Error {
108    /// A number indicating the error type that occurred.
109    pub code: ErrorCode,
110    /// A short description of the error.
111    pub message: Cow<'static, str>,
112    /// Additional information about the error, if any.
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub data: Option<LSPAny>,
115}
116
117impl Error {
118    /// Creates a new error from the given `ErrorCode`.
119    #[must_use]
120    pub const fn new(code: ErrorCode) -> Self {
121        Self {
122            code,
123            message: Cow::Borrowed(code.description()),
124            data: None,
125        }
126    }
127
128    /// Creates a new parse error (`-32700`).
129    #[must_use]
130    pub const fn parse_error() -> Self {
131        Self::new(ErrorCode::ParseError)
132    }
133
134    /// Creates a new "invalid request" error (`-32600`).
135    #[must_use]
136    pub const fn invalid_request() -> Self {
137        Self::new(ErrorCode::InvalidRequest)
138    }
139
140    /// Creates a new "method not found" error (`-32601`).
141    #[must_use]
142    pub const fn method_not_found() -> Self {
143        Self::new(ErrorCode::MethodNotFound)
144    }
145
146    /// Creates a new "invalid params" error (`-32602`).
147    pub fn invalid_params<M>(message: M) -> Self
148    where
149        M: Into<Cow<'static, str>>,
150    {
151        Self {
152            code: ErrorCode::InvalidParams,
153            message: message.into(),
154            data: None,
155        }
156    }
157
158    /// Creates a new internal error (`-32603`).
159    #[must_use]
160    pub const fn internal_error() -> Self {
161        Self::new(ErrorCode::InternalError)
162    }
163
164    /// Creates a new "request cancelled" error (`-32800`).
165    ///
166    /// # Compatibility
167    ///
168    /// This error code is defined by the Language Server Protocol.
169    #[must_use]
170    pub const fn request_cancelled() -> Self {
171        Self::new(ErrorCode::RequestCancelled)
172    }
173
174    /// Creates a new "content modified" error (`-32801`).
175    ///
176    /// # Compatibility
177    ///
178    /// This error code is defined by the Language Server Protocol.
179    #[must_use]
180    pub const fn content_modified() -> Self {
181        Self::new(ErrorCode::ContentModified)
182    }
183}
184
185impl Display for Error {
186    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
187        write!(f, "{}: {}", self.code.description(), self.message)
188    }
189}
190
191impl std::error::Error for Error {}
192
193/// Error response returned for every request received before the server is initialized.
194///
195/// See [here](https://microsoft.github.io/language-server-protocol/specification#initialize)
196/// for reference.
197pub const fn not_initialized_error() -> Error {
198    Error {
199        code: ErrorCode::ServerError(-32002),
200        message: Cow::Borrowed("Server not initialized"),
201        data: None,
202    }
203}
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208
209    #[test]
210    fn error_code_serializes_as_i64() {
211        let serialized = serde_json::to_string(&ErrorCode::ParseError).unwrap();
212        assert_eq!(serialized, "-32700");
213
214        let serialized = serde_json::to_string(&ErrorCode::ServerError(-12345)).unwrap();
215        assert_eq!(serialized, "-12345");
216    }
217
218    #[test]
219    fn error_code_deserializes_from_i64() {
220        let deserialized: ErrorCode = serde_json::from_str("-32700").unwrap();
221        assert_eq!(deserialized, ErrorCode::ParseError);
222
223        let deserialized: ErrorCode = serde_json::from_str("-12345").unwrap();
224        assert_eq!(deserialized, ErrorCode::ServerError(-12345));
225    }
226}