proto.rs

  1use std::sync::Arc;
  2
  3use crate::{diagnostic_set::DiagnosticEntry, Diagnostic, Operation};
  4use anyhow::{anyhow, Result};
  5use clock::ReplicaId;
  6use lsp::DiagnosticSeverity;
  7use rpc::proto;
  8use text::*;
  9
 10pub use proto::Buffer;
 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::operation::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::Buffer(text::Operation::UpdateSelections {
 45                set_id,
 46                selections,
 47                lamport_timestamp,
 48            }) => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
 49                replica_id: set_id.replica_id as u32,
 50                local_timestamp: set_id.value,
 51                lamport_timestamp: lamport_timestamp.value,
 52                selections: selections
 53                    .iter()
 54                    .map(|selection| proto::Selection {
 55                        id: selection.id as u64,
 56                        start: Some(serialize_anchor(&selection.start)),
 57                        end: Some(serialize_anchor(&selection.end)),
 58                        reversed: selection.reversed,
 59                    })
 60                    .collect(),
 61            }),
 62            Operation::Buffer(text::Operation::RemoveSelections {
 63                set_id,
 64                lamport_timestamp,
 65            }) => proto::operation::Variant::RemoveSelections(proto::operation::RemoveSelections {
 66                replica_id: set_id.replica_id as u32,
 67                local_timestamp: set_id.value,
 68                lamport_timestamp: lamport_timestamp.value,
 69            }),
 70            Operation::Buffer(text::Operation::SetActiveSelections {
 71                set_id,
 72                lamport_timestamp,
 73            }) => proto::operation::Variant::SetActiveSelections(
 74                proto::operation::SetActiveSelections {
 75                    replica_id: lamport_timestamp.replica_id as u32,
 76                    local_timestamp: set_id.map(|set_id| set_id.value),
 77                    lamport_timestamp: lamport_timestamp.value,
 78                },
 79            ),
 80            Operation::UpdateDiagnostics {
 81                diagnostics,
 82                lamport_timestamp,
 83            } => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics {
 84                replica_id: lamport_timestamp.replica_id as u32,
 85                lamport_timestamp: lamport_timestamp.value,
 86                diagnostics: serialize_diagnostics(diagnostics.iter()),
 87            }),
 88        }),
 89    }
 90}
 91
 92pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
 93    let ranges = operation
 94        .ranges
 95        .iter()
 96        .map(|range| proto::Range {
 97            start: range.start.0 as u64,
 98            end: range.end.0 as u64,
 99        })
