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