proto.rs

  1use crate::{
  2    diagnostic_set::DiagnosticEntry, CodeAction, CodeLabel, Completion, Diagnostic, Language,
  3    Operation,
  4};
  5use anyhow::{anyhow, Result};
  6use clock::ReplicaId;
  7use lsp::DiagnosticSeverity;
  8use rpc::proto;
  9use std::{ops::Range, sync::Arc};
 10use text::*;
 11
 12pub use proto::{Buffer, BufferState, LineEnding, SelectionSet};
 13
 14pub fn deserialize_line_ending(message: proto::LineEnding) -> text::LineEnding {
 15    match message {
 16        LineEnding::Unix => text::LineEnding::Unix,
 17        LineEnding::Windows => text::LineEnding::Windows,
 18    }
 19}
 20
 21pub fn serialize_line_ending(message: text::LineEnding) -> proto::LineEnding {
 22    match message {
 23        text::LineEnding::Unix => proto::LineEnding::Unix,
 24        text::LineEnding::Windows => proto::LineEnding::Windows,
 25    }
 26}
 27
 28pub fn serialize_operation(operation: &Operation) -> proto::Operation {
 29    proto::Operation {
 30        variant: Some(match operation {
 31            Operation::Buffer(text::Operation::Edit(edit)) => {
 32                proto::operation::Variant::Edit(serialize_edit_operation(edit))
 33            }
 34            Operation::Buffer(text::Operation::Undo {
 35                undo,
 36                lamport_timestamp,
 37            }) => proto::operation::Variant::Undo(proto::operation::Undo {
 38                replica_id: undo.id.replica_id as u32,
 39                local_timestamp: undo.id.value,
 40                lamport_timestamp: lamport_timestamp.value,
 41                version: serialize_version(&undo.version),
 42                transaction_ranges: undo
 43                    .transaction_ranges
 44                    .iter()
 45                    .map(serialize_range)
 46                    .collect(),
 47                transaction_version: serialize_version(&undo.transaction_version),
 48                counts: undo
 49                    .counts
 50                    .iter()
 51                    .map(|(edit_id, count)| proto::UndoCount {
 52                        replica_id: edit_id.replica_id as u32,
 53                        local_timestamp: edit_id.value,
 54                        count: *count,
 55                    })
 56                    .collect(),
 57            }),
 58            Operation::UpdateSelections {
 59                selections,
 60                line_mode,
 61                lamport_timestamp,
 62            } => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
 63                replica_id: lamport_timestamp.replica_id as u32,
 64                lamport_timestamp: lamport_timestamp.value,
 65                selections: serialize_selections(selections),
 66                line_mode: *line_mode,
 67            }),
 68            Operation::UpdateDiagnostics {
 69                diagnostics,
 70                lamport_timestamp,
 71            } => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics {
 72                replica_id: lamport_timestamp.replica_id as u32,
 73                lamport_timestamp: lamport_timestamp.value,
 74                diagnostics: serialize_diagnostics(diagnostics.iter()),
 75            }),
 76            Operation::UpdateCompletionTriggers {
 77                triggers,
 78                lamport_timestamp,
 79            } => proto::operation::Variant::UpdateCompletionTriggers(
 80                proto::operation::UpdateCompletionTriggers {
 81                    replica_id: lamport_timestamp.replica_id as u32,
 82                    lamport_timestamp: lamport_timestamp.value,
 83                    triggers: triggers.clone(),
 84                },
 85            ),
 86        }),
 87    }
 88}
 89
 90pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
 91    proto::operation::Edit {
 92        replica_id: operation.timestamp.replica_id as u32,
 93        local_timestamp: operation.timestamp.local,
 94        lamport_timestamp: operation.timestamp.lamport,
 95        version: serialize_version(&operation.version),
 96        ranges: operation.ranges.iter().map(serialize_range).collect(),
 97        new_text: operation
 98            .new_text
 99            .iter()
100            .map(|text| text.to_string())
101            .collect(),
102    }
103}
104
105pub fn serialize_undo_map_entry(
106    (edit_id, counts): (&clock::Local, &[(clock::Local, u32)]),
107) -> proto::UndoMapEntry {
108    proto::UndoMapEntry {
109        replica_id: edit_id.replica_id as u32,
110        local_timestamp: edit_id.value,
111        counts: counts
112            .iter()
113            .map(|(undo_id, count)| proto::UndoCount {
114                replica_id: undo_id.replica_id as u32,
115                local_timestamp: undo_id.value,
116                count: *count,
117            })
118            .collect(),
119    }
120}
121
122pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
123    selections.iter().map(serialize_selection).collect()
124}
125
126pub fn serialize_selection(selection: &Selection<Anchor>) -> proto::Selection {
127    proto::Selection {
128        id: selection.id as u64,
129        start: Some(serialize_anchor(&selection.start)),
130        end: Some(serialize_anchor(&selection.end)),
131        reversed: selection.reversed,
132    }
133}
134
135pub fn serialize_diagnostics<'a>(
136    diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
137) -> Vec<proto::Diagnostic> {
138    diagnostics
139        .into_iter()
140        .map(|entry| proto::Diagnostic {
141            start: Some(serialize_anchor(&entry.range.start)),
142            end: Some(serialize_anchor(&entry.range.end)),
143            message: entry.diagnostic.message.clone(),
144            severity: match entry.diagnostic.severity {
145                DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
146                DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
147                DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
148                DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
149                _ => proto::diagnostic::Severity::None,
150            } as i32,
151            group_id: entry.diagnostic.group_id as u64,
152            is_primary: entry.diagnostic.is_primary,
153            is_valid: entry.diagnostic.is_valid,
154            code: entry.diagnostic.code.clone(),
155            is_disk_based: entry.diagnostic.is_disk_based,
156            is_unnecessary: entry.diagnostic.is_unnecessary,
157        })
158        .collect()
159}
160
161pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
162    proto::Anchor {
163        replica_id: anchor.timestamp.replica_id as u32,
164        local_timestamp: anchor.timestamp.value,
165        offset: anchor.offset as u64,
166        bias: match anchor.bias {
167            Bias::Left => proto::Bias::Left as i32,
168            Bias::Right => proto::Bias::Right as i32,
169        },
170        buffer_id: anchor.buffer_id,
171    }
172}
173
174pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
175    Ok(
176        match message
177            .variant
178            .ok_or_else(|| anyhow!("missing operation variant"))?
179        {
180            proto::operation::Variant::Edit(edit) => {
181                Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
182            }
183            proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
184                lamport_timestamp: clock::Lamport {
185                    replica_id: undo.replica_id as ReplicaId,
186                    value: undo.lamport_timestamp,
187                },
188                undo: UndoOperation {
189                    id: clock::Local {
190                        replica_id: undo.replica_id as ReplicaId,
191                        value: undo.local_timestamp,
192                    },
193                    version: deserialize_version(undo.version),
194                    counts: undo
195                        .counts
196                        .into_iter()
197                        .map(|c| {
198                            (
199                                clock::Local {
200                                    replica_id: c.replica_id as ReplicaId,
201                                    value: c.local_timestamp,
202                                },
203                                c.count,
204                            )
205                        })
206                        .collect(),
207                    transaction_ranges: undo
208                        .transaction_ranges
209                        .into_iter()
210                        .map(deserialize_range)
211                        .collect(),
212                    transaction_version: deserialize_version(undo.transaction_version),
213                },
214            }),
215            proto::operation::Variant::UpdateSelections(message) => {
216                let selections = message
217                    .selections
218                    .into_iter()
219                    .filter_map(|selection| {
220                        Some(Selection {
221                            id: selection.id as usize,
222                            start: deserialize_anchor(selection.start?)?,
223                            end: deserialize_anchor(selection.end?)?,
224                            reversed: selection.reversed,
225                            goal: SelectionGoal::None,
226                        })
227                    })
228                    .collect::<Vec<_>>();
229
230                Operation::UpdateSelections {
231                    lamport_timestamp: clock::Lamport {
232                        replica_id: message.replica_id as ReplicaId,
233                        value: message.lamport_timestamp,
234                    },
235                    selections: Arc::from(selections),
236                    line_mode: message.line_mode,
237                }
238            }
239            proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
240                diagnostics: deserialize_diagnostics(message.diagnostics),
241                lamport_timestamp: clock::Lamport {
242                    replica_id: message.replica_id as ReplicaId,
243                    value: message.lamport_timestamp,
244                },
245            },
246            proto::operation::Variant::UpdateCompletionTriggers(message) => {
247                Operation::UpdateCompletionTriggers {
248                    triggers: message.triggers,
249                    lamport_timestamp: clock::Lamport {
250                        replica_id: message.replica_id as ReplicaId,
251                        value: message.lamport_timestamp,
252                    },
253                }
254            }
255        },
256    )
257}
258
259pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
260    EditOperation {
261        timestamp: InsertionTimestamp {
262            replica_id: edit.replica_id as ReplicaId,
263            local: edit.local_timestamp,
264            lamport: edit.lamport_timestamp,
265        },
266        version: deserialize_version(edit.version),
267        ranges: edit.ranges.into_iter().map(deserialize_range).collect(),
268        new_text: edit.new_text.into_iter().map(Arc::from).collect(),
269    }
270}
271
272pub fn deserialize_undo_map_entry(
273    entry: proto::UndoMapEntry,
274) -> (clock::Local, Vec<(clock::Local, u32)>) {
275    (
276        clock::Local {
277            replica_id: entry.replica_id as u16,
278            value: entry.local_timestamp,
279        },
280        entry
281            .counts
282            .into_iter()
283            .map(|undo_count| {
284                (
285                    clock::Local {
286                        replica_id: undo_count.replica_id as u16,
287                        value: undo_count.local_timestamp,
288                    },
289                    undo_count.count,
290                )
291            })
292            .collect(),
293    )
294}
295
296pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
297    Arc::from(
298        selections
299            .into_iter()
300            .filter_map(deserialize_selection)
301            .collect::<Vec<_>>(),
302    )
303}
304
305pub fn deserialize_selection(selection: proto::Selection) -> Option<Selection<Anchor>> {
306    Some(Selection {
307        id: selection.id as usize,
308        start: deserialize_anchor(selection.start?)?,
309        end: deserialize_anchor(selection.end?)?,
310        reversed: selection.reversed,
311        goal: SelectionGoal::None,
312    })
313}
314
315pub fn deserialize_diagnostics(
316    diagnostics: Vec<proto::Diagnostic>,
317) -> Arc<[DiagnosticEntry<Anchor>]> {
318    diagnostics
319        .into_iter()
320        .filter_map(|diagnostic| {
321            Some(DiagnosticEntry {
322                range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
323                diagnostic: Diagnostic {
324                    severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
325                        proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
326                        proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
327                        proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
328                        proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
329                        proto::diagnostic::Severity::None => return None,
330                    },
331                    message: diagnostic.message,
332                    group_id: diagnostic.group_id as usize,
333                    code: diagnostic.code,
334                    is_valid: diagnostic.is_valid,
335                    is_primary: diagnostic.is_primary,
336                    is_disk_based: diagnostic.is_disk_based,
337                    is_unnecessary: diagnostic.is_unnecessary,
338                },
339            })
340        })
341        .collect()
342}
343
344pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
345    Some(Anchor {
346        timestamp: clock::Local {
347            replica_id: anchor.replica_id as ReplicaId,
348            value: anchor.local_timestamp,
349        },
350        offset: anchor.offset as usize,
351        bias: match proto::Bias::from_i32(anchor.bias)? {
352            proto::Bias::Left => Bias::Left,
353            proto::Bias::Right => Bias::Right,
354        },
355        buffer_id: anchor.buffer_id,
356    })
357}
358
359pub fn lamport_timestamp_for_operation(operation: &proto::Operation) -> Option<clock::Lamport> {
360    let replica_id;
361    let value;
362    match operation.variant.as_ref()? {
363        proto::operation::Variant::Edit(op) => {
364            replica_id = op.replica_id;
365            value = op.lamport_timestamp;
366        }
367        proto::operation::Variant::Undo(op) => {
368            replica_id = op.replica_id;
369            value = op.lamport_timestamp;
370        }
371        proto::operation::Variant::UpdateDiagnostics(op) => {
372            replica_id = op.replica_id;
373            value = op.lamport_timestamp;
374        }
375        proto::operation::Variant::UpdateSelections(op) => {
376            replica_id = op.replica_id;
377            value = op.lamport_timestamp;
378        }
379        proto::operation::Variant::UpdateCompletionTriggers(op) => {
380            replica_id = op.replica_id;
381            value = op.lamport_timestamp;
382        }
383    }
384
385    Some(clock::Lamport {
386        replica_id: replica_id as ReplicaId,
387        value,
388    })
389}
390
391pub fn serialize_completion(completion: &Completion) -> proto::Completion {
392    proto::Completion {
393        old_start: Some(serialize_anchor(&completion.old_range.start)),
394        old_end: Some(serialize_anchor(&completion.old_range.end)),
395        new_text: completion.new_text.clone(),
396        lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
397    }
398}
399
400pub async fn deserialize_completion(
401    completion: proto::Completion,
402    language: Option<Arc<Language>>,
403) -> Result<Completion> {
404    let old_start = completion
405        .old_start
406        .and_then(deserialize_anchor)
407        .ok_or_else(|| anyhow!("invalid old start"))?;
408    let old_end = completion
409        .old_end
410        .and_then(deserialize_anchor)
411        .ok_or_else(|| anyhow!("invalid old end"))?;
412    let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
413    let label = match language {
414        Some(l) => l.label_for_completion(&lsp_completion).await,
415        None => None,
416    };
417
418    Ok(Completion {
419        old_range: old_start..old_end,
420        new_text: completion.new_text,
421        label: label.unwrap_or(CodeLabel::plain(
422            lsp_completion.label.clone(),
423            lsp_completion.filter_text.as_deref(),
424        )),
425        lsp_completion,
426    })
427}
428
429pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
430    proto::CodeAction {
431        start: Some(serialize_anchor(&action.range.start)),
432        end: Some(serialize_anchor(&action.range.end)),
433        lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
434    }
435}
436
437pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
438    let start = action
439        .start
440        .and_then(deserialize_anchor)
441        .ok_or_else(|| anyhow!("invalid start"))?;
442    let end = action
443        .end
444        .and_then(deserialize_anchor)
445        .ok_or_else(|| anyhow!("invalid end"))?;
446    let lsp_action = serde_json::from_slice(&action.lsp_action)?;
447    Ok(CodeAction {
448        range: start..end,
449        lsp_action,
450    })
451}
452
453pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
454    proto::Transaction {
455        id: Some(serialize_local_timestamp(transaction.id)),
456        edit_ids: transaction
457            .edit_ids
458            .iter()
459            .copied()
460            .map(serialize_local_timestamp)
461            .collect(),
462        start: serialize_version(&transaction.start),
463        end: serialize_version(&transaction.end),
464        ranges: transaction.ranges.iter().map(serialize_range).collect(),
465    }
466}
467
468pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transaction> {
469    Ok(Transaction {
470        id: deserialize_local_timestamp(
471            transaction
472                .id
473                .ok_or_else(|| anyhow!("missing transaction id"))?,
474        ),
475        edit_ids: transaction
476            .edit_ids
477            .into_iter()
478            .map(deserialize_local_timestamp)
479            .collect(),
480        start: deserialize_version(transaction.start.into()),
481        end: deserialize_version(transaction.end),
482        ranges: transaction
483            .ranges
484            .into_iter()
485            .map(deserialize_range)
486            .collect(),
487    })
488}
489
490pub fn serialize_local_timestamp(timestamp: clock::Local) -> proto::LocalTimestamp {
491    proto::LocalTimestamp {
492        replica_id: timestamp.replica_id as u32,
493        value: timestamp.value,
494    }
495}
496
497pub fn deserialize_local_timestamp(timestamp: proto::LocalTimestamp) -> clock::Local {
498    clock::Local {
499        replica_id: timestamp.replica_id as ReplicaId,
500        value: timestamp.value,
501    }
502}
503
504pub fn serialize_range(range: &Range<FullOffset>) -> proto::Range {
505    proto::Range {
506        start: range.start.0 as u64,
507        end: range.end.0 as u64,
508    }
509}
510
511pub fn deserialize_range(range: proto::Range) -> Range<FullOffset> {
512    FullOffset(range.start as usize)..FullOffset(range.end as usize)
513}
514
515pub fn deserialize_version(message: Vec<proto::VectorClockEntry>) -> clock::Global {
516    let mut version = clock::Global::new();
517    for entry in message {
518        version.observe(clock::Local {
519            replica_id: entry.replica_id as ReplicaId,
520            value: entry.timestamp,
521        });
522    }
523    version
524}
525
526pub fn serialize_version(version: &clock::Global) -> Vec<proto::VectorClockEntry> {
527    version
528        .iter()
529        .map(|entry| proto::VectorClockEntry {
530            replica_id: entry.replica_id as u32,
531            timestamp: entry.value,
532        })
533        .collect()
534}