1use std::fmt;
4#[cfg(any(feature = "lsp", feature = "dap"))]
5use std::io::{self, BufRead, Write};
6
7use serde::{Deserialize, Serialize};
8
9#[cfg(feature = "dap")]
10use crate::dap;
11#[cfg(feature = "lsp")]
12use crate::lsp;
13
14#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[serde(transparent)]
17pub struct RequestId(IdRepr);
18
19impl RequestId {
20 #[cfg(all(feature = "dap", feature = "server"))]
21 pub(crate) fn dap(id: RequestId) -> i64 {
22 match id.0 {
23 IdRepr::I32(it) => it as i64,
24 IdRepr::String(it) => panic!("unexpected string ID in DAP: {it}"),
25 }
26 }
27}
28
29#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[serde(untagged)]
31enum IdRepr {
32 I32(i32),
33 String(String),
34}
35
36impl From<i32> for RequestId {
37 fn from(id: i32) -> RequestId {
38 RequestId(IdRepr::I32(id))
39 }
40}
41
42impl From<String> for RequestId {
43 fn from(id: String) -> RequestId {
44 RequestId(IdRepr::String(id))
45 }
46}
47
48impl fmt::Display for RequestId {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match &self.0 {
51 IdRepr::I32(it) => fmt::Display::fmt(it, f),
52 IdRepr::String(it) => fmt::Debug::fmt(it, f),
56 }
57 }
58}
59
60#[derive(Debug, Serialize, Deserialize, Clone)]
62pub struct ResponseError {
63 pub code: i32,
65 pub message: String,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub data: Option<serde_json::Value>,
70}
71
72#[derive(Clone, Copy, Debug)]
74#[non_exhaustive]
75pub enum ErrorCode {
76 ParseError = -32700,
79 InvalidRequest = -32600,
81 MethodNotFound = -32601,
83 InvalidParams = -32602,
85 InternalError = -32603,
87 ServerErrorStart = -32099,
89 ServerErrorEnd = -32000,
91
92 ServerNotInitialized = -32002,
95 UnknownErrorCode = -32001,
98
99 RequestCanceled = -32800,
103
104 ContentModified = -32801,
113
114 ServerCancelled = -32802,
120
121 RequestFailed = -32803,
128}
129
130#[cfg(feature = "lsp")]
132pub type LspMessage = lsp::Message;
133#[cfg(feature = "dap")]
135pub type DapMessage = dap::Message;
136
137#[derive(Debug)]
139pub enum Message {
140 #[cfg(feature = "lsp")]
142 Lsp(LspMessage),
143 #[cfg(feature = "dap")]
145 Dap(DapMessage),
146}
147
148impl Message {
149 #[cfg(feature = "lsp")]
151 pub fn read_lsp<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
152 let msg = lsp::Message::read(reader)?;
153 Ok(msg.map(Message::Lsp))
154 }
155
156 #[cfg(feature = "dap")]
158 pub fn read_dap<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
159 let msg = dap::Message::read(reader)?;
160 Ok(msg.map(Message::Dap))
161 }
162
163 pub fn write<W: std::io::Write>(self, _writer: &mut W) -> std::io::Result<()> {
165 match self {
166 #[cfg(feature = "lsp")]
167 Message::Lsp(msg) => msg.write(_writer),
168 #[cfg(feature = "dap")]
169 Message::Dap(msg) => msg.write(_writer),
170 }
171 }
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176pub enum MessageKind {
177 #[cfg(feature = "lsp")]
179 Lsp,
180 #[cfg(feature = "dap")]
182 Dap,
183}
184
185pub trait GetMessageKind {
187 fn get_message_kind() -> MessageKind;
189}
190
191#[cfg(feature = "lsp")]
192impl GetMessageKind for LspMessage {
193 fn get_message_kind() -> MessageKind {
194 MessageKind::Lsp
195 }
196}
197
198#[cfg(feature = "dap")]
199impl GetMessageKind for DapMessage {
200 fn get_message_kind() -> MessageKind {
201 MessageKind::Dap
202 }
203}
204
205#[allow(unused)]
206pub(crate) enum LspOrDapResponse {
207 #[cfg(feature = "lsp")]
208 Lsp(lsp::Response),
209 #[cfg(feature = "dap")]
210 Dap(dap::Response),
211}
212
213#[cfg(any(feature = "lsp", feature = "dap"))]
214pub(crate) fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
215 let mut size = None;
216 let mut buf = String::new();
217 loop {
218 buf.clear();
219 if inp.read_line(&mut buf)? == 0 {
220 return Ok(None);
221 }
222 if !buf.ends_with("\r\n") {
223 return Err(invalid_data_fmt!("malformed header: {buf:?}"));
224 }
225 let buf = &buf[..buf.len() - 2];
226 if buf.is_empty() {
227 break;
228 }
229 let mut parts = buf.splitn(2, ": ");
230 let header_name = parts.next().unwrap();
231 let header_value = parts
232 .next()
233 .ok_or_else(|| invalid_data_fmt!("malformed header: {buf:?}"))?;
234 if header_name.eq_ignore_ascii_case("Content-Length") {
235 size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
236 }
237 }
238 let size: usize = size.ok_or_else(|| invalid_data_fmt!("no Content-Length"))?;
239 let mut buf = buf.into_bytes();
240 buf.resize(size, 0);
241 inp.read_exact(&mut buf)?;
242 let buf = String::from_utf8(buf).map_err(invalid_data)?;
243 log::debug!("< {buf}");
244 Ok(Some(buf))
245}
246
247#[cfg(any(feature = "lsp", feature = "dap"))]
248pub(crate) fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> {
249 log::debug!("> {msg}");
250 write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
251 out.write_all(msg.as_bytes())?;
252 out.flush()?;
253 Ok(())
254}
255
256#[cfg(any(feature = "lsp", feature = "dap"))]
257pub(crate) fn invalid_data(
258 error: impl Into<Box<dyn std::error::Error + Send + Sync>>,
259) -> io::Error {
260 io::Error::new(io::ErrorKind::InvalidData, error)
261}
262
263#[cfg(any(feature = "lsp", feature = "dap"))]
264macro_rules! invalid_data_fmt {
265 ($($tt:tt)*) => ($crate::invalid_data(format!($($tt)*)))
266}
267#[cfg(any(feature = "lsp", feature = "dap"))]
268pub(crate) use invalid_data_fmt;