proto.rs

  1use crate::{diagnostic_set::DiagnosticEntry, Diagnostic, Operation};
  2use anyhow::{anyhow, Result};
  3use clock::ReplicaId;
  4use lsp::DiagnosticSeverity;
  5use rpc::proto;
  6use std::sync::Arc;
  7use text::*;
  8
  9pub use proto::{Buffer, SelectionSet};
 10
 11pub fn serialize_operation(operation: &Operation) -> proto::Operation {
 12    proto::Operation {
 13        variant: Some(match operation {
 14            Operation::Buffer(text::Operation::Edit(edit)) => {
 15                proto::operation::Variant::Edit(serialize_edit_operation(edit))
 16            }
 17            Operation::Buffer(text::Operation::Undo {
 18                undo,
 19                lamport_timestamp,
 20            }) => proto::operation::Variant::Undo(proto::operation::Undo {
 21                replica_id: undo.id.replica_id as u32,
 22                local_timestamp: undo.id.value,
 23                lamport_timestamp: lamport_timestamp.value,
 24                ranges: undo
 25                    .ranges
 26                    .iter()
 27                    .map(|r| proto::Range {
 28                        start: r.start.0 as u64,
 29                        end: r.end.0 as u64,
 30                    })
 31                    .collect(),
 32                counts: undo
 33                    .counts
 34                    .iter()
 35                    .map(|(edit_id, count)| proto::UndoCount {
 36                        replica_id: edit_id.replica_id as u32,
 37                        local_timestamp: edit_id.value,
 38                        count: *count,
 39                    })
 40                    .collect(),
 41                version: From::from(&undo.version),
 42            }),
 43            Operation::UpdateSelections {
 44                replica_id,
 45                selections,
 46                lamport_timestamp,
 47            } => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
 48                replica_id: *replica_id as u32,
 49                lamport_timestamp: lamport_timestamp.value,
 50                selections: serialize_selections(selections),
 51            }),
 52            Operation::RemoveSelections {
 53                replica_id,
 54                lamport_timestamp,
 55            } => proto::operation::Variant::RemoveSelections(proto::operation::RemoveSelections {
 56                replica_id: *replica_id as u32,
 57                lamport_timestamp: lamport_timestamp.value,
 58            }),
 59            Operation::UpdateDiagnostics {
 60                provider_name,
 61                diagnostics,
 62                lamport_timestamp,
 63            } => proto::operation::Variant::UpdateDiagnosticSet(proto::UpdateDiagnosticSet {
 64                replica_id: lamport_timestamp.replica_id as u32,
 65                lamport_timestamp: lamport_timestamp.value,
 66                diagnostic_set: Some(serialize_diagnostic_set(
 67                    provider_name.clone(),
 68                    diagnostics.iter(),
 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: fragment
128            .max_undos
129            .iter()
130            .map(|clock| proto::VectorClockEntry {
131                replica_id: clock.replica_id as u32,
132                timestamp: clock.value,
133            })
134            .collect(),
135    }
136}
137
138pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
139    selections
140        .iter()
141        .map(|selection| proto::Selection {
142            id: selection.id as u64,
143            start: Some(serialize_anchor(&selection.start)),
144            end: Some(serialize_anchor(&selection.end)),
145            reversed: selection.reversed,
146        })
147        .collect()
148}
149
150pub fn serialize_diagnostic_set<'a>(
151    provider_name: String,
152    diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
153) -> proto::DiagnosticSet {
154    proto::DiagnosticSet {
155        provider_name,
156        diagnostics: diagnostics
157            .into_iter()
158            .map(|entry| proto::Diagnostic {
159                start: Some(serialize_anchor(&entry.range.start)),
160                end: Some(serialize_anchor(&entry.range.end)),
161                message: entry.diagnostic.message.clone(),
162                severity: match entry.diagnostic.severity {
163                    DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
164                    DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
165                    DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
166                    DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
167                    _ => proto::diagnostic::Severity::None,
168                } as i32,
169                group_id: entry.diagnostic.group_id as u64,
170                is_primary: entry.diagnostic.is_primary,
171                is_valid: entry.diagnostic.is_valid,
172                code: entry.diagnostic.code.clone(),
173                is_disk_based: entry.diagnostic.is_disk_based,
174            })
175            .collect(),
176    }
177}
178
179fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
180    proto::Anchor {
181        replica_id: anchor.timestamp.replica_id as u32,
182        local_timestamp: anchor.timestamp.value,
183        offset: anchor.offset as u64,
184        bias: match anchor.bias {
185            Bias::Left => proto::Bias::Left as i32,
186            Bias::Right => proto::Bias::Right as i32,
187        },
188    }
189}
190
191pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
192    Ok(
193        match message
194            .variant
195            .ok_or_else(|| anyhow!("missing operation variant"))?
196        {
197            proto::operation::Variant::Edit(edit) => {
198                Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
199            }
200            proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
201                lamport_timestamp: clock::Lamport {
202                    replica_id: undo.replica_id as ReplicaId,
203                    value: undo.lamport_timestamp,
204                },
205                undo: UndoOperation {
206                    id: clock::Local {
207                        replica_id: undo.replica_id as ReplicaId,
208                        value: undo.local_timestamp,
209                    },
210                    counts: undo
211                        .counts
212                        .into_iter()
213                        .map(|c| {
214                            (
215                                clock::Local {
216                                    replica_id: c.replica_id as ReplicaId,
217                                    value: c.local_timestamp,
218                                },
219                                c.count,
220                            )
221                        })
222                        .collect(),
223                    ranges: undo
224                        .ranges
225                        .into_iter()
226                        .map(|r| FullOffset(r.start as usize)..FullOffset(r.end as usize))
227                        .collect(),
228                    version: undo.version.into(),
229                },
230            }),
231            proto::operation::Variant::UpdateSelections(message) => {
232                let selections = message
233                    .selections
234                    .into_iter()
235                    .filter_map(|selection| {
236                        Some(Selection {
237                            id: selection.id as usize,
238                            start: deserialize_anchor(selection.start?)?,
239                            end: deserialize_anchor(selection.end?)?,
240                            reversed: selection.reversed,
241                            goal: SelectionGoal::None,
242                        })
243                    })
244                    .collect::<Vec<_>>();
245
246                Operation::UpdateSelections {
247                    replica_id: message.replica_id as ReplicaId,
248                    lamport_timestamp: clock::Lamport {
249                        replica_id: message.replica_id as ReplicaId,
250                        value: message.lamport_timestamp,
251                    },
252                    selections: Arc::from(selections),
253                }
254            }
255            proto::operation::Variant::RemoveSelections(message) => Operation::RemoveSelections {
256                replica_id: message.replica_id as ReplicaId,
257                lamport_timestamp: clock::Lamport {
258                    replica_id: message.replica_id as ReplicaId,
259                    value: message.lamport_timestamp,
260                },
261            },
262            proto::operation::Variant::UpdateDiagnosticSet(message) => {
263                let (provider_name, diagnostics) = deserialize_diagnostic_set(
264                    message
265                        .diagnostic_set
266                        .ok_or_else(|| anyhow!("missing diagnostic set"))?,
267                );
268                Operation::UpdateDiagnostics {
269                    provider_name,
270                    diagnostics,
271                    lamport_timestamp: clock::Lamport {
272                        replica_id: message.replica_id as ReplicaId,
273                        value: message.lamport_timestamp,
274                    },
275                }
276            }
277        },
278    )
279}
280
281pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
282    let ranges = edit
283        .ranges
284        .into_iter()
285        .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
286        .collect();
287    EditOperation {
288        timestamp: InsertionTimestamp {
289            replica_id: edit.replica_id as ReplicaId,
290            local: edit.local_timestamp,
291            lamport: edit.lamport_timestamp,
292        },
293        version: edit.version.into(),
294        ranges,
295        new_text: edit.new_text,
296    }
297}
298
299pub fn deserialize_undo_map_entry(
300    entry: proto::UndoMapEntry,
301) -> (clock::Local, Vec<(clock::Local, u32)>) {
302    (
303        clock::Local {
304            replica_id: entry.replica_id as u16,
305            value: entry.local_timestamp,
306        },
307        entry
308            .counts
309            .into_iter()
310            .map(|undo_count| {
311                (
312                    clock::Local {
313                        replica_id: undo_count.replica_id as u16,
314                        value: undo_count.local_timestamp,
315                    },
316                    undo_count.count,
317                )
318            })
319            .collect(),
320    )
321}
322
323pub fn deserialize_buffer_fragment(
324    message: proto::BufferFragment,
325    ix: usize,
326    count: usize,
327) -> Fragment {
328    todo!()
329}
330
331pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
332    Arc::from(
333        selections
334            .into_iter()
335            .filter_map(|selection| {
336                Some(Selection {
337                    id: selection.id as usize,
338                    start: deserialize_anchor(selection.start?)?,
339                    end: deserialize_anchor(selection.end?)?,
340                    reversed: selection.reversed,
341                    goal: SelectionGoal::None,
342                })
343            })
344            .collect::<Vec<_>>(),
345    )
346}
347
348pub fn deserialize_diagnostic_set(
349    message: proto::DiagnosticSet,
350) -> (String, Arc<[DiagnosticEntry<Anchor>]>) {
351    (
352        message.provider_name,
353        message
354            .diagnostics
355            .into_iter()
356            .filter_map(|diagnostic| {
357                Some(DiagnosticEntry {
358                    range: deserialize_anchor(diagnostic.start?)?
359                        ..deserialize_anchor(diagnostic.end?)?,
360                    diagnostic: Diagnostic {
361                        severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)?
362                        {
363                            proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
364                            proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
365                            proto::diagnostic::Severity::Information => {
366                                DiagnosticSeverity::INFORMATION
367                            }
368                            proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
369                            proto::diagnostic::Severity::None => return None,
370                        },
371                        message: diagnostic.message,
372                        group_id: diagnostic.group_id as usize,
373                        code: diagnostic.code,
374                        is_valid: diagnostic.is_valid,
375                        is_primary: diagnostic.is_primary,
376                        is_disk_based: diagnostic.is_disk_based,
377                    },
378                })
379            })
380            .collect(),
381    )
382}
383
384fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
385    Some(Anchor {
386        timestamp: clock::Local {
387            replica_id: anchor.replica_id as ReplicaId,
388            value: anchor.local_timestamp,
389        },
390        offset: anchor.offset as usize,
391        bias: match proto::Bias::from_i32(anchor.bias)? {
392            proto::Bias::Left => Bias::Left,
393            proto::Bias::Right => Bias::Right,
394        },
395    })
396}