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