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}