use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum DapMessage {
#[serde(rename = "request")]
Request {
seq: i32,
command: String,
arguments: Option<serde_json::Value>,
},
#[serde(rename = "response")]
Response {
seq: i32,
request_seq: i32,
command: String,
success: bool,
body: Option<serde_json::Value>,
message: Option<String>,
},
#[serde(rename = "event")]
Event {
seq: i32,
event: String,
body: Option<serde_json::Value>,
},
}
pub struct DebugAdapterProtocol {
}
impl DebugAdapterProtocol {
pub fn new() -> Self {
Self {}
}
pub async fn handle_message(&self, message: DapMessage) -> Result<Option<DapMessage>, String> {
match message {
DapMessage::Request { seq, command, arguments } => {
self.handle_request(seq, &command, arguments).await
}
_ => Err("Invalid message type".to_string()),
}
}
async fn handle_request(&self, seq: i32, command: &str, arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
match command {
"initialize" => self.handle_initialize(seq, arguments).await,
"launch" => self.handle_launch(seq, arguments).await,
"setBreakpoints" => self.handle_set_breakpoints(seq, arguments).await,
"threads" => self.handle_threads(seq).await,
"stackTrace" => self.handle_stack_trace(seq, arguments).await,
"scopes" => self.handle_scopes(seq, arguments).await,
"variables" => self.handle_variables(seq, arguments).await,
"continue" => self.handle_continue(seq, arguments).await,
"next" => self.handle_next(seq, arguments).await,
"stepIn" => self.handle_step_in(seq, arguments).await,
"stepOut" => self.handle_step_out(seq, arguments).await,
"evaluate" => self.handle_evaluate(seq, arguments).await,
_ => Err(format!("Unknown command: {}", command)),
}
}
async fn handle_initialize(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "initialize".to_string(),
success: true,
body: Some(serde_json::json!({
"supportsConfigurationDoneRequest": true,
"supportsEvaluateForHovers": true,
"supportsStepBack": true,
"supportsSetVariable": true
})),
message: None,
};
Ok(Some(response))
}
async fn handle_launch(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "launch".to_string(),
success: true,
body: None,
message: None,
};
Ok(Some(response))
}
async fn handle_set_breakpoints(&self, seq: i32, arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "setBreakpoints".to_string(),
success: true,
body: Some(serde_json::json!({
"breakpoints": []
})),
message: None,
};
Ok(Some(response))
}
async fn handle_threads(&self, seq: i32) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "threads".to_string(),
success: true,
body: Some(serde_json::json!({
"threads": [
{ "id": 1, "name": "Main Thread" }
]
})),
message: None,
};
Ok(Some(response))
}
async fn handle_stack_trace(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "stackTrace".to_string(),
success: true,
body: Some(serde_json::json!({
"stackFrames": []
})),
message: None,
};
Ok(Some(response))
}
async fn handle_scopes(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "scopes".to_string(),
success: true,
body: Some(serde_json::json!({
"scopes": []
})),
message: None,
};
Ok(Some(response))
}
async fn handle_variables(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "variables".to_string(),
success: true,
body: Some(serde_json::json!({
"variables": []
})),
message: None,
};
Ok(Some(response))
}
async fn handle_continue(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "continue".to_string(),
success: true,
body: Some(serde_json::json!({
"allThreadsContinued": true
})),
message: None,
};
Ok(Some(response))
}
async fn handle_next(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "next".to_string(),
success: true,
body: None,
message: None,
};
Ok(Some(response))
}
async fn handle_step_in(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "stepIn".to_string(),
success: true,
body: None,
message: None,
};
Ok(Some(response))
}
async fn handle_step_out(&self, seq: i32, _arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "stepOut".to_string(),
success: true,
body: None,
message: None,
};
Ok(Some(response))
}
async fn handle_evaluate(&self, seq: i32, arguments: Option<serde_json::Value>) -> Result<Option<DapMessage>, String> {
let response: _ = DapMessage::Response {
seq: seq + 1,
request_seq: seq,
command: "evaluate".to_string(),
success: true,
body: Some(serde_json::json!({
"result": "42",
"type": "number"
})),
message: None,
};
Ok(Some(response))
}
}