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