1use anyhow::{Context as _, Result};
2use client::proto::{
3 self, DapChecksum, DapChecksumAlgorithm, DapEvaluateContext, DapModule, DapScope,
4 DapScopePresentationHint, DapSource, DapSourcePresentationHint, DapStackFrame, DapVariable,
5};
6use dap_types::{OutputEventCategory, OutputEventGroup, ScopePresentationHint, Source};
7
8pub trait ProtoConversion {
9 type ProtoType;
10 type Output;
11
12 fn to_proto(&self) -> Self::ProtoType;
13 fn from_proto(payload: Self::ProtoType) -> Self::Output;
14}
15
16impl<T> ProtoConversion for Vec<T>
17where
18 T: ProtoConversion<Output = T>,
19{
20 type ProtoType = Vec<T::ProtoType>;
21 type Output = Self;
22
23 fn to_proto(&self) -> Self::ProtoType {
24 self.iter().map(|item| item.to_proto()).collect()
25 }
26
27 fn from_proto(payload: Self::ProtoType) -> Self {
28 payload
29 .into_iter()
30 .map(|item| T::from_proto(item))
31 .collect()
32 }
33}
34
35impl ProtoConversion for dap_types::Scope {
36 type ProtoType = DapScope;
37 type Output = Self;
38
39 fn to_proto(&self) -> Self::ProtoType {
40 Self::ProtoType {
41 name: self.name.clone(),
42 presentation_hint: self
43 .presentation_hint
44 .as_ref()
45 .map(|hint| hint.to_proto().into()),
46 variables_reference: self.variables_reference,
47 named_variables: self.named_variables,
48 indexed_variables: self.indexed_variables,
49 expensive: self.expensive,
50 source: self.source.as_ref().map(Source::to_proto),
51 line: self.line,
52 end_line: self.end_line,
53 column: self.column,
54 end_column: self.end_column,
55 }
56 }
57
58 fn from_proto(payload: Self::ProtoType) -> Self {
59 let presentation_hint = payload
60 .presentation_hint
61 .and_then(DapScopePresentationHint::from_i32);
62 Self {
63 name: payload.name,
64 presentation_hint: presentation_hint.map(ScopePresentationHint::from_proto),
65 variables_reference: payload.variables_reference,
66 named_variables: payload.named_variables,
67 indexed_variables: payload.indexed_variables,
68 expensive: payload.expensive,
69 source: payload.source.map(dap_types::Source::from_proto),
70 line: payload.line,
71 end_line: payload.end_line,
72 column: payload.column,
73 end_column: payload.end_column,
74 }
75 }
76}
77
78impl ProtoConversion for dap_types::Variable {
79 type ProtoType = DapVariable;
80 type Output = Self;
81
82 fn to_proto(&self) -> Self::ProtoType {
83 Self::ProtoType {
84 name: self.name.clone(),
85 value: self.value.clone(),
86 r#type: self.type_.clone(),
87 evaluate_name: self.evaluate_name.clone(),
88 variables_reference: self.variables_reference,
89 named_variables: self.named_variables,
90 indexed_variables: self.indexed_variables,
91 memory_reference: self.memory_reference.clone(),
92 }
93 }
94
95 fn from_proto(payload: Self::ProtoType) -> Self {
96 Self {
97 name: payload.name,
98 value: payload.value,
99 type_: payload.r#type,
100 evaluate_name: payload.evaluate_name,
101 presentation_hint: None, // TODO Debugger Collab Add this
102 variables_reference: payload.variables_reference,
103 named_variables: payload.named_variables,
104 indexed_variables: payload.indexed_variables,
105 memory_reference: payload.memory_reference,
106 declaration_location_reference: None, // TODO
107 value_location_reference: None, // TODO
108 }
109 }
110}
111
112impl ProtoConversion for dap_types::ScopePresentationHint {
113 type ProtoType = DapScopePresentationHint;
114 type Output = Self;
115
116 fn to_proto(&self) -> Self::ProtoType {
117 match self {
118 dap_types::ScopePresentationHint::Locals => DapScopePresentationHint::Locals,
119 dap_types::ScopePresentationHint::Arguments => DapScopePresentationHint::Arguments,
120 dap_types::ScopePresentationHint::Registers => DapScopePresentationHint::Registers,
121 dap_types::ScopePresentationHint::ReturnValue => DapScopePresentationHint::ReturnValue,
122 dap_types::ScopePresentationHint::Unknown => DapScopePresentationHint::ScopeUnknown,
123 &_ => unreachable!(),
124 }
125 }
126
127 fn from_proto(payload: Self::ProtoType) -> Self {
128 match payload {
129 DapScopePresentationHint::Locals => dap_types::ScopePresentationHint::Locals,
130 DapScopePresentationHint::Arguments => dap_types::ScopePresentationHint::Arguments,
131 DapScopePresentationHint::Registers => dap_types::ScopePresentationHint::Registers,
132 DapScopePresentationHint::ReturnValue => dap_types::ScopePresentationHint::ReturnValue,
133 DapScopePresentationHint::ScopeUnknown => dap_types::ScopePresentationHint::Unknown,
134 }
135 }
136}
137
138impl ProtoConversion for dap_types::SourcePresentationHint {
139 type ProtoType = DapSourcePresentationHint;
140 type Output = Self;
141
142 fn to_proto(&self) -> Self::ProtoType {
143 match self {
144 dap_types::SourcePresentationHint::Normal => DapSourcePresentationHint::SourceNormal,
145 dap_types::SourcePresentationHint::Emphasize => DapSourcePresentationHint::Emphasize,
146 dap_types::SourcePresentationHint::Deemphasize => {
147 DapSourcePresentationHint::Deemphasize
148 }
149 dap_types::SourcePresentationHint::Unknown => DapSourcePresentationHint::SourceUnknown,
150 }
151 }
152
153 fn from_proto(payload: Self::ProtoType) -> Self {
154 match payload {
155 DapSourcePresentationHint::SourceNormal => dap_types::SourcePresentationHint::Normal,
156 DapSourcePresentationHint::Emphasize => dap_types::SourcePresentationHint::Emphasize,
157 DapSourcePresentationHint::Deemphasize => {
158 dap_types::SourcePresentationHint::Deemphasize
159 }
160 DapSourcePresentationHint::SourceUnknown => dap_types::SourcePresentationHint::Unknown,
161 }
162 }
163}
164
165impl ProtoConversion for dap_types::Checksum {
166 type ProtoType = DapChecksum;
167 type Output = Self;
168
169 fn to_proto(&self) -> Self::ProtoType {
170 DapChecksum {
171 algorithm: self.algorithm.to_proto().into(),
172 checksum: self.checksum.clone(),
173 }
174 }
175
176 fn from_proto(payload: Self::ProtoType) -> Self {
177 Self {
178 algorithm: dap_types::ChecksumAlgorithm::from_proto(payload.algorithm()),
179 checksum: payload.checksum,
180 }
181 }
182}
183
184impl ProtoConversion for dap_types::ChecksumAlgorithm {
185 type ProtoType = DapChecksumAlgorithm;
186 type Output = Self;
187
188 fn to_proto(&self) -> Self::ProtoType {
189 match self {
190 dap_types::ChecksumAlgorithm::Md5 => DapChecksumAlgorithm::Md5,
191 dap_types::ChecksumAlgorithm::Sha1 => DapChecksumAlgorithm::Sha1,
192 dap_types::ChecksumAlgorithm::Sha256 => DapChecksumAlgorithm::Sha256,
193 dap_types::ChecksumAlgorithm::Timestamp => DapChecksumAlgorithm::Timestamp,
194 }
195 }
196
197 fn from_proto(payload: Self::ProtoType) -> Self {
198 match payload {
199 DapChecksumAlgorithm::Md5 => dap_types::ChecksumAlgorithm::Md5,
200 DapChecksumAlgorithm::Sha1 => dap_types::ChecksumAlgorithm::Sha1,
201 DapChecksumAlgorithm::Sha256 => dap_types::ChecksumAlgorithm::Sha256,
202 DapChecksumAlgorithm::Timestamp => dap_types::ChecksumAlgorithm::Timestamp,
203 DapChecksumAlgorithm::ChecksumAlgorithmUnspecified => unreachable!(),
204 }
205 }
206}
207
208impl ProtoConversion for dap_types::Source {
209 type ProtoType = DapSource;
210 type Output = Self;
211
212 fn to_proto(&self) -> Self::ProtoType {
213 Self::ProtoType {
214 name: self.name.clone(),
215 path: self.path.clone(),
216 source_reference: self.source_reference,
217 presentation_hint: self.presentation_hint.map(|hint| hint.to_proto().into()),
218 origin: self.origin.clone(),
219 sources: self
220 .sources
221 .clone()
222 .map(|src| src.to_proto())
223 .unwrap_or_default(),
224 adapter_data: Default::default(), // TODO Debugger Collab
225 checksums: self
226 .checksums
227 .clone()
228 .map(|c| c.to_proto())
229 .unwrap_or_default(),
230 }
231 }
232
233 fn from_proto(payload: Self::ProtoType) -> Self {
234 Self {
235 name: payload.name.clone(),
236 path: payload.path.clone(),
237 source_reference: payload.source_reference,
238 presentation_hint: payload
239 .presentation_hint
240 .and_then(DapSourcePresentationHint::from_i32)
241 .map(dap_types::SourcePresentationHint::from_proto),
242 origin: payload.origin.clone(),
243 sources: Some(Vec::<dap_types::Source>::from_proto(payload.sources)),
244 checksums: Some(Vec::<dap_types::Checksum>::from_proto(payload.checksums)),
245 adapter_data: None, // TODO Debugger Collab
246 }
247 }
248}
249
250impl ProtoConversion for dap_types::StackFrame {
251 type ProtoType = DapStackFrame;
252 type Output = Self;
253
254 fn to_proto(&self) -> Self::ProtoType {
255 Self::ProtoType {
256 id: self.id,
257 name: self.name.clone(),
258 source: self.source.as_ref().map(|src| src.to_proto()),
259 line: self.line,
260 column: self.column,
261 end_line: self.end_line,
262 end_column: self.end_column,
263 can_restart: self.can_restart,
264 instruction_pointer_reference: self.instruction_pointer_reference.clone(),
265 module_id: None, // TODO Debugger Collab
266 presentation_hint: None, // TODO Debugger Collab
267 }
268 }
269
270 fn from_proto(payload: Self::ProtoType) -> Self {
271 Self {
272 id: payload.id,
273 name: payload.name,
274 source: payload.source.map(dap_types::Source::from_proto),
275 line: payload.line,
276 column: payload.column,
277 end_line: payload.end_line,
278 end_column: payload.end_column,
279 can_restart: payload.can_restart,
280 instruction_pointer_reference: payload.instruction_pointer_reference,
281 module_id: None, // TODO Debugger Collab
282 presentation_hint: None, // TODO Debugger Collab
283 }
284 }
285}
286
287impl ProtoConversion for dap_types::Module {
288 type ProtoType = DapModule;
289 type Output = Result<Self>;
290
291 fn to_proto(&self) -> Self::ProtoType {
292 let id = match &self.id {
293 dap_types::ModuleId::Number(num) => proto::dap_module_id::Id::Number(*num),
294 dap_types::ModuleId::String(string) => proto::dap_module_id::Id::String(string.clone()),
295 };
296
297 DapModule {
298 id: Some(proto::DapModuleId { id: Some(id) }),
299 name: self.name.clone(),
300 path: self.path.clone(),
301 is_optimized: self.is_optimized,
302 is_user_code: self.is_user_code,
303 version: self.version.clone(),
304 symbol_status: self.symbol_status.clone(),
305 symbol_file_path: self.symbol_file_path.clone(),
306 date_time_stamp: self.date_time_stamp.clone(),
307 address_range: self.address_range.clone(),
308 }
309 }
310
311 fn from_proto(payload: Self::ProtoType) -> Result<Self> {
312 let id = match payload
313 .id
314 .context("All DapModule proto messages must have an id")?
315 .id
316 .context("All DapModuleID proto messages must have an id")?
317 {
318 proto::dap_module_id::Id::String(string) => dap_types::ModuleId::String(string),
319 proto::dap_module_id::Id::Number(num) => dap_types::ModuleId::Number(num),
320 };
321
322 Ok(Self {
323 id,
324 name: payload.name,
325 path: payload.path,
326 is_optimized: payload.is_optimized,
327 is_user_code: payload.is_user_code,
328 version: payload.version,
329 symbol_status: payload.symbol_status,
330 symbol_file_path: payload.symbol_file_path,
331 date_time_stamp: payload.date_time_stamp,
332 address_range: payload.address_range,
333 })
334 }
335}
336
337impl ProtoConversion for dap_types::SteppingGranularity {
338 type ProtoType = proto::SteppingGranularity;
339 type Output = Self;
340
341 fn to_proto(&self) -> Self::ProtoType {
342 match self {
343 dap_types::SteppingGranularity::Statement => proto::SteppingGranularity::Statement,
344 dap_types::SteppingGranularity::Line => proto::SteppingGranularity::Line,
345 dap_types::SteppingGranularity::Instruction => proto::SteppingGranularity::Instruction,
346 }
347 }
348
349 fn from_proto(payload: Self::ProtoType) -> Self {
350 match payload {
351 proto::SteppingGranularity::Line => dap_types::SteppingGranularity::Line,
352 proto::SteppingGranularity::Instruction => dap_types::SteppingGranularity::Instruction,
353 proto::SteppingGranularity::Statement => dap_types::SteppingGranularity::Statement,
354 }
355 }
356}
357
358impl ProtoConversion for dap_types::OutputEventCategory {
359 type ProtoType = proto::DapOutputCategory;
360 type Output = Self;
361
362 fn to_proto(&self) -> Self::ProtoType {
363 match self {
364 Self::Console => proto::DapOutputCategory::ConsoleOutput,
365 Self::Important => proto::DapOutputCategory::Important,
366 Self::Stdout => proto::DapOutputCategory::Stdout,
367 Self::Stderr => proto::DapOutputCategory::Stderr,
368 _ => proto::DapOutputCategory::Unknown,
369 }
370 }
371
372 fn from_proto(payload: Self::ProtoType) -> Self {
373 match payload {
374 proto::DapOutputCategory::ConsoleOutput => Self::Console,
375 proto::DapOutputCategory::Important => Self::Important,
376 proto::DapOutputCategory::Stdout => Self::Stdout,
377 proto::DapOutputCategory::Stderr => Self::Stderr,
378 proto::DapOutputCategory::Unknown => Self::Unknown,
379 }
380 }
381}
382
383impl ProtoConversion for dap_types::OutputEvent {
384 type ProtoType = proto::DapOutputEvent;
385 type Output = Self;
386
387 fn to_proto(&self) -> Self::ProtoType {
388 proto::DapOutputEvent {
389 category: self
390 .category
391 .as_ref()
392 .map(|category| category.to_proto().into()),
393 output: self.output.clone(),
394 variables_reference: self.variables_reference,
395 source: self.source.as_ref().map(|source| source.to_proto()),
396 line: self.line.map(|line| line as u32),
397 column: self.column.map(|column| column as u32),
398 group: self.group.map(|group| group.to_proto().into()),
399 }
400 }
401
402 fn from_proto(payload: Self::ProtoType) -> Self {
403 dap_types::OutputEvent {
404 category: payload
405 .category
406 .and_then(proto::DapOutputCategory::from_i32)
407 .map(OutputEventCategory::from_proto),
408 output: payload.output.clone(),
409 variables_reference: payload.variables_reference,
410 source: payload.source.map(Source::from_proto),
411 line: payload.line.map(|line| line as u64),
412 column: payload.column.map(|column| column as u64),
413 group: payload
414 .group
415 .and_then(proto::DapOutputEventGroup::from_i32)
416 .map(OutputEventGroup::from_proto),
417 data: None,
418 location_reference: None,
419 }
420 }
421}
422
423impl ProtoConversion for dap_types::OutputEventGroup {
424 type ProtoType = proto::DapOutputEventGroup;
425 type Output = Self;
426
427 fn to_proto(&self) -> Self::ProtoType {
428 match self {
429 dap_types::OutputEventGroup::Start => proto::DapOutputEventGroup::Start,
430 dap_types::OutputEventGroup::StartCollapsed => {
431 proto::DapOutputEventGroup::StartCollapsed
432 }
433 dap_types::OutputEventGroup::End => proto::DapOutputEventGroup::End,
434 }
435 }
436
437 fn from_proto(payload: Self::ProtoType) -> Self {
438 match payload {
439 proto::DapOutputEventGroup::Start => Self::Start,
440 proto::DapOutputEventGroup::StartCollapsed => Self::StartCollapsed,
441 proto::DapOutputEventGroup::End => Self::End,
442 }
443 }
444}
445
446impl ProtoConversion for dap_types::CompletionItem {
447 type ProtoType = proto::DapCompletionItem;
448 type Output = Self;
449
450 fn to_proto(&self) -> Self::ProtoType {
451 proto::DapCompletionItem {
452 label: self.label.clone(),
453 text: self.text.clone(),
454 detail: self.detail.clone(),
455 typ: self
456 .type_
457 .as_ref()
458 .map(ProtoConversion::to_proto)
459 .map(|typ| typ.into()),
460 start: self.start,
461 length: self.length,
462 selection_start: self.selection_start,
463 selection_length: self.selection_length,
464 sort_text: self.sort_text.clone(),
465 }
466 }
467
468 fn from_proto(payload: Self::ProtoType) -> Self {
469 let typ = payload.typ(); // todo(debugger): This might be a potential issue/bug because it defaults to a type when it's None
470
471 Self {
472 label: payload.label,
473 detail: payload.detail,
474 sort_text: payload.sort_text,
475 text: payload.text.clone(),
476 type_: Some(dap_types::CompletionItemType::from_proto(typ)),
477 start: payload.start,
478 length: payload.length,
479 selection_start: payload.selection_start,
480 selection_length: payload.selection_length,
481 }
482 }
483}
484
485impl ProtoConversion for dap_types::EvaluateArgumentsContext {
486 type ProtoType = DapEvaluateContext;
487 type Output = Self;
488
489 fn to_proto(&self) -> Self::ProtoType {
490 match self {
491 dap_types::EvaluateArgumentsContext::Variables => {
492 proto::DapEvaluateContext::EvaluateVariables
493 }
494 dap_types::EvaluateArgumentsContext::Watch => proto::DapEvaluateContext::Watch,
495 dap_types::EvaluateArgumentsContext::Hover => proto::DapEvaluateContext::Hover,
496 dap_types::EvaluateArgumentsContext::Repl => proto::DapEvaluateContext::Repl,
497 dap_types::EvaluateArgumentsContext::Clipboard => proto::DapEvaluateContext::Clipboard,
498 dap_types::EvaluateArgumentsContext::Unknown => {
499 proto::DapEvaluateContext::EvaluateUnknown
500 }
501 _ => proto::DapEvaluateContext::EvaluateUnknown,
502 }
503 }
504
505 fn from_proto(payload: Self::ProtoType) -> Self {
506 match payload {
507 proto::DapEvaluateContext::EvaluateVariables => {
508 dap_types::EvaluateArgumentsContext::Variables
509 }
510 proto::DapEvaluateContext::Watch => dap_types::EvaluateArgumentsContext::Watch,
511 proto::DapEvaluateContext::Hover => dap_types::EvaluateArgumentsContext::Hover,
512 proto::DapEvaluateContext::Repl => dap_types::EvaluateArgumentsContext::Repl,
513 proto::DapEvaluateContext::Clipboard => dap_types::EvaluateArgumentsContext::Clipboard,
514 proto::DapEvaluateContext::EvaluateUnknown => {
515 dap_types::EvaluateArgumentsContext::Unknown
516 }
517 }
518 }
519}
520
521impl ProtoConversion for dap_types::CompletionItemType {
522 type ProtoType = proto::DapCompletionItemType;
523 type Output = Self;
524
525 fn to_proto(&self) -> Self::ProtoType {
526 match self {
527 dap_types::CompletionItemType::Class => proto::DapCompletionItemType::Class,
528 dap_types::CompletionItemType::Color => proto::DapCompletionItemType::Color,
529 dap_types::CompletionItemType::Constructor => proto::DapCompletionItemType::Constructor,
530 dap_types::CompletionItemType::Customcolor => proto::DapCompletionItemType::Customcolor,
531 dap_types::CompletionItemType::Enum => proto::DapCompletionItemType::Enum,
532 dap_types::CompletionItemType::Field => proto::DapCompletionItemType::Field,
533 dap_types::CompletionItemType::File => proto::DapCompletionItemType::CompletionItemFile,
534 dap_types::CompletionItemType::Function => proto::DapCompletionItemType::Function,
535 dap_types::CompletionItemType::Interface => proto::DapCompletionItemType::Interface,
536 dap_types::CompletionItemType::Keyword => proto::DapCompletionItemType::Keyword,
537 dap_types::CompletionItemType::Method => proto::DapCompletionItemType::Method,
538 dap_types::CompletionItemType::Module => proto::DapCompletionItemType::Module,
539 dap_types::CompletionItemType::Property => proto::DapCompletionItemType::Property,
540 dap_types::CompletionItemType::Reference => proto::DapCompletionItemType::Reference,
541 dap_types::CompletionItemType::Snippet => proto::DapCompletionItemType::Snippet,
542 dap_types::CompletionItemType::Text => proto::DapCompletionItemType::Text,
543 dap_types::CompletionItemType::Unit => proto::DapCompletionItemType::Unit,
544 dap_types::CompletionItemType::Value => proto::DapCompletionItemType::Value,
545 dap_types::CompletionItemType::Variable => proto::DapCompletionItemType::Variable,
546 }
547 }
548
549 fn from_proto(payload: Self::ProtoType) -> Self {
550 match payload {
551 proto::DapCompletionItemType::Class => dap_types::CompletionItemType::Class,
552 proto::DapCompletionItemType::Color => dap_types::CompletionItemType::Color,
553 proto::DapCompletionItemType::CompletionItemFile => dap_types::CompletionItemType::File,
554 proto::DapCompletionItemType::Constructor => dap_types::CompletionItemType::Constructor,
555 proto::DapCompletionItemType::Customcolor => dap_types::CompletionItemType::Customcolor,
556 proto::DapCompletionItemType::Enum => dap_types::CompletionItemType::Enum,
557 proto::DapCompletionItemType::Field => dap_types::CompletionItemType::Field,
558 proto::DapCompletionItemType::Function => dap_types::CompletionItemType::Function,
559 proto::DapCompletionItemType::Interface => dap_types::CompletionItemType::Interface,
560 proto::DapCompletionItemType::Keyword => dap_types::CompletionItemType::Keyword,
561 proto::DapCompletionItemType::Method => dap_types::CompletionItemType::Method,
562 proto::DapCompletionItemType::Module => dap_types::CompletionItemType::Module,
563 proto::DapCompletionItemType::Property => dap_types::CompletionItemType::Property,
564 proto::DapCompletionItemType::Reference => dap_types::CompletionItemType::Reference,
565 proto::DapCompletionItemType::Snippet => dap_types::CompletionItemType::Snippet,
566 proto::DapCompletionItemType::Text => dap_types::CompletionItemType::Text,
567 proto::DapCompletionItemType::Unit => dap_types::CompletionItemType::Unit,
568 proto::DapCompletionItemType::Value => dap_types::CompletionItemType::Value,
569 proto::DapCompletionItemType::Variable => dap_types::CompletionItemType::Variable,
570 }
571 }
572}
573
574impl ProtoConversion for dap_types::Thread {
575 type ProtoType = proto::DapThread;
576 type Output = Self;
577
578 fn to_proto(&self) -> Self::ProtoType {
579 proto::DapThread {
580 id: self.id,
581 name: self.name.clone(),
582 }
583 }
584
585 fn from_proto(payload: Self::ProtoType) -> Self {
586 Self {
587 id: payload.id,
588 name: payload.name,
589 }
590 }
591}