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