proto.rs

  1use crate::{diagnostic_set::DiagnosticEntry, Completion, Diagnostic, Language, Operation};
  2use anyhow::{anyhow, Result};
  3use clock::ReplicaId;
  4use collections::HashSet;
  5use lsp::DiagnosticSeverity;
  6use rpc::proto;
  7use std::sync::Arc;
  8use text::*;
  9
 10pub use proto::{Buffer, BufferState, SelectionSet};
 11
 12pub fn serialize_operation(operation: &Operation) -> proto::Operation {
 13    proto::Operation {
 14        variant: Some(match operation {
 15            Operation::Buffer(text::Operation::Edit(edit)) => {
 16                proto::operation::Variant::Edit(serialize_edit_operation(edit))
 17            }
 18            Operation::Buffer(text::Operation::Undo {
 19                undo,
 20                lamport_timestamp,
 21            }) => proto::operation::Variant::Undo(proto::operation::Undo {
 22                replica_id: undo.id.replica_id as u32,
 23                local_timestamp: undo.id.value,
 24                lamport_timestamp: lamport_timestamp.value,
 25                ranges: undo
 26                    .ranges
 27                    .iter()
 28                    .map(|r| proto::Range {
 29                        start: r.start.0 as u64,
 30                        end: r.end.0 as u64,
 31                    })
 32                    .collect(),
 33                counts: undo
 34                    .counts
 35                    .iter()
 36                    .map(|(edit_id, count)| proto::UndoCount {
 37                        replica_id: edit_id.replica_id as u32,
 38                        local_timestamp: edit_id.value,
 39                        count: *count,
 40                    })
 41                    .collect(),
 42                version: From::from(&undo.version),
 43            }),
 44            Operation::UpdateSelections {
 45                replica_id,
 46                selections,
 47                lamport_timestamp,
 48            } => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
 49                replica_id: *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 { triggers } => {
 62                proto::operation::Variant::UpdateCompletionTriggers(
 63                    proto::operation::UpdateCompletionTriggers {
 64                        triggers: triggers.clone(),
 65                    },
 66                )
 67            }
 68        }),
 69    }
 70}
 71
 72pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
 73    let ranges = operation
 74        .ranges
 75        .iter()
 76        .map(|range| proto::Range {
 77            start: range.start.0 as u64,
 78            end: range.end.0 as u64,
 79        })
 80        .collect();
 81    proto::operation::Edit {
 82        replica_id: operation.timestamp.replica_id as u32,
 83        local_timestamp: operation.timestamp.local,
 84        lamport_timestamp: operation.timestamp.lamport,
 85        version: From::from(&operation.version),
 86        ranges,
 87        new_text: operation.new_text.clone(),
 88    }
 89}
 90
 91pub fn serialize_undo_map_entry(
 92    (edit_id, counts): (&clock::Local, &[(clock::Local, u32)]),
 93) -> proto::UndoMapEntry {
 94    proto::UndoMapEntry {
 95        replica_id: edit_id.replica_id as u32,
 96        local_timestamp: edit_id.value,
 97        counts: counts
 98            .iter()
 99            .map(|(undo_id, count)| proto::UndoCount {
100                replica_id: undo_id.replica_id as u32,
101                local_timestamp: undo_id.value,
102                count: *count,
103            })
104            .collect(),
105    }
106}
107
108pub fn serialize_buffer_fragment(fragment: &text::Fragment) -> proto::BufferFragment {
109    proto::BufferFragment {
110        replica_id: fragment.insertion_timestamp.replica_id as u32,
111        local_timestamp: fragment.insertion_timestamp.local,
112        lamport_timestamp: fragment.insertion_timestamp.lamport,
113        insertion_offset: fragment.insertion_offset as u32,
114        len: fragment.len as u32,
115        visible: fragment.visible,
116        deletions: fragment
117            .deletions
118            .iter()
119            .map(|clock| proto::VectorClockEntry {
120                replica_id: clock.replica_id as u32,
121                timestamp: clock.value,
122            })
123            .collect(),
124        max_undos: From::from(&fragment.max_undos),
125    }
126}
127
128pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
129    selections
130        .iter()
131        .map(|selection| proto::Selection {
132            id: selection.id as u64,
133            start: Some(serialize_anchor(&selection.start)),
134            end: Some(serialize_anchor(&selection.end)),
135            reversed: selection.reversed,
136        })
137        .collect()
138}
139
140pub fn serialize_diagnostics<'a>(
141    diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
142) -> Vec<proto::Diagnostic> {
143    diagnostics
144        .into_iter()
145        .map(|entry| proto::Diagnostic {
146            start: Some(serialize_anchor(&entry.range.start)),
147            end: Some(serialize_anchor(&entry.range.end)),
148            message: entry.diagnostic.message.clone(),
149            severity: match entry.diagnostic.severity {
150                DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
151                DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
152                DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
153                DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
154                _ => proto::diagnostic::Severity::None,
155            } as i32,
156            group_id: entry.diagnostic.group_id as u64,
157            is_primary: entry.diagnostic.is_primary,
158            is_valid: entry.diagnostic.is_valid,
159            code: entry.diagnostic.code.clone(),
160            is_disk_based: entry.diagnostic.is_disk_based,
161        })
162        .collect()
163}
164
165pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
166    proto::Anchor {
167        replica_id: anchor.timestamp.replica_id as u32,
168        local_timestamp: anchor.timestamp.value,
169        offset: anchor.offset as u64,
170        bias: match anchor.bias {
171            Bias::Left => proto::Bias::Left as i32,
172            Bias::Right => proto::Bias::Right as i32,
173        },
174    }
175}
176
177pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
178    Ok(
179        match message
180            .variant
181            .ok_or_else(|| anyhow!("missing operation variant"))?
182        {
183            proto::operation::Variant::Edit(edit) => {
184                Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
185            }
186            proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
187                lamport_timestamp: clock::Lamport {
188                    replica_id: undo.replica_id as ReplicaId,
189                    value: undo.lamport_timestamp,
190                },
191                undo: UndoOperation {
192                    id: clock::Local {
193                        replica_id: undo.replica_id as ReplicaId,
194                        value: undo.local_timestamp,
195                    },
196                    counts: undo
197                        .counts
198                        .into_iter()
199                        .map(|c| {
200                            (
201                                clock::Local {
202                                    replica_id: c.replica_id as ReplicaId,
203                                    value: c.local_timestamp,
204                                },
205                                c.count,
206                            )
207                        })
208                        .collect(),
209                    ranges: undo
210                        .ranges
211                        .into_iter()
212                        .map(|r| FullOffset(r.start as usize)..FullOffset(r.end as usize))
213                        .collect(),
214                    version: undo.version.into(),
215                },
216            }),
217            proto::operation::Variant::UpdateSelections(message) => {
218                let selections = message
219                    .selections
220                    .into_iter()
221                    .filter_map(|selection| {
222                        Some(Selection {
223                            id: selection.id as usize,
224                            start: deserialize_anchor(selection.start?)?,
225                            end: deserialize_anchor(selection.end?)?,
226                            reversed: selection.reversed,
227                            goal: SelectionGoal::None,
228                        })
229                    })
230                    .collect::<Vec<_>>();
231
232                Operation::UpdateSelections {
233                    replica_id: message.replica_id as ReplicaId,
234                    lamport_timestamp: clock::Lamport {
235                        replica_id: message.replica_id as ReplicaId,
236                        value: message.lamport_timestamp,
237                    },
238                    selections: Arc::from(selections),
239                }
240            }
241            proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
242                diagnostics: deserialize_diagnostics(message.diagnostics),
243                lamport_timestamp: clock::Lamport {
244                    replica_id: message.replica_id as ReplicaId,
245                    value: message.lamport_timestamp,
246                },
247            },
248            proto::operation::Variant::UpdateCompletionTriggers(message) => {
249                Operation::UpdateCompletionTriggers {
250                    triggers: message.triggers,
251                }
252            }
253        },
254    )
255}
256
257pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
258    let ranges = edit
259        .ranges
260        .into_iter()
261        .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
262        .collect();
263    EditOperation {
264        timestamp: InsertionTimestamp {
265            replica_id: edit.replica_id as ReplicaId,
266            local: edit.local_timestamp,
267            lamport: edit.lamport_timestamp,
268        },
269        version: edit.version.into(),
270        ranges,
271        new_text: edit.new_text,
272    }
273}
274
275pub fn deserialize_undo_map_entry(
276    entry: proto::UndoMapEntry,
277) -> (clock::Local, Vec<(clock::Local, u32)>) {
278    (
279        clock::Local {
280            replica_id: entry.replica_id as u16,
281            value: entry.local_timestamp,
282        },
283        entry
284            .counts
285            .into_iter()
286            .map(|undo_count| {
287                (
288                    clock::Local {
289                        replica_id: undo_count.replica_id as u16,
290                        value: undo_count.local_timestamp,
291                    },
292                    undo_count.count,
293                )
294            })
295            .collect(),
296    )
297}
298
299pub fn deserialize_buffer_fragment(
300    message: proto::BufferFragment,
301    ix: usize,
302    count: usize,
303) -> Fragment {
304    Fragment {
305        id: locator::Locator::from_index(ix, count),
306        insertion_timestamp: InsertionTimestamp {
307            replica_id: message.replica_id as ReplicaId,
308            local: message.local_timestamp,
309            lamport: message.lamport_timestamp,
310        },
311        insertion_offset: message.insertion_offset as usize,
312        len: message.len as usize,
313        visible: message.visible,
314        deletions: HashSet::from_iter(message.deletions.into_iter().map(|entry| clock::Local {
315            replica_id: entry.replica_id as ReplicaId,
316            value: entry.timestamp,
317        })),
318        max_undos: From::from(message.max_undos),
319    }
320}
321
322pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
323    Arc::from(
324        selections
325            .into_iter()
326            .filter_map(|selection| {
327                Some(Selection {
328                    id: selection.id as usize,
329                    start: deserialize_anchor(selection.start?)?,
330                    end: deserialize_anchor(selection.end?)?,
331                    reversed: selection.reversed,
332                    goal: SelectionGoal::None,
333                })
334            })
335            .collect::<Vec<_>>(),
336    )
337}
338
339pub fn deserialize_diagnostics(
340    diagnostics: Vec<proto::Diagnostic>,
341) -> Arc<[DiagnosticEntry<Anchor>]> {
342    diagnostics
343        .into_iter()
344        .filter_map(|diagnostic| {
345            Some(DiagnosticEntry {
346                range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
347                diagnostic: Diagnostic {
348                    severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
349                        proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
350                        proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
351                        proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
352                        proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
353                        proto::diagnostic::Severity::None => return None,
354                    },
355                    message: diagnostic.message,
356                    group_id: diagnostic.group_id as usize,
357                    code: diagnostic.code,
358                    is_valid: diagnostic.is_valid,
359                    is_primary: diagnostic.is_primary,
360                    is_disk_based: diagnostic.is_disk_based,
361                },
362            })
363        })
364        .collect()
365}
366
367pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
368    Some(Anchor {
369        timestamp: clock::Local {
370            replica_id: anchor.replica_id as ReplicaId,
371            value: anchor.local_timestamp,
372        },
373        offset: anchor.offset as usize,
374        bias: match proto::Bias::from_i32(anchor.bias)? {
375            proto::Bias::Left => Bias::Left,
376            proto::Bias::Right => Bias::Right,
377        },
378    })
379}
380
381pub fn serialize_completion(completion: &Completion<Anchor>) -> 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 fn deserialize_completion(
391    completion: proto::Completion,
392    language: Option<&Arc<Language>>,
393) -> Result<Completion<Anchor>> {
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    Ok(Completion {
404        old_range: old_start..old_end,
405        new_text: completion.new_text,
406        label: language.and_then(|l| l.label_for_completion(&lsp_completion)),
407        lsp_completion,
408    })
409}