proto_conversions.rs

  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}