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}