1use crate::{
2 diagnostic_set::DiagnosticEntry, CodeAction, CodeLabel, Completion, Diagnostic, Language,
3 Operation,
4};
5use anyhow::{anyhow, Result};
6use clock::ReplicaId;
7use collections::HashSet;
8use lsp::DiagnosticSeverity;
9use rpc::proto;
10use std::{ops::Range, sync::Arc};
11use text::*;
12
13pub use proto::{Buffer, BufferState, SelectionSet};
14
15pub fn serialize_operation(operation: &Operation) -> proto::Operation {
16 proto::Operation {
17 variant: Some(match operation {
18 Operation::Buffer(text::Operation::Edit(edit)) => {
19 proto::operation::Variant::Edit(serialize_edit_operation(edit))
20 }
21 Operation::Buffer(text::Operation::Undo {
22 undo,
23 lamport_timestamp,
24 }) => proto::operation::Variant::Undo(proto::operation::Undo {
25 replica_id: undo.id.replica_id as u32,
26 local_timestamp: undo.id.value,
27 lamport_timestamp: lamport_timestamp.value,
28 version: serialize_version(&undo.version),
29 transaction_ranges: undo
30 .transaction_ranges
31 .iter()
32 .map(serialize_range)
33 .collect(),
34 transaction_version: serialize_version(&undo.transaction_version),
35 counts: undo
36 .counts
37 .iter()
38 .map(|(edit_id, count)| proto::UndoCount {
39 replica_id: edit_id.replica_id as u32,
40 local_timestamp: edit_id.value,
41 count: *count,
42 })
43 .collect(),
44 }),
45 Operation::UpdateSelections {
46 selections,
47 lamport_timestamp,
48 } => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
49 replica_id: lamport_timestamp.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 Operation::UpdateCompletionTriggers {
62 triggers,
63 lamport_timestamp,
64 } => proto::operation::Variant::UpdateCompletionTriggers(
65 proto::operation::UpdateCompletionTriggers {
66 replica_id: lamport_timestamp.replica_id as u32,
67 lamport_timestamp: lamport_timestamp.value,
68 triggers: triggers.clone(),
69 },
70 ),
71 }),
72 }
73}
74
75pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
76 proto::operation::Edit {
77 replica_id: operation.timestamp.replica_id as u32,
78 local_timestamp: operation.timestamp.local,
79 lamport_timestamp: operation.timestamp.lamport,
80 version: serialize_version(&operation.version),
81 ranges: operation.ranges.iter().map(serialize_range).collect(),
82 new_text: operation.new_text.clone(),
83 }
84}
85
86pub fn serialize_undo_map_entry(
87 (edit_id, counts): (&clock::Local, &[(clock::Local, u32)]),
88) -> proto::UndoMapEntry {
89 proto::UndoMapEntry {
90 replica_id: edit_id.replica_id as u32,
91 local_timestamp: edit_id.value,
92 counts: counts
93 .iter()
94 .map(|(undo_id, count)| proto::UndoCount {
95 replica_id: undo_id.replica_id as u32,
96 local_timestamp: undo_id.value,
97 count: *count,
98 })
99 .collect(),
100 }
101}
102
103pub fn serialize_buffer_fragment(fragment: &text::Fragment) -> proto::BufferFragment {
104 proto::BufferFragment {
105 replica_id: fragment.insertion_timestamp.replica_id as u32,
106 local_timestamp: fragment.insertion_timestamp.local,
107 lamport_timestamp: fragment.insertion_timestamp.lamport,
108 insertion_offset: fragment.insertion_offset as u32,
109 len: fragment.len as u32,
110 visible: fragment.visible,
111 deletions: fragment
112 .deletions
113 .iter()
114 .map(|clock| proto::VectorClockEntry {
115 replica_id: clock.replica_id as u32,
116 timestamp: clock.value,
117 })
118 .collect(),
119 max_undos: serialize_version(&fragment.max_undos),
120 }
121}
122
123pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
124 selections
125 .iter()
126 .map(|selection| proto::Selection {
127 id: selection.id as u64,
128 start: Some(serialize_anchor(&selection.start)),
129 end: Some(serialize_anchor(&selection.end)),
130 reversed: selection.reversed,
131 })
132 .collect()
133}
134
135pub fn serialize_diagnostics<'a>(
136 diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
137) -> Vec<proto::Diagnostic> {
138 diagnostics
139 .into_iter()
140 .map(|entry| proto::Diagnostic {
141 start: Some(serialize_anchor(&entry.range.start)),
142 end: Some(serialize_anchor(&entry.range.end)),
143 message: entry.diagnostic.message.clone(),
144 severity: match entry.diagnostic.severity {
145 DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
146 DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
147 DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
148 DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
149 _ => proto::diagnostic::Severity::None,
150 } as i32,
151 group_id: entry.diagnostic.group_id as u64,
152 is_primary: entry.diagnostic.is_primary,
153 is_valid: entry.diagnostic.is_valid,
154 code: entry.diagnostic.code.clone(),
155 is_disk_based: entry.diagnostic.is_disk_based,
156 })
157 .collect()
158}
159
160pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
161 proto::Anchor {
162 replica_id: anchor.timestamp.replica_id as u32,
163 local_timestamp: anchor.timestamp.value,
164 offset: anchor.offset as u64,
165 bias: match anchor.bias {
166 Bias::Left => proto::Bias::Left as i32,
167 Bias::Right => proto::Bias::Right as i32,
168 },
169 }
170}
171
172pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
173 Ok(
174 match message
175 .variant
176 .ok_or_else(|| anyhow!("missing operation variant"))?
177 {
178 proto::operation::Variant::Edit(edit) => {
179 Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
180 }
181 proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
182 lamport_timestamp: clock::Lamport {
183 replica_id: undo.replica_id as ReplicaId,
184 value: undo.lamport_timestamp,
185 },
186 undo: UndoOperation {
187 id: clock::Local {
188 replica_id: undo.replica_id as ReplicaId,
189 value: undo.local_timestamp,
190 },
191 version: deserialize_version(undo.version),
192 counts: undo
193 .counts
194 .into_iter()
195 .map(|c| {
196 (
197 clock::Local {
198 replica_id: c.replica_id as ReplicaId,
199 value: c.local_timestamp,
200 },
201 c.count,
202 )
203 })
204 .collect(),
205 transaction_ranges: undo
206 .transaction_ranges
207 .into_iter()
208 .map(deserialize_range)
209 .collect(),
210 transaction_version: deserialize_version(undo.transaction_version),
211 },
212 }),
213 proto::operation::Variant::UpdateSelections(message) => {
214 let selections = message
215 .selections
216 .into_iter()
217 .filter_map(|selection| {
218 Some(Selection {
219 id: selection.id as usize,
220 start: deserialize_anchor(selection.start?)?,
221 end: deserialize_anchor(selection.end?)?,
222 reversed: selection.reversed,
223 goal: SelectionGoal::None,
224 })
225 })
226 .collect::<Vec<_>>();
227
228 Operation::UpdateSelections {
229 lamport_timestamp: clock::Lamport {
230 replica_id: message.replica_id as ReplicaId,
231 value: message.lamport_timestamp,
232 },
233 selections: Arc::from(selections),
234 }
235 }
236 proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
237 diagnostics: deserialize_diagnostics(message.diagnostics),
238 lamport_timestamp: clock::Lamport {
239 replica_id: message.replica_id as ReplicaId,
240 value: message.lamport_timestamp,
241 },
242 },
243 proto::operation::Variant::UpdateCompletionTriggers(message) => {
244 Operation::UpdateCompletionTriggers {
245 triggers: message.triggers,
246 lamport_timestamp: clock::Lamport {
247 replica_id: message.replica_id as ReplicaId,
248 value: message.lamport_timestamp,
249 },
250 }
251 }
252 },
253 )
254}
255
256pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
257 EditOperation {
258 timestamp: InsertionTimestamp {
259 replica_id: edit.replica_id as ReplicaId,
260 local: edit.local_timestamp,
261 lamport: edit.lamport_timestamp,
262 },
263 version: deserialize_version(edit.version),
264 ranges: edit.ranges.into_iter().map(deserialize_range).collect(),
265 new_text: edit.new_text,
266 }
267}
268
269pub fn deserialize_undo_map_entry(
270 entry: proto::UndoMapEntry,
271) -> (clock::Local, Vec<(clock::Local, u32)>) {
272 (
273 clock::Local {
274 replica_id: entry.replica_id as u16,
275 value: entry.local_timestamp,
276 },
277 entry
278 .counts
279 .into_iter()
280 .map(|undo_count| {
281 (
282 clock::Local {
283 replica_id: undo_count.replica_id as u16,
284 value: undo_count.local_timestamp,
285 },
286 undo_count.count,
287 )
288 })
289 .collect(),
290 )
291}
292
293pub fn deserialize_buffer_fragment(
294 message: proto::BufferFragment,
295 ix: usize,
296 count: usize,
297) -> Fragment {
298 Fragment {
299 id: locator::Locator::from_index(ix, count),
300 insertion_timestamp: InsertionTimestamp {
301 replica_id: message.replica_id as ReplicaId,
302 local: message.local_timestamp,
303 lamport: message.lamport_timestamp,
304 },
305 insertion_offset: message.insertion_offset as usize,
306 len: message.len as usize,
307 visible: message.visible,
308 deletions: HashSet::from_iter(message.deletions.into_iter().map(|entry| clock::Local {
309 replica_id: entry.replica_id as ReplicaId,
310 value: entry.timestamp,
311 })),
312 max_undos: deserialize_version(message.max_undos),
313 }
314}
315
316pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
317 Arc::from(
318 selections
319 .into_iter()
320 .filter_map(|selection| {
321 Some(Selection {
322 id: selection.id as usize,
323 start: deserialize_anchor(selection.start?)?,
324 end: deserialize_anchor(selection.end?)?,
325 reversed: selection.reversed,
326 goal: SelectionGoal::None,
327 })
328 })
329 .collect::<Vec<_>>(),
330 )
331}
332
333pub fn deserialize_diagnostics(
334 diagnostics: Vec<proto::Diagnostic>,
335) -> Arc<[DiagnosticEntry<Anchor>]> {
336 diagnostics
337 .into_iter()
338 .filter_map(|diagnostic| {
339 Some(DiagnosticEntry {
340 range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
341 diagnostic: Diagnostic {
342 severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
343 proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
344 proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
345 proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
346 proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
347 proto::diagnostic::Severity::None => return None,
348 },
349 message: diagnostic.message,
350 group_id: diagnostic.group_id as usize,
351 code: diagnostic.code,
352 is_valid: diagnostic.is_valid,
353 is_primary: diagnostic.is_primary,
354 is_disk_based: diagnostic.is_disk_based,
355 },
356 })
357 })
358 .collect()
359}
360
361pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
362 Some(Anchor {
363 timestamp: clock::Local {
364 replica_id: anchor.replica_id as ReplicaId,
365 value: anchor.local_timestamp,
366 },
367 offset: anchor.offset as usize,
368 bias: match proto::Bias::from_i32(anchor.bias)? {
369 proto::Bias::Left => Bias::Left,
370 proto::Bias::Right => Bias::Right,
371 },
372 })
373}
374
375pub fn lamport_timestamp_for_operation(operation: &proto::Operation) -> Option<clock::Lamport> {
376 let replica_id;
377 let value;
378 match operation.variant.as_ref()? {
379 proto::operation::Variant::Edit(op) => {
380 replica_id = op.replica_id;
381 value = op.lamport_timestamp;
382 }
383 proto::operation::Variant::Undo(op) => {
384 replica_id = op.replica_id;
385 value = op.lamport_timestamp;
386 }
387 proto::operation::Variant::UpdateDiagnostics(op) => {
388 replica_id = op.replica_id;
389 value = op.lamport_timestamp;
390 }
391 proto::operation::Variant::UpdateSelections(op) => {
392 replica_id = op.replica_id;
393 value = op.lamport_timestamp;
394 }
395 proto::operation::Variant::UpdateCompletionTriggers(op) => {
396 replica_id = op.replica_id;
397 value = op.lamport_timestamp;
398 }
399 }
400
401 Some(clock::Lamport {
402 replica_id: replica_id as ReplicaId,
403 value,
404 })
405}
406
407pub fn serialize_completion(completion: &Completion) -> proto::Completion {
408 proto::Completion {
409 old_start: Some(serialize_anchor(&completion.old_range.start)),
410 old_end: Some(serialize_anchor(&completion.old_range.end)),
411 new_text: completion.new_text.clone(),
412 lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
413 }
414}
415
416pub fn deserialize_completion(
417 completion: proto::Completion,
418 language: Option<&Arc<Language>>,
419) -> Result<Completion> {
420 let old_start = completion
421 .old_start
422 .and_then(deserialize_anchor)
423 .ok_or_else(|| anyhow!("invalid old start"))?;
424 let old_end = completion
425 .old_end
426 .and_then(deserialize_anchor)
427 .ok_or_else(|| anyhow!("invalid old end"))?;
428 let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
429 Ok(Completion {
430 old_range: old_start..old_end,
431 new_text: completion.new_text,
432 label: language
433 .and_then(|l| l.label_for_completion(&lsp_completion))
434 .unwrap_or(CodeLabel::plain(
435 lsp_completion.label.clone(),
436 lsp_completion.filter_text.as_deref(),
437 )),
438 lsp_completion,
439 })
440}
441
442pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
443 proto::CodeAction {
444 start: Some(serialize_anchor(&action.range.start)),
445 end: Some(serialize_anchor(&action.range.end)),
446 lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
447 }
448}
449
450pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
451 let start = action
452 .start
453 .and_then(deserialize_anchor)
454 .ok_or_else(|| anyhow!("invalid start"))?;
455 let end = action
456 .end
457 .and_then(deserialize_anchor)
458 .ok_or_else(|| anyhow!("invalid end"))?;
459 let lsp_action = serde_json::from_slice(&action.lsp_action)?;
460 Ok(CodeAction {
461 range: start..end,
462 lsp_action,
463 })
464}
465
466pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
467 proto::Transaction {
468 id: Some(serialize_local_timestamp(transaction.id)),
469 edit_ids: transaction
470 .edit_ids
471 .iter()
472 .copied()
473 .map(serialize_local_timestamp)
474 .collect(),
475 start: serialize_version(&transaction.start),
476 end: serialize_version(&transaction.end),
477 ranges: transaction.ranges.iter().map(serialize_range).collect(),
478 }
479}
480
481pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transaction> {
482 Ok(Transaction {
483 id: deserialize_local_timestamp(
484 transaction
485 .id
486 .ok_or_else(|| anyhow!("missing transaction id"))?,
487 ),
488 edit_ids: transaction
489 .edit_ids
490 .into_iter()
491 .map(deserialize_local_timestamp)
492 .collect(),
493 start: deserialize_version(transaction.start.into()),
494 end: deserialize_version(transaction.end),
495 ranges: transaction
496 .ranges
497 .into_iter()
498 .map(deserialize_range)
499 .collect(),
500 })
501}
502
503pub fn serialize_local_timestamp(timestamp: clock::Local) -> proto::LocalTimestamp {
504 proto::LocalTimestamp {
505 replica_id: timestamp.replica_id as u32,
506 value: timestamp.value,
507 }
508}
509
510pub fn deserialize_local_timestamp(timestamp: proto::LocalTimestamp) -> clock::Local {
511 clock::Local {
512 replica_id: timestamp.replica_id as ReplicaId,
513 value: timestamp.value,
514 }
515}
516
517pub fn serialize_range(range: &Range<FullOffset>) -> proto::Range {
518 proto::Range {
519 start: range.start.0 as u64,
520 end: range.end.0 as u64,
521 }
522}
523
524pub fn deserialize_range(range: proto::Range) -> Range<FullOffset> {
525 FullOffset(range.start as usize)..FullOffset(range.end as usize)
526}
527
528pub fn deserialize_version(message: Vec<proto::VectorClockEntry>) -> clock::Global {
529 let mut version = clock::Global::new();
530 for entry in message {
531 version.observe(clock::Local {
532 replica_id: entry.replica_id as ReplicaId,
533 value: entry.timestamp,
534 });
535 }
536 version
537}
538
539pub fn serialize_version(version: &clock::Global) -> Vec<proto::VectorClockEntry> {
540 version
541 .iter()
542 .map(|entry| proto::VectorClockEntry {
543 replica_id: entry.replica_id as u32,
544 timestamp: entry.value,
545 })
546 .collect()
547}