proto.rs

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