sync_ls/
dap.rs

1//! A synchronous debug adaptor server implementation.
2
3use std::io;
4
5use serde::{Deserialize, Serialize};
6use serde_json::json;
7
8pub use dapts::{Event, Request, Response};
9
10use crate::{LspOrDapResponse, invalid_data_fmt, read_msg_text, write_msg_text};
11
12/// A message in the Debug Adaptor Protocol.
13#[derive(Deserialize, Debug, Clone)]
14#[serde(tag = "type")]
15pub enum Message {
16    /// Request messages
17    #[serde(rename = "request")]
18    Request(Request),
19    /// Response messages
20    #[serde(rename = "response")]
21    Response(Response),
22    /// Event messages
23    #[serde(rename = "event")]
24    Event(Event),
25    /// Response messages with the corresponding request command.
26    ///
27    /// `dapts::Response` currently does not carry DAP's required `command`
28    /// field. Keep the raw response type for reads, but use this variant when
29    /// writing server responses so clients like nvim-dap can route callbacks.
30    #[serde(skip)]
31    ResponseWithCommand(ResponseWithCommand),
32}
33
34/// A DAP response paired with the corresponding request command.
35#[derive(Debug, Clone)]
36pub struct ResponseWithCommand {
37    /// The request command this response answers.
38    pub command: String,
39    /// The response payload.
40    pub response: Response,
41}
42
43impl ResponseWithCommand {
44    /// Creates a response wrapper with a command field.
45    pub fn new(command: String, response: Response) -> Self {
46        Self { command, response }
47    }
48}
49
50impl Serialize for Message {
51    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
52        use serde::ser::Error;
53
54        let mut value = match self {
55            Message::Request(req) => serde_json::to_value(req).map_err(Error::custom)?,
56            Message::Response(resp) => serde_json::to_value(resp).map_err(Error::custom)?,
57            Message::Event(event) => serde_json::to_value(event).map_err(Error::custom)?,
58            Message::ResponseWithCommand(resp) => {
59                let mut value = serde_json::to_value(&resp.response).map_err(Error::custom)?;
60                let object = value
61                    .as_object_mut()
62                    .ok_or_else(|| Error::custom("DAP response did not serialize to an object"))?;
63                object.insert("command".to_owned(), json!(resp.command));
64                value
65            }
66        };
67
68        let object = value
69            .as_object_mut()
70            .ok_or_else(|| Error::custom("DAP message did not serialize to an object"))?;
71        object.insert(
72            "type".to_owned(),
73            json!(match self {
74                Message::Request(_) => "request",
75                Message::Response(_) | Message::ResponseWithCommand(_) => "response",
76                Message::Event(_) => "event",
77            }),
78        );
79
80        value.serialize(serializer)
81    }
82}
83
84impl From<Request> for Message {
85    fn from(req: Request) -> Self {
86        Message::Request(req)
87    }
88}
89
90impl From<Response> for Message {
91    fn from(resp: Response) -> Self {
92        Message::Response(resp)
93    }
94}
95
96impl From<Event> for Message {
97    fn from(event: Event) -> Self {
98        Message::Event(event)
99    }
100}
101
102impl Message {
103    /// Reads a DAP message from the reader.
104    pub fn read(r: &mut impl io::BufRead) -> io::Result<Option<Message>> {
105        let text = match read_msg_text(r)? {
106            None => return Ok(None),
107            Some(text) => text,
108        };
109
110        let msg = match serde_json::from_str(&text) {
111            Ok(msg) => msg,
112            Err(e) => {
113                return Err(invalid_data_fmt!("malformed DAP payload: {e:?}"));
114            }
115        };
116
117        Ok(Some(msg))
118    }
119    /// Writes the DAP message to the writer.
120    pub fn write(self, w: &mut impl io::Write) -> io::Result<()> {
121        #[derive(Serialize)]
122        struct JsonRpc {
123            jsonrpc: &'static str,
124            #[serde(flatten)]
125            msg: Message,
126        }
127        let text = serde_json::to_string(&JsonRpc {
128            jsonrpc: "2.0",
129            msg: self,
130        })?;
131        write_msg_text(w, &text)
132    }
133}
134
135impl TryFrom<crate::Message> for Message {
136    type Error = anyhow::Error;
137
138    fn try_from(msg: crate::Message) -> anyhow::Result<Self> {
139        match msg {
140            #[cfg(feature = "lsp")]
141            crate::Message::Lsp(msg) => anyhow::bail!("unexpected LSP message: {msg:?}"),
142            crate::Message::Dap(msg) => Ok(msg),
143        }
144    }
145}
146
147impl From<Request> for crate::Message {
148    fn from(request: Request) -> crate::Message {
149        crate::Message::Dap(request.into())
150    }
151}
152
153impl From<Response> for crate::Message {
154    fn from(response: Response) -> crate::Message {
155        crate::Message::Dap(response.into())
156    }
157}
158
159impl From<Event> for crate::Message {
160    fn from(notification: Event) -> crate::Message {
161        crate::Message::Dap(notification.into())
162    }
163}
164
165impl From<Response> for LspOrDapResponse {
166    fn from(resp: Response) -> Self {
167        Self::Dap(resp)
168    }
169}
170
171impl TryFrom<LspOrDapResponse> for Response {
172    type Error = anyhow::Error;
173
174    fn try_from(resp: LspOrDapResponse) -> anyhow::Result<Self> {
175        match resp {
176            #[cfg(feature = "lsp")]
177            LspOrDapResponse::Lsp(_) => anyhow::bail!("unexpected LSP response"),
178            LspOrDapResponse::Dap(resp) => Ok(resp),
179        }
180    }
181}