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