proto.rs

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