1use std::collections::HashMap;
7use std::sync::Arc;
8
9use serde::{Deserialize, Serialize};
10use tokio::sync::RwLock;
11
12use crate::config::DapAdapterConfig;
13use crate::error::DapError;
14use crate::transport::{DapTransport, EventHandler};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
18#[non_exhaustive]
19pub enum DapSessionState {
20 #[default]
22 NotStarted,
23 Initializing,
25 Configured,
27 Running,
29 Stopped,
31 Terminated,
33}
34
35impl std::fmt::Display for DapSessionState {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 Self::NotStarted => write!(f, "not_started"),
39 Self::Initializing => write!(f, "initializing"),
40 Self::Configured => write!(f, "configured"),
41 Self::Running => write!(f, "running"),
42 Self::Stopped => write!(f, "stopped"),
43 Self::Terminated => write!(f, "terminated"),
44 }
45 }
46}
47
48pub struct DapClient {
53 transport: Arc<DapTransport>,
54 capabilities: RwLock<Option<serde_json::Value>>,
55 status: Arc<RwLock<DapSessionState>>,
56 active_breakpoints: Arc<RwLock<HashMap<String, Vec<serde_json::Value>>>>,
57}
58
59impl DapClient {
60 pub fn start(config: &DapAdapterConfig, event_handler: EventHandler) -> Result<Self, DapError> {
70 drop(
72 which::which(&config.command).map_err(|_| DapError::BinaryNotFound {
73 binary: config.command.clone(),
74 })?,
75 );
76
77 let transport =
78 DapTransport::spawn(&config.command, &config.args, &config.env, event_handler)?;
79
80 Ok(Self {
81 transport: Arc::new(transport),
82 capabilities: RwLock::new(None),
83 status: Arc::new(RwLock::new(DapSessionState::NotStarted)),
84 active_breakpoints: Arc::new(RwLock::new(HashMap::new())),
85 })
86 }
87
88 pub async fn initialize(&self) -> Result<(), DapError> {
97 self.set_status(DapSessionState::Initializing).await;
98
99 let args = serde_json::json!({
100 "clientID": "synwire",
101 "clientName": "Synwire Agent",
102 "adapterID": "synwire",
103 "linesStartAt1": true,
104 "columnsStartAt1": true,
105 "pathFormat": "path",
106 "supportsRunInTerminalRequest": false,
107 "supportsVariableType": true,
108 "supportsVariablePaging": false,
109 });
110
111 let response = self
112 .transport
113 .send_request("initialize", args)
114 .await
115 .map_err(|e| DapError::InitializationFailed(e.to_string()))?;
116
117 if let Some(body) = response.get("body") {
119 *self.capabilities.write().await = Some(body.clone());
120 }
121
122 tracing::debug!("DAP initialize handshake complete");
123
124 Ok(())
125 }
126
127 pub async fn launch(&self, config: serde_json::Value) -> Result<(), DapError> {
136 self.ensure_initialized().await?;
137
138 let _ = self.transport.send_request("launch", config).await?;
139 let _ = self
140 .transport
141 .send_request("configurationDone", serde_json::json!({}))
142 .await?;
143
144 self.set_status(DapSessionState::Running).await;
145 tracing::debug!("DAP launch complete");
146 Ok(())
147 }
148
149 pub async fn attach(&self, config: serde_json::Value) -> Result<(), DapError> {
155 self.ensure_initialized().await?;
156
157 let _ = self.transport.send_request("attach", config).await?;
158 let _ = self
159 .transport
160 .send_request("configurationDone", serde_json::json!({}))
161 .await?;
162
163 self.set_status(DapSessionState::Running).await;
164 tracing::debug!("DAP attach complete");
165 Ok(())
166 }
167
168 pub async fn disconnect(&self) -> Result<(), DapError> {
174 let _ = self
175 .transport
176 .send_request(
177 "disconnect",
178 serde_json::json!({
179 "restart": false,
180 "terminateDebuggee": true,
181 }),
182 )
183 .await?;
184
185 self.set_status(DapSessionState::Terminated).await;
186 tracing::debug!("DAP disconnected");
187 Ok(())
188 }
189
190 pub async fn terminate(&self) -> Result<(), DapError> {
196 let _ = self
197 .transport
198 .send_request("terminate", serde_json::json!({ "restart": false }))
199 .await?;
200
201 self.set_status(DapSessionState::Terminated).await;
202 tracing::debug!("DAP terminated");
203 Ok(())
204 }
205
206 pub async fn set_breakpoints(
214 &self,
215 source_path: &str,
216 lines: &[i64],
217 ) -> Result<Vec<serde_json::Value>, DapError> {
218 let breakpoints: Vec<serde_json::Value> = lines
219 .iter()
220 .map(|&line| serde_json::json!({ "line": line }))
221 .collect();
222
223 let args = serde_json::json!({
224 "source": { "path": source_path },
225 "breakpoints": breakpoints,
226 });
227
228 let response = self.transport.send_request("setBreakpoints", args).await?;
229
230 let result = response
231 .get("body")
232 .and_then(|b| b.get("breakpoints"))
233 .and_then(serde_json::Value::as_array)
234 .cloned()
235 .unwrap_or_default();
236
237 let _ = self
239 .active_breakpoints
240 .write()
241 .await
242 .insert(source_path.to_string(), result.clone());
243
244 Ok(result)
245 }
246
247 pub async fn set_function_breakpoints(
253 &self,
254 names: &[String],
255 ) -> Result<Vec<serde_json::Value>, DapError> {
256 let breakpoints: Vec<serde_json::Value> = names
257 .iter()
258 .map(|name| serde_json::json!({ "name": name }))
259 .collect();
260
261 let args = serde_json::json!({ "breakpoints": breakpoints });
262
263 let response = self
264 .transport
265 .send_request("setFunctionBreakpoints", args)
266 .await?;
267
268 let result = response
269 .get("body")
270 .and_then(|b| b.get("breakpoints"))
271 .and_then(serde_json::Value::as_array)
272 .cloned()
273 .unwrap_or_default();
274
275 Ok(result)
276 }
277
278 pub async fn set_exception_breakpoints(&self, filters: &[String]) -> Result<(), DapError> {
284 let _ = self
285 .transport
286 .send_request(
287 "setExceptionBreakpoints",
288 serde_json::json!({ "filters": filters }),
289 )
290 .await?;
291 Ok(())
292 }
293
294 pub async fn continue_execution(&self, thread_id: i64) -> Result<(), DapError> {
300 let _ = self
301 .transport
302 .send_request("continue", serde_json::json!({ "threadId": thread_id }))
303 .await?;
304 self.set_status(DapSessionState::Running).await;
305 Ok(())
306 }
307
308 pub async fn next(&self, thread_id: i64) -> Result<(), DapError> {
314 let _ = self
315 .transport
316 .send_request("next", serde_json::json!({ "threadId": thread_id }))
317 .await?;
318 self.set_status(DapSessionState::Running).await;
319 Ok(())
320 }
321
322 pub async fn step_in(&self, thread_id: i64) -> Result<(), DapError> {
328 let _ = self
329 .transport
330 .send_request("stepIn", serde_json::json!({ "threadId": thread_id }))
331 .await?;
332 self.set_status(DapSessionState::Running).await;
333 Ok(())
334 }
335
336 pub async fn step_out(&self, thread_id: i64) -> Result<(), DapError> {
342 let _ = self
343 .transport
344 .send_request("stepOut", serde_json::json!({ "threadId": thread_id }))
345 .await?;
346 self.set_status(DapSessionState::Running).await;
347 Ok(())
348 }
349
350 pub async fn pause(&self, thread_id: i64) -> Result<(), DapError> {
356 let _ = self
357 .transport
358 .send_request("pause", serde_json::json!({ "threadId": thread_id }))
359 .await?;
360 self.set_status(DapSessionState::Stopped).await;
361 Ok(())
362 }
363
364 pub async fn threads(&self) -> Result<Vec<serde_json::Value>, DapError> {
370 let response = self
371 .transport
372 .send_request("threads", serde_json::json!({}))
373 .await?;
374 Ok(extract_array(&response, "threads"))
375 }
376
377 pub async fn stack_trace(&self, thread_id: i64) -> Result<Vec<serde_json::Value>, DapError> {
383 let response = self
384 .transport
385 .send_request("stackTrace", serde_json::json!({ "threadId": thread_id }))
386 .await?;
387 Ok(extract_array(&response, "stackFrames"))
388 }
389
390 pub async fn scopes(&self, frame_id: i64) -> Result<Vec<serde_json::Value>, DapError> {
396 let response = self
397 .transport
398 .send_request("scopes", serde_json::json!({ "frameId": frame_id }))
399 .await?;
400 Ok(extract_array(&response, "scopes"))
401 }
402
403 pub async fn variables(&self, variables_ref: i64) -> Result<Vec<serde_json::Value>, DapError> {
409 let response = self
410 .transport
411 .send_request(
412 "variables",
413 serde_json::json!({ "variablesReference": variables_ref }),
414 )
415 .await?;
416 Ok(extract_array(&response, "variables"))
417 }
418
419 pub async fn evaluate(
425 &self,
426 expression: &str,
427 frame_id: Option<i64>,
428 ) -> Result<serde_json::Value, DapError> {
429 let mut args = serde_json::json!({
430 "expression": expression,
431 "context": "repl",
432 });
433
434 if let Some(fid) = frame_id
435 && let Some(obj) = args.as_object_mut()
436 {
437 let _ = obj.insert("frameId".to_string(), serde_json::json!(fid));
438 }
439
440 let response = self.transport.send_request("evaluate", args).await?;
441
442 Ok(response
443 .get("body")
444 .cloned()
445 .unwrap_or_else(|| serde_json::json!({})))
446 }
447
448 pub async fn status(&self) -> DapSessionState {
450 *self.status.read().await
451 }
452
453 pub async fn capabilities(&self) -> Option<serde_json::Value> {
455 self.capabilities.read().await.clone()
456 }
457
458 #[must_use]
460 pub const fn transport(&self) -> &Arc<DapTransport> {
461 &self.transport
462 }
463
464 pub async fn active_breakpoints(&self) -> HashMap<String, Vec<serde_json::Value>> {
466 self.active_breakpoints.read().await.clone()
467 }
468
469 pub(crate) async fn set_status(&self, new_state: DapSessionState) {
471 *self.status.write().await = new_state;
472 }
473
474 async fn ensure_initialized(&self) -> Result<(), DapError> {
476 let state = *self.status.read().await;
477 if state == DapSessionState::NotStarted {
478 return Err(DapError::NotReady {
479 state: state.to_string(),
480 });
481 }
482 Ok(())
483 }
484}
485
486fn extract_array(response: &serde_json::Value, field: &str) -> Vec<serde_json::Value> {
488 response
489 .get("body")
490 .and_then(|b| b.get(field))
491 .and_then(serde_json::Value::as_array)
492 .cloned()
493 .unwrap_or_default()
494}