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}