100        .collect();
101    proto::operation::Edit {
102        replica_id: operation.timestamp.replica_id as u32,
103        local_timestamp: operation.timestamp.local,
104        lamport_timestamp: operation.timestamp.lamport,
105        version: From::from(&operation.version),
106        ranges,
107        new_text: operation.new_text.clone(),
108    }
109}
110
111pub fn serialize_selection_set(set: &SelectionSet) -> proto::SelectionSet {
112    proto::SelectionSet {
113        replica_id: set.id.replica_id as u32,
114        lamport_timestamp: set.id.value as u32,
115        is_active: set.active,
116        selections: set
117            .selections
118            .iter()
119            .map(|selection| proto::Selection {
120                id: selection.id as u64,
121                start: Some(serialize_anchor(&selection.start)),
122                end: Some(serialize_anchor(&selection.end)),
123                reversed: selection.reversed,
124            })
125            .collect(),
126    }
127}
128
129pub fn serialize_diagnostics<'a>(
130    diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
131) -> Vec<proto::Diagnostic> {
132    diagnostics
133        .into_iter()
134        .map(|entry| proto::Diagnostic {
135            start: Some(serialize_anchor(&entry.range.start)),
136            end: Some(serialize_anchor(&entry.range.end)),
137            message: entry.diagnostic.message.clone(),
138            severity: match entry.diagnostic.severity {
139                DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
140                DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
141                DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
142                DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
143                _ => proto::diagnostic::Severity::None,
144            } as i32,
145            group_id: entry.diagnostic.group_id as u64,
146            is_primary: entry.diagnostic.is_primary,
147        })
148        .collect()
149}
150
151fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
152    proto::Anchor {
153        replica_id: anchor.timestamp.replica_id as u32,
154        local_timestamp: anchor.timestamp.value,
155        offset: anchor.offset as u64,
156        bias: match anchor.bias {
157            Bias::Left => proto::Bias::Left as i32,
158            Bias::Right => proto::Bias::Right as i32,
159        },
160    }
161}
162
163pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
164    Ok(
165        match message
166            .variant
167            .ok_or_else(|| anyhow!("missing operation variant"))?
168        {
169            proto::operation::Variant::Edit(edit) => {
170                Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
171            }
172            proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
173                lamport_timestamp: clock::Lamport {
174                    replica_id: undo.replica_id as ReplicaId,
175                    value: undo.lamport_timestamp,
176                },
177                undo: UndoOperation {
178                    id: clock::Local {
179                        replica_id: undo.replica_id as ReplicaId,
180                        value: undo.local_timestamp,
181                    },
182                    counts: undo
183                        .counts
184                        .into_iter()
185                        .map(|c| {
186                            (
187                                clock::Local {
188                                    replica_id: c.replica_id as ReplicaId,
189                                    value: c.local_timestamp,
190                                },
191                                c.count,
192                            )
193                        })
194                        .collect(),
195                    ranges: undo
196                        .ranges
197                        .into_iter()
198                        .map(|r| FullOffset(r.start as usize)..FullOffset(r.end as usize))
199                        .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::Buffer(text::Operation::UpdateSelections {
219                    set_id: clock::Lamport {
220                        replica_id: message.replica_id as ReplicaId,
221                        value: message.local_timestamp,
222                    },
223                    lamport_timestamp: clock::Lamport {
224                        replica_id: message.replica_id as ReplicaId,
225                        value: message.lamport_timestamp,
226                    },
227                    selections: Arc::from(selections),
228                })
229            }
230            proto::operation::Variant::RemoveSelections(message) => {
231                Operation::Buffer(text::Operation::RemoveSelections {
232                    set_id: clock::Lamport {
233                        replica_id: message.replica_id as ReplicaId,
234                        value: message.local_timestamp,
235                    },
236                    lamport_timestamp: clock::Lamport {
237                        replica_id: message.replica_id as ReplicaId,
238                        value: message.lamport_timestamp,
239                    },
240                })
241            }
242            proto::operation::Variant::SetActiveSelections(message) => {
243                Operation::Buffer(text::Operation::SetActiveSelections {
244                    set_id: message.local_timestamp.map(|value| clock::Lamport {
245                        replica_id: message.replica_id as ReplicaId,
246                        value,
247                    }),
248                    lamport_timestamp: clock::Lamport {
249                        replica_id: message.replica_id as ReplicaId,
250                        value: message.lamport_timestamp,
251                    },
252                })
253            }
254            proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
255                diagnostics: Arc::from(deserialize_diagnostics(message.diagnostics)),
256                lamport_timestamp: clock::Lamport {
257                    replica_id: message.replica_id as ReplicaId,
258                    value: message.lamport_timestamp,
259                },
260            },
261        },
262    )
263}
264
265pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
266    let ranges = edit
267        .ranges
268        .into_iter()
269        .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
270        .collect();
271    EditOperation {
272        timestamp: InsertionTimestamp {
273            replica_id: edit.replica_id as ReplicaId,
274            local: edit.local_timestamp,
275            lamport: edit.lamport_timestamp,
276        },
277        version: edit.version.into(),
278        ranges,
279        new_text: edit.new_text,
280    }
281}
282
283pub fn deserialize_selection_set(set: proto::SelectionSet) -> SelectionSet {
284    SelectionSet {
285        id: clock::Lamport {
286            replica_id: set.replica_id as u16,
287            value: set.lamport_timestamp,
288        },
289        active: set.is_active,
290        selections: Arc::from(
291            set.selections
292                .into_iter()
293                .filter_map(|selection| {
294                    Some(Selection {
295                        id: selection.id as usize,
296                        start: deserialize_anchor(selection.start?)?,
297                        end: deserialize_anchor(selection.end?)?,
298                        reversed: selection.reversed,
299                        goal: SelectionGoal::None,
300                    })
301                })
302                .collect::<Vec<_>>(),
303        ),
304    }
305}
306
307pub fn deserialize_diagnostics(
308    diagnostics: Vec<proto::Diagnostic>,
309) -> Vec<DiagnosticEntry<Anchor>> {
310    diagnostics
311        .into_iter()
312        .filter_map(|diagnostic| {
313            Some(DiagnosticEntry {
314                range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
315                diagnostic: Diagnostic {
316                    severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
317                        proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
318                        proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
319                        proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
320                        proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
321                        proto::diagnostic::Severity::None => return None,
322                    },
323                    message: diagnostic.message,
324                    group_id: diagnostic.group_id as usize,
325                    is_primary: diagnostic.is_primary,
326                },
327            })
328        })
329        .collect()
330}
331
332fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
333    Some(Anchor {
334        timestamp: clock::Local {
335            replica_id: anchor.replica_id as ReplicaId,
336            value: anchor.local_timestamp,
337        },
338        offset: anchor.offset as usize,
339        bias: match proto::Bias::from_i32(anchor.bias)? {
340            proto::Bias::Left => Bias::Left,
341            proto::Bias::Right => Bias::Right,
342        },
343    })
344}