Skip to main content

dscode_dap/
types.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Source {
6    pub name: Option<String>,
7    pub path: Option<String>,
8    #[serde(rename = "sourceReference")]
9    pub source_reference: Option<i64>,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Breakpoint {
14    pub id: Option<i64>,
15    #[serde(default)]
16    pub verified: bool,
17    pub message: Option<String>,
18    pub source: Option<Source>,
19    pub line: Option<i64>,
20    pub column: Option<i64>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct SourceBreakpoint {
25    pub line: i64,
26    pub column: Option<i64>,
27    pub condition: Option<String>,
28    #[serde(rename = "hitCondition")]
29    pub hit_condition: Option<String>,
30    #[serde(rename = "logMessage")]
31    pub log_message: Option<String>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct StackFrame {
36    pub id: i64,
37    pub name: String,
38    pub source: Option<Source>,
39    pub line: i64,
40    pub column: i64,
41    #[serde(rename = "endLine")]
42    pub end_line: Option<i64>,
43    #[serde(rename = "endColumn")]
44    pub end_column: Option<i64>,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct Thread {
49    pub id: i64,
50    pub name: String,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct Variable {
55    pub name: String,
56    pub value: String,
57    #[serde(rename = "type")]
58    pub var_type: Option<String>,
59    #[serde(rename = "variablesReference")]
60    pub variables_reference: i64,
61    #[serde(rename = "namedVariables")]
62    pub named_variables: Option<i64>,
63    #[serde(rename = "indexedVariables")]
64    pub indexed_variables: Option<i64>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct Scope {
69    pub name: String,
70    #[serde(rename = "variablesReference")]
71    pub variables_reference: i64,
72    pub expensive: bool,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76#[serde(rename_all = "camelCase")]
77pub struct LaunchRequestArguments {
78    pub program: String,
79    pub args: Option<Vec<String>>,
80    pub cwd: Option<String>,
81    pub env: Option<HashMap<String, String>>,
82    pub stop_on_entry: Option<bool>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
86pub enum DebugState {
87    Stopped,
88    Initialized,
89    Running,
90    Paused,
91    Terminated,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct DebugSession {
96    pub id: String,
97    pub name: String,
98    pub state: DebugState,
99    pub adapter_type: String,
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_debug_session_serialization() {
108        let session = DebugSession {
109            id: "session-1".to_string(),
110            name: "Debug Main".to_string(),
111            state: DebugState::Running,
112            adapter_type: "cppdbg".to_string(),
113        };
114
115        // Serialize to JSON
116        let json = serde_json::to_string(&session).expect("Failed to serialize DebugSession");
117
118        // Verify key fields are in the JSON output
119        assert!(json.contains("session-1"));
120        assert!(json.contains("Debug Main"));
121        assert!(json.contains("Running"));
122        assert!(json.contains("cppdbg"));
123
124        // Deserialize back and verify round-trip
125        let deserialized: DebugSession =
126            serde_json::from_str(&json).expect("Failed to deserialize DebugSession");
127        assert_eq!(deserialized.id, session.id);
128        assert_eq!(deserialized.name, session.name);
129        assert_eq!(deserialized.state, session.state);
130        assert_eq!(deserialized.adapter_type, session.adapter_type);
131
132        // Test each DebugState variant
133        for state in [
134            DebugState::Stopped,
135            DebugState::Initialized,
136            DebugState::Running,
137            DebugState::Paused,
138            DebugState::Terminated,
139        ] {
140            let s = DebugSession {
141                id: "test".to_string(),
142                name: "test".to_string(),
143                state: state.clone(),
144                adapter_type: "test-adapter".to_string(),
145            };
146            let json = serde_json::to_string(&s).unwrap();
147            let roundtrip: DebugSession = serde_json::from_str(&json).unwrap();
148            assert_eq!(roundtrip.state, state);
149        }
150    }
151
152    #[test]
153    fn test_breakpoint_serialization() {
154        // Test Breakpoint round-trip
155        let bp = Breakpoint {
156            id: Some(42),
157            verified: true,
158            message: Some("Breakpoint set".to_string()),
159            source: Some(Source {
160                name: Some("main.rs".to_string()),
161                path: Some("/src/main.rs".to_string()),
162                source_reference: None,
163            }),
164            line: Some(10),
165            column: Some(5),
166        };
167
168        let json = serde_json::to_string(&bp).expect("Failed to serialize Breakpoint");
169        let roundtrip: Breakpoint = serde_json::from_str(&json).expect("Failed to deserialize Breakpoint");
170        assert_eq!(roundtrip.id, bp.id);
171        assert_eq!(roundtrip.verified, bp.verified);
172        assert_eq!(roundtrip.message, bp.message);
173        assert_eq!(roundtrip.line, bp.line);
174        assert_eq!(roundtrip.column, bp.column);
175
176        // Test SourceBreakpoint round-trip
177        let sbp = SourceBreakpoint {
178            line: 25,
179            column: Some(8),
180            condition: Some("x > 0".to_string()),
181            hit_condition: Some("5".to_string()),
182            log_message: Some("Hit breakpoint at line 25".to_string()),
183        };
184
185        let json = serde_json::to_string(&sbp).expect("Failed to serialize SourceBreakpoint");
186        let roundtrip: SourceBreakpoint =
187            serde_json::from_str(&json).expect("Failed to deserialize SourceBreakpoint");
188        assert_eq!(roundtrip.line, sbp.line);
189        assert_eq!(roundtrip.column, sbp.column);
190        assert_eq!(roundtrip.condition, sbp.condition);
191        assert_eq!(roundtrip.hit_condition, sbp.hit_condition);
192        assert_eq!(roundtrip.log_message, sbp.log_message);
193
194        // Test minimal SourceBreakpoint (only required field)
195        let minimal = SourceBreakpoint {
196            line: 1,
197            column: None,
198            condition: None,
199            hit_condition: None,
200            log_message: None,
201        };
202        let json = serde_json::to_string(&minimal).unwrap();
203        let roundtrip: SourceBreakpoint = serde_json::from_str(&json).unwrap();
204        assert_eq!(roundtrip.line, 1);
205        assert!(roundtrip.column.is_none());
206    }
207}