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