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