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(feature = "dap")]
22 pub fn dap(id: RequestId) -> i64 {
23 match id.0 {
24 IdRepr::I32(it) => it as i64,
25 IdRepr::String(it) => panic!("unexpected string ID in DAP: {it}"),
26 }
27 }
28}
29
30#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31#[serde(untagged)]
32enum IdRepr {
33 I32(i32),
34 String(String),
35}
36
37impl From<i32> for RequestId {
38 fn from(id: i32) -> RequestId {
39 RequestId(IdRepr::I32(id))
40 }
41}
42
43impl From<String> for RequestId {
44 fn from(id: String) -> RequestId {
45 RequestId(IdRepr::String(id))
46 }
47}
48
49impl fmt::Display for RequestId {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match &self.0 {
52 IdRepr::I32(it) => fmt::Display::fmt(it, f),
53 IdRepr::String(it) => fmt::Debug::fmt(it, f),
57 }
58 }
59}
60
61#[derive(Debug, Serialize, Deserialize, Clone)]
63pub struct ResponseError {
64 pub code: i32,
66 pub message: String,
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub data: Option<serde_json::Value>,
71}
72
73#[derive(Clone, Copy, Debug)]
75#[non_exhaustive]
76pub enum ErrorCode {
77 ParseError = -32700,
80 InvalidRequest = -32600,
82 MethodNotFound = -32601,
84 InvalidParams = -32602,
86 InternalError = -32603,
88 ServerErrorStart = -32099,
90 ServerErrorEnd = -32000,
92
93 ServerNotInitialized = -32002,
96 UnknownErrorCode = -32001,
99
100 RequestCanceled = -32800,
104
105 ContentModified = -32801,
114
115 ServerCancelled = -32802,
121
122 RequestFailed = -32803,
129}
130
131#[cfg(feature = "lsp")]
133pub type LspMessage = lsp::Message;
134#[cfg(feature = "dap")]
136pub type DapMessage = dap::Message;
137
138#[derive(Debug)]
140pub enum Message {
141 #[cfg(feature = "lsp")]
143 Lsp(LspMessage),
144 #[cfg(feature = "dap")]
146 Dap(DapMessage),
147}
148
149impl Message {
150 #[cfg(feature = "lsp")]
152 pub fn read_lsp<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
153 let msg = lsp::Message::read(reader)?;
154 Ok(msg.map(Message::Lsp))
155 }
156
157 #[cfg(feature = "dap")]
159 pub fn read_dap<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
160 let msg = dap::Message::read(reader)?;
161 Ok(msg.map(Message::Dap))
162 }
163
164 pub fn write<W: std::io::Write>(self, _writer: &mut W) -> std::io::Result<()> {
166 match self {
167 #[cfg(feature = "lsp")]
168 Message::Lsp(msg) => msg.write(_writer),
169 #[cfg(feature = "dap")]
170 Message::Dap(msg) => msg.write(_writer),
171 }
172 }
173}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub enum MessageKind {
178 #[cfg(feature = "lsp")]
180 Lsp,
181 #[cfg(feature = "dap")]
183 Dap,
184}
185
186pub trait GetMessageKind {
188 const MESSAGE_KIND: MessageKind;
190}
191
192#[cfg(feature = "lsp")]
193impl GetMessageKind for LspMessage {
194 const MESSAGE_KIND: MessageKind = MessageKind::Lsp;
195}
196
197#[cfg(feature = "dap")]
198impl GetMessageKind for DapMessage {
199 const MESSAGE_KIND: MessageKind = MessageKind::Dap;
200}
201
202#[allow(unused)]
203pub(crate) enum LspOrDapResponse {
204 #[cfg(feature = "lsp")]
205 Lsp(lsp::Response),
206 #[cfg(feature = "dap")]
207 Dap(dap::Response),
208}
209
210#[cfg(any(feature = "lsp", feature = "dap"))]
211pub(crate) fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
212 let mut size = None;
213 let mut buf = String::new();
214 loop {
215 buf.clear();
216 if inp.read_line(&mut buf)? == 0 {
217 return Ok(None);
218 }
219 if !buf.ends_with("\r\n") {
220 return Err(invalid_data_fmt!("malformed header: {buf:?}"));
221 }
222 let buf = &buf[..buf.len() - 2];
223 if buf.is_empty() {
224 break;
225 }
226 let mut parts = buf.splitn(2, ": ");
227 let header_name = parts.next().unwrap();
228 let header_value = parts
229 .next()
230 .ok_or_else(|| invalid_data_fmt!("malformed header: {buf:?}"))?;
231 if header_name.eq_ignore_ascii_case("Content-Length") {
232 size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
233 }
234 }
235 let size: usize = size.ok_or_else(|| invalid_data_fmt!("no Content-Length"))?;
236 let mut buf = buf.into_bytes();
237 buf.resize(size, 0);
238 inp.read_exact(&mut buf)?;
239 let buf = String::from_utf8(buf).map_err(invalid_data)?;
240 log::debug!("< {buf}");
241 Ok(Some(buf))
242}
243
244#[cfg(any(feature = "lsp", feature = "dap"))]
245pub(crate) fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> {
246 log::debug!("> {msg}");
247 write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
248 out.write_all(msg.as_bytes())?;
249 out.flush()?;
250 Ok(())
251}
252
253#[cfg(any(feature = "lsp", feature = "dap"))]
254pub(crate) fn invalid_data(
255 error: impl Into<Box<dyn std::error::Error + Send + Sync>>,
256) -> io::Error {
257 io::Error::new(io::ErrorKind::InvalidData, error)
258}
259
260#[cfg(any(feature = "lsp", feature = "dap"))]
261macro_rules! invalid_data_fmt {
262 ($($tt:tt)*) => ($crate::invalid_data(format!($($tt)*)))
263}
264#[cfg(any(feature = "lsp", feature = "dap"))]
265pub(crate) use invalid_data_fmt;