dap_reactor/
request.rs

1#[cfg(test)]
2mod tests;
3
4use crate::error::{Cause, Error};
5use crate::models::*;
6use crate::protocol::ProtocolRequest;
7use crate::utils;
8
9use serde_json::Value;
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum Request {
14    Attach {
15        arguments: AttachArguments,
16    },
17    Restart {
18        arguments: Option<RestartArguments>,
19    },
20    Disconnect {
21        arguments: Option<DisconnectArguments>,
22    },
23    Terminate {
24        arguments: Option<TerminateArguments>,
25    },
26    BreakpointLocations {
27        arguments: Option<BreakpointLocationsArguments>,
28    },
29    ConfigurationDone {
30        arguments: Option<ConfigurationDoneArguments>,
31    },
32    Continue {
33        arguments: ContinueArguments,
34    },
35    Evaluate {
36        arguments: EvaluateArguments,
37    },
38    ExceptionInfo {
39        arguments: ExceptionInfoArguments,
40    },
41    Goto {
42        arguments: GotoArguments,
43    },
44    Initialize {
45        arguments: InitializeArguments,
46    },
47    Launch {
48        arguments: LaunchArguments,
49    },
50    LoadedSources {
51        arguments: Option<LoadedSourcesArguments>,
52    },
53    Next {
54        arguments: Option<NextArguments>,
55    },
56    ReverseContinue {
57        arguments: ReverseContinueArguments,
58    },
59    Scopes {
60        arguments: ScopesArguments,
61    },
62    SetBreakpoints {
63        arguments: SetBreakpointsArguments,
64    },
65    StackTrace {
66        arguments: StackTraceArguments,
67    },
68    StepBack {
69        arguments: StepBackArguments,
70    },
71    Threads,
72    Variables {
73        arguments: VariablesArguments,
74    },
75    Custom {
76        arguments: Option<Value>,
77    },
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
81pub enum RunInTerminalKind {
82    Integrated,
83    External,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq)]
87pub enum ReverseRequest {
88    RunInTerminal {
89        kind: Option<RunInTerminalKind>,
90        title: Option<String>,
91        cwd: String,
92        args: Vec<String>,
93        env: Option<HashMap<String, Option<String>>>,
94        args_can_be_interpreted_by_shell: bool,
95    },
96}
97
98impl Request {
99    pub fn into_protocol(self, seq: u64) -> ProtocolRequest {
100        let (command, arguments) = match self {
101            Request::Attach { arguments } => {
102                let command = "attach";
103                let arguments = Some(Value::from(arguments));
104
105                (command, arguments)
106            }
107
108            Request::Restart { arguments } => {
109                let command = "restart";
110                let arguments = arguments.map(Value::from);
111
112                (command, arguments)
113            }
114
115            Request::Disconnect { arguments } => {
116                let command = "disconnect";
117                let arguments = arguments.map(Value::from);
118
119                (command, arguments)
120            }
121
122            Request::Terminate { arguments } => {
123                let command = "terminate";
124                let arguments = arguments.map(Value::from);
125
126                (command, arguments)
127            }
128
129            Request::BreakpointLocations { arguments } => {
130                let command = "breakpointLocations";
131                let arguments = arguments.map(Value::from);
132
133                (command, arguments)
134            }
135
136            Request::ConfigurationDone { arguments } => {
137                let command = "configurationDone";
138                let arguments = arguments.map(Value::from);
139
140                (command, arguments)
141            }
142
143            Request::Continue { arguments } => {
144                let command = "continue";
145                let arguments = arguments.into();
146
147                (command, Some(arguments))
148            }
149
150            Request::Evaluate { arguments } => {
151                let command = "evaluate";
152                let arguments = arguments.into();
153
154                (command, Some(arguments))
155            }
156
157            Request::ExceptionInfo { arguments } => {
158                let command = "exceptionInfo";
159                let arguments = arguments.into();
160
161                (command, Some(arguments))
162            }
163
164            Request::Goto { arguments } => {
165                let command = "goto";
166                let arguments = arguments.into();
167
168                (command, Some(arguments))
169            }
170
171            Request::Initialize { arguments } => {
172                let command = "initialize";
173                let arguments = arguments.into();
174
175                (command, Some(arguments))
176            }
177
178            Request::Launch { arguments } => {
179                let command = "launch";
180                let arguments = arguments.into();
181
182                (command, Some(arguments))
183            }
184
185            Request::LoadedSources { arguments } => {
186                let command = "loadedSources";
187                let arguments = arguments.into();
188
189                (command, Some(arguments))
190            }
191
192            Request::Next { arguments } => {
193                let command = "next";
194                let arguments = arguments.into();
195
196                (command, Some(arguments))
197            }
198
199            Request::ReverseContinue { arguments } => {
200                let command = "reverseContinue";
201                let arguments = arguments.into();
202
203                (command, Some(arguments))
204            }
205
206            Request::Scopes { arguments } => {
207                let command = "scopes";
208                let arguments = arguments.into();
209
210                (command, Some(arguments))
211            }
212
213            Request::SetBreakpoints { arguments } => {
214                let command = "setBreakpoints";
215                let arguments = arguments.into();
216
217                (command, Some(arguments))
218            }
219
220            Request::StackTrace { arguments } => {
221                let command = "stackTrace";
222                let arguments = arguments.into();
223
224                (command, Some(arguments))
225            }
226
227            Request::StepBack { arguments } => {
228                let command = "stepBack";
229                let arguments = arguments.into();
230
231                (command, Some(arguments))
232            }
233
234            Request::Threads => {
235                let command = "threads";
236
237                (command, None)
238            }
239
240            Request::Variables { arguments } => {
241                let command = "variables";
242                let arguments = arguments.into();
243
244                (command, Some(arguments))
245            }
246
247            Request::Custom { arguments } => {
248                let command = "custom";
249
250                (command, arguments)
251            }
252        };
253
254        ProtocolRequest {
255            seq,
256            command: command.to_string(),
257            arguments,
258        }
259    }
260}
261
262impl TryFrom<&ProtocolRequest> for Request {
263    type Error = Error;
264
265    fn try_from(rq: &ProtocolRequest) -> Result<Self, Self::Error> {
266        let arguments = rq.arguments.as_ref().and_then(|b| b.as_object());
267
268        match rq.command.as_str() {
269            "attach" => {
270                let arguments =
271                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
272
273                let arguments = AttachArguments::from(arguments);
274
275                Ok(Self::Attach { arguments })
276            }
277
278            "restart" => {
279                let arguments = arguments.map(RestartArguments::try_from).transpose()?;
280
281                Ok(Self::Restart { arguments })
282            }
283
284            "disconnect" => {
285                let arguments = arguments.map(DisconnectArguments::try_from).transpose()?;
286
287                Ok(Self::Disconnect { arguments })
288            }
289
290            "terminate" => {
291                let arguments = arguments.map(TerminateArguments::try_from).transpose()?;
292
293                Ok(Self::Terminate { arguments })
294            }
295
296            "breakpointLocations" => {
297                let arguments = arguments
298                    .map(BreakpointLocationsArguments::try_from)
299                    .transpose()?;
300
301                Ok(Self::BreakpointLocations { arguments })
302            }
303
304            "configurationDone" => {
305                let arguments = arguments.map(ConfigurationDoneArguments::from);
306
307                Ok(Self::ConfigurationDone { arguments })
308            }
309
310            "continue" => {
311                let arguments =
312                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
313
314                let arguments = ContinueArguments::try_from(arguments)?;
315
316                Ok(Self::Continue { arguments })
317            }
318
319            "evaluate" => {
320                let arguments =
321                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
322
323                let arguments = EvaluateArguments::try_from(arguments)?;
324
325                Ok(Self::Evaluate { arguments })
326            }
327
328            "exceptionInfo" => {
329                let arguments =
330                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
331
332                let arguments = ExceptionInfoArguments::try_from(arguments)?;
333
334                Ok(Self::ExceptionInfo { arguments })
335            }
336
337            "goto" => {
338                let arguments =
339                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
340
341                let arguments = GotoArguments::try_from(arguments)?;
342
343                Ok(Self::Goto { arguments })
344            }
345
346            "initialize" => {
347                let arguments =
348                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
349
350                let arguments = InitializeArguments::try_from(arguments)?;
351
352                Ok(Self::Initialize { arguments })
353            }
354
355            "launch" => {
356                let arguments =
357                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
358
359                let arguments = LaunchArguments::try_from(arguments)?;
360
361                Ok(Self::Launch { arguments })
362            }
363
364            "loadedSources" => {
365                let arguments = arguments.map(LoadedSourcesArguments::from);
366
367                Ok(Self::LoadedSources { arguments })
368            }
369
370            "next" => {
371                let arguments = arguments.map(NextArguments::try_from).transpose()?;
372
373                Ok(Self::Next { arguments })
374            }
375
376            "reverseContinue" => {
377                let arguments =
378                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
379
380                let arguments = ReverseContinueArguments::try_from(arguments)?;
381
382                Ok(Self::ReverseContinue { arguments })
383            }
384
385            "scopes" => {
386                let arguments =
387                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
388
389                let arguments = ScopesArguments::try_from(arguments)?;
390
391                Ok(Self::Scopes { arguments })
392            }
393
394            "setBreakpoints" => {
395                let arguments =
396                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
397
398                let arguments = SetBreakpointsArguments::try_from(arguments)?;
399
400                Ok(Self::SetBreakpoints { arguments })
401            }
402
403            "stackTrace" => {
404                let arguments =
405                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
406
407                let arguments = StackTraceArguments::try_from(arguments)?;
408
409                Ok(Self::StackTrace { arguments })
410            }
411
412            "stepBack" => {
413                let arguments =
414                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
415
416                let arguments = StepBackArguments::try_from(arguments)?;
417
418                Ok(Self::StepBack { arguments })
419            }
420
421            "threads" => Ok(Self::Threads),
422
423            "variables" => {
424                let arguments =
425                    arguments.ok_or_else(|| Error::new("arguments", Cause::IsMandatory))?;
426
427                let arguments = VariablesArguments::try_from(arguments)?;
428
429                Ok(Self::Variables { arguments })
430            }
431
432            "custom" => {
433                let arguments = rq.arguments.as_ref().cloned();
434
435                Ok(Self::Custom { arguments })
436            }
437
438            _ => Err(Error::new("request", Cause::ExpectsEnum)),
439        }
440    }
441}
442
443impl From<RunInTerminalKind> for String {
444    fn from(k: RunInTerminalKind) -> Self {
445        match k {
446            RunInTerminalKind::Integrated => "integrated".to_string(),
447            RunInTerminalKind::External => "external".to_string(),
448        }
449    }
450}
451
452impl TryFrom<&str> for RunInTerminalKind {
453    type Error = Error;
454
455    fn try_from(s: &str) -> Result<Self, Self::Error> {
456        match s {
457            "integrated" => Ok(Self::Integrated),
458            "external" => Ok(Self::External),
459            _ => Err(Error::new("kind", Cause::ExpectsEnum)),
460        }
461    }
462}
463
464impl ReverseRequest {
465    pub fn into_protocol(self, seq: u64) -> ProtocolRequest {
466        let (command, arguments) = match self {
467            ReverseRequest::RunInTerminal {
468                kind,
469                title,
470                cwd,
471                args,
472                env,
473                args_can_be_interpreted_by_shell,
474            } => {
475                let command = "runInTerminal";
476
477                let kind = utils::attribute_string_optional("kind", kind);
478                let title = utils::attribute_string_optional("title", title);
479                let cwd = utils::attribute_string("cwd", cwd);
480                let args = utils::attribute_array("args", args);
481                let env = utils::attribute_map_optional("env", env);
482                let args_can_be_interpreted_by_shell = utils::attribute_bool_optional(
483                    "argsCanBeInterpretedByShell",
484                    args_can_be_interpreted_by_shell,
485                );
486
487                let arguments = utils::finalize_object(
488                    kind.chain(title)
489                        .chain(cwd)
490                        .chain(args)
491                        .chain(env)
492                        .chain(args_can_be_interpreted_by_shell),
493                );
494
495                (command, Some(arguments))
496            }
497        };
498
499        ProtocolRequest {
500            seq,
501            command: command.to_string(),
502            arguments,
503        }
504    }
505}
506
507impl TryFrom<&ProtocolRequest> for ReverseRequest {
508    type Error = Error;
509
510    fn try_from(rq: &ProtocolRequest) -> Result<Self, Self::Error> {
511        let arguments = rq.arguments.as_ref().and_then(|b| b.as_object());
512
513        match rq.command.as_str() {
514            "runInTerminal" => {
515                let map = arguments.ok_or(Error::new("arguments", Cause::IsMandatory))?;
516
517                let kind = utils::get_str_optional(map, "kind")?
518                    .map(RunInTerminalKind::try_from)
519                    .transpose()?;
520
521                let title = utils::get_string_optional(map, "title")?;
522                let cwd = utils::get_string(map, "cwd")?;
523                let args = utils::get_array_of_string(map, "args")?;
524                let env = utils::get_map_to_string_or_null_optional(map, "env")?;
525                let args_can_be_interpreted_by_shell =
526                    utils::get_bool_optional(map, "argsCanBeInterpretedByShell")?;
527
528                Ok(Self::RunInTerminal {
529                    kind,
530                    title,
531                    cwd,
532                    args,
533                    env,
534                    args_can_be_interpreted_by_shell,
535                })
536            }
537
538            _ => Err(Error::new("reverseRequest", Cause::ExpectsEnum)),
539        }
540    }
541}