proto.rs

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