Skip to main content

lsp_max/jsonrpc/
request.rs

1use std::borrow::Cow;
2use std::fmt::{self, Display, Formatter};
3use std::str::FromStr;
4
5use serde::{Deserialize, Deserializer, Serialize};
6use serde_json::Value;
7
8use super::{Id, Version};
9
10fn deserialize_some<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
11where
12    T: Deserialize<'de>,
13    D: Deserializer<'de>,
14{
15    T::deserialize(deserializer).map(Some)
16}
17
18/// A JSON-RPC request or notification.
19#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
20pub struct Request {
21    jsonrpc: Version,
22    #[serde(default)]
23    method: Cow<'static, str>,
24    #[serde(default, deserialize_with = "deserialize_some")]
25    #[serde(skip_serializing_if = "Option::is_none")]
26    params: Option<Value>,
27    #[serde(default, deserialize_with = "deserialize_some")]
28    #[serde(skip_serializing_if = "Option::is_none")]
29    id: Option<Id>,
30}
31
32impl Request {
33    /// Starts building a JSON-RPC method call.
34    ///
35    /// Returns a `RequestBuilder`, which allows setting the `params` field or adding a request ID.
36    pub fn build<M>(method: M) -> RequestBuilder
37    where
38        M: Into<Cow<'static, str>>,
39    {
40        RequestBuilder {
41            method: method.into(),
42            params: None,
43            id: None,
44        }
45    }
46
47    /// Constructs a JSON-RPC request from its corresponding LSP type.
48    ///
49    /// # Panics
50    ///
51    /// Panics if `params` could not be serialized into a [`serde_json::Value`]. Since the
52    /// [`lsp_types_max::request::Request`] trait promises this invariant is upheld, this should never
53    /// happen in practice (unless the trait was implemented incorrectly).
54    pub(crate) fn from_request<R>(id: Id, params: R::Params) -> Self
55    where
56        R: lsp_types_max::request::Request,
57    {
58        Request {
59            jsonrpc: Version,
60            method: R::METHOD.into(),
61            params: Some(serde_json::to_value(params).unwrap_or(Value::Null)),
62            id: Some(id),
63        }
64    }
65
66    /// Constructs a JSON-RPC notification from its corresponding LSP type.
67    ///
68    /// # Panics
69    ///
70    /// Panics if `params` could not be serialized into a [`serde_json::Value`]. Since the
71    /// [`lsp_types_max::notification::Notification`] trait promises this invariant is upheld, this
72    /// should never happen in practice (unless the trait was implemented incorrectly).
73    pub(crate) fn from_notification<N>(params: N::Params) -> Self
74    where
75        N: lsp_types_max::notification::Notification,
76    {
77        Request {
78            jsonrpc: Version,
79            method: N::METHOD.into(),
80            params: Some(serde_json::to_value(params).unwrap_or(Value::Null)),
81            id: None,
82        }
83    }
84
85    /// Constructs a JSON-RPC request from an `lsp_types_max::RequestMessage`.
86    pub fn from_message(msg: lsp_types_max::RequestMessage) -> Self {
87        Request {
88            jsonrpc: Version,
89            method: Cow::Owned(msg.method),
90            params: msg.params,
91            id: Some(Id::from(msg.id)),
92        }
93    }
94
95    /// Constructs a JSON-RPC notification from an `lsp_types_max::NotificationMessage`.
96    pub fn from_notification_message(msg: lsp_types_max::NotificationMessage) -> Self {
97        Request {
98            jsonrpc: Version,
99            method: Cow::Owned(msg.method),
100            params: msg.params,
101            id: None,
102        }
103    }
104
105    /// Returns the name of the method to be invoked.
106    pub fn method(&self) -> &str {
107        self.method.as_ref()
108    }
109
110    /// Returns the unique ID of this request, if present.
111    pub fn id(&self) -> Option<&Id> {
112        self.id.as_ref()
113    }
114
115    /// Returns the `params` field, if present.
116    pub fn params(&self) -> Option<&Value> {
117        self.params.as_ref()
118    }
119
120    /// Splits this request into the method name, request ID, and the `params` field, if present.
121    pub fn into_parts(self) -> (Cow<'static, str>, Option<Id>, Option<Value>) {
122        (self.method, self.id, self.params)
123    }
124}
125
126impl Display for Request {
127    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
128        use std::{io, str};
129
130        struct WriterFormatter<'a, 'b: 'a> {
131            inner: &'a mut Formatter<'b>,
132        }
133
134        impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> {
135            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
136                fn io_error<E>(_: E) -> io::Error {
137                    // Error value does not matter because fmt::Display impl below just
138                    // maps it to fmt::Error
139                    io::Error::other("fmt error")
140                }
141                let s = str::from_utf8(buf).map_err(io_error)?;
142                self.inner.write_str(s).map_err(io_error)?;
143                Ok(buf.len())
144            }
145
146            fn flush(&mut self) -> io::Result<()> {
147                Ok(())
148            }
149        }
150
151        let mut w = WriterFormatter { inner: f };
152        serde_json::to_writer(&mut w, self).map_err(|_| fmt::Error)
153    }
154}
155
156impl FromStr for Request {
157    type Err = serde_json::Error;
158
159    fn from_str(s: &str) -> Result<Self, Self::Err> {
160        serde_json::from_str(s)
161    }
162}
163
164/// A builder to construct the properties of a `Request`.
165///
166/// To construct a `RequestBuilder`, refer to [`Request::build`].
167#[derive(Debug)]
168pub struct RequestBuilder {
169    method: Cow<'static, str>,
170    params: Option<Value>,
171    id: Option<Id>,
172}
173
174impl RequestBuilder {
175    /// Sets the `id` member of the request to the given value.
176    ///
177    /// If this method is not called, the resulting `Request` will be assumed to be a notification.
178    pub fn id<I: Into<Id>>(mut self, id: I) -> Self {
179        self.id = Some(id.into());
180        self
181    }
182
183    /// Sets the `params` member of the request to the given value.
184    ///
185    /// This member is omitted from the request by default.
186    pub fn params<V: Into<Value>>(mut self, params: V) -> Self {
187        self.params = Some(params.into());
188        self
189    }
190
191    /// Constructs the JSON-RPC request and returns it.
192    pub fn finish(self) -> Request {
193        Request {
194            jsonrpc: Version,
195            method: self.method,
196            params: self.params,
197            id: self.id,
198        }
199    }
200}