1use crate::{diagnostic_set::DiagnosticEntry, Diagnostic, Operation};
2use anyhow::{anyhow, Result};
3use clock::ReplicaId;
4use lsp::DiagnosticSeverity;
5use rpc::proto;
6use std::sync::Arc;
7use text::*;
8
9pub use proto::{Buffer, SelectionSet};
10
11pub fn serialize_operation(operation: &Operation) -> proto::Operation {
12 proto::Operation {
13 variant: Some(match operation {
14 Operation::Buffer(text::Operation::Edit(edit)) => {
15 proto::operation::Variant::Edit(serialize_edit_operation(edit))
16 }
17 Operation::Buffer(text::Operation::Undo {
18 undo,
19 lamport_timestamp,
20 }) => proto::operation::Variant::Undo(proto::operation::Undo {
21 replica_id: undo.id.replica_id as u32,
22 local_timestamp: undo.id.value,
23 lamport_timestamp: lamport_timestamp.value,
24 ranges: undo
25 .ranges
26 .iter()
27 .map(|r| proto::Range {
28 start: r.start.0 as u64,
29 end: r.end.0 as u64,
30 })
31 .collect(),
32 counts: undo
33 .counts
34 .iter()
35 .map(|(edit_id, count)| proto::operation::UndoCount {
36 replica_id: edit_id.replica_id as u32,
37 local_timestamp: edit_id.value,
38 count: *count,
39 })
40 .collect(),
41 version: From::from(&undo.version),
42 }),
43 Operation::UpdateSelections {
44 replica_id,
45 selections,
46 lamport_timestamp,
47 } => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
48 replica_id: *replica_id as u32,
49 lamport_timestamp: lamport_timestamp.value,
50 selections: serialize_selections(selections),
51 }),
52 Operation::RemoveSelections {
53 replica_id,
54 lamport_timestamp,
55 } => proto::operation::Variant::RemoveSelections(proto::operation::RemoveSelections {
56 replica_id: *replica_id as u32,
57 lamport_timestamp: lamport_timestamp.value,
58 }),
59 Operation::UpdateDiagnostics {
60 provider_name,
61 diagnostics,
62 lamport_timestamp,
63 } => proto::operation::Variant::UpdateDiagnosticSet(proto::UpdateDiagnosticSet {
64 replica_id: lamport_timestamp.replica_id as u32,
65 lamport_timestamp: lamport_timestamp.value,
66 diagnostic_set: Some(serialize_diagnostic_set(
67 provider_name.clone(),
68 diagnostics.iter(),
69 )),
70 }),
71 }),
72 }
73}
74
75pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
76 let ranges = operation
77 .ranges
78 .iter()
79 .map(|range| proto::Range {
80 start: range.start.0 as u64,
81 end: range.end.0 as u64,
82 })
83 .collect();
84 proto::operation::Edit {
85 replica_id: operation.timestamp.replica_id as u32,
86 local_timestamp: operation.timestamp.local,
87 lamport_timestamp: operation.timestamp.lamport,
88 version: From::from(&operation.version),
89 ranges,
90 new_text: operation.new_text.clone(),
91 }
92}
93
94pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
95 selections
96 .iter()
97 .map(|selection| proto::Selection {
98 id: selection.id as u64,
99 start: Some(serialize_anchor(&selection.start)),
100 end: Some(serialize_anchor(&selection.end)),
101 reversed: selection.reversed,
102 })
103 .collect()
104}
105
106pub fn serialize_diagnostic_set<'a>(
107 provider_name: String,
108 diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
109) -> proto::DiagnosticSet {
110 proto::DiagnosticSet {
111 provider_name,
112 diagnostics: diagnostics
113 .into_iter()
114 .map(|entry| proto::Diagnostic {
115 start: Some(serialize_anchor(&entry.range.start)),
116 end: Some(serialize_anchor(&entry.range.end)),
117 message: entry.diagnostic.message.clone(),
118 severity: match entry.diagnostic.severity {
119 DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
120 DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
121 DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
122 DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
123 _ => proto::diagnostic::Severity::None,
124 } as i32,
125 group_id: entry.diagnostic.group_id as u64,
126 is_primary: entry.diagnostic.is_primary,
127 is_valid: entry.diagnostic.is_valid,
128 code: entry.diagnostic.code.clone(),
129 is_disk_based: entry.diagnostic.is_disk_based,
130 })
131 .collect(),
132 }
133}
134
135fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
136 proto::Anchor {
137 replica_id: anchor.timestamp.replica_id as u32,
138 local_timestamp: anchor.timestamp.value,
139 offset: anchor.offset as u64,
140 bias: match anchor.bias {
141 Bias::Left => proto::Bias::Left as i32,
142 Bias::Right => proto::Bias::Right as i32,
143 },
144 }
145}
146
147pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
148 Ok(
149 match message
150 .variant
151 .ok_or_else(|| anyhow!("missing operation variant"))?
152 {
153 proto::operation::Variant::Edit(edit) => {
154 Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
155 }
156 proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
157 lamport_timestamp: clock::Lamport {
158 replica_id: undo.replica_id as ReplicaId,
159 value: undo.lamport_timestamp,
160 },
161 undo: UndoOperation {
162 id: clock::Local {
163 replica_id: undo.replica_id as ReplicaId,
164 value: undo.local_timestamp,
165 },
166 counts: undo
167 .counts
168 .into_iter()
169 .map(|c| {
170 (
171 clock::Local {
172 replica_id: c.replica_id as ReplicaId,
173 value: c.local_timestamp,
174 },
175 c.count,
176 )
177 })
178 .collect(),
179 ranges: undo
180 .ranges
181 .into_iter()
182 .map(|r| FullOffset(r.start as usize)..FullOffset(r.end as usize))
183 .collect(),
184 version: undo.version.into(),
185 },
186 }),
187 proto::operation::Variant::UpdateSelections(message) => {
188 let selections = message
189 .selections
190 .into_iter()
191 .filter_map(|selection| {
192 Some(Selection {
193 id: selection.id as usize,
194 start: deserialize_anchor(selection.start?)?,
195 end: deserialize_anchor(selection.end?)?,
196 reversed: selection.reversed,
197 goal: SelectionGoal::None,
198 })
199 })
200 .collect::<Vec<_>>();
201
202 Operation::UpdateSelections {
203 replica_id: message.replica_id as ReplicaId,
204 lamport_timestamp: clock::Lamport {
205 replica_id: message.replica_id as ReplicaId,
206 value: message.lamport_timestamp,
207 },
208 selections: Arc::from(selections),
209 }
210 }
211 proto::operation::Variant::RemoveSelections(message) => Operation::RemoveSelections {
212 replica_id: message.replica_id as ReplicaId,
213 lamport_timestamp: clock::Lamport {
214 replica_id: message.replica_id as ReplicaId,
215 value: message.lamport_timestamp,
216 },
217 },
218 proto::operation::Variant::UpdateDiagnosticSet(message) => {
219 let (provider_name, diagnostics) = deserialize_diagnostic_set(
220 message
221 .diagnostic_set
222 .ok_or_else(|| anyhow!("missing diagnostic set"))?,
223 );
224 Operation::UpdateDiagnostics {
225 provider_name,
226 diagnostics,
227 lamport_timestamp: clock::Lamport {
228 replica_id: message.replica_id as ReplicaId,
229 value: message.lamport_timestamp,
230 },
231 }
232 }
233 },
234 )
235}
236
237pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
238 let ranges = edit
239 .ranges
240 .into_iter()
241 .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
242 .collect();
243 EditOperation {
244 timestamp: InsertionTimestamp {
245 replica_id: edit.replica_id as ReplicaId,
246 local: edit.local_timestamp,
247 lamport: edit.lamport_timestamp,
248 },
249 version: edit.version.into(),
250 ranges,
251 new_text: edit.new_text,
252 }
253}
254
255pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
256 Arc::from(
257 selections
258 .into_iter()
259 .filter_map(|selection| {
260 Some(Selection {
261 id: selection.id as usize,
262 start: deserialize_anchor(selection.start?)?,
263 end: deserialize_anchor(selection.end?)?,
264 reversed: selection.reversed,
265 goal: SelectionGoal::None,
266 })
267 })
268 .collect::<Vec<_>>(),
269 )
270}
271
272pub fn deserialize_diagnostic_set(
273 message: proto::DiagnosticSet,
274) -> (String, Arc<[DiagnosticEntry<Anchor>]>) {
275 (
276 message.provider_name,
277 message
278 .diagnostics
279 .into_iter()
280 .filter_map(|diagnostic| {
281 Some(DiagnosticEntry {
282 range: deserialize_anchor(diagnostic.start?)?
283 ..deserialize_anchor(diagnostic.end?)?,
284 diagnostic: Diagnostic {
285 severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)?
286 {
287 proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
288 proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
289 proto::diagnostic::Severity::Information => {
290 DiagnosticSeverity::INFORMATION
291 }
292 proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
293 proto::diagnostic::Severity::None => return None,
294 },
295 message: diagnostic.message,
296 group_id: diagnostic.group_id as usize,
297 code: diagnostic.code,
298 is_valid: diagnostic.is_valid,
299 is_primary: diagnostic.is_primary,
300 is_disk_based: diagnostic.is_disk_based,
301 },
302 })
303 })
304 .collect(),
305 )
306}
307
308fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
309 Some(Anchor {
310 timestamp: clock::Local {
311 replica_id: anchor.replica_id as ReplicaId,
312 value: anchor.local_timestamp,
313 },
314 offset: anchor.offset as usize,
315 bias: match proto::Bias::from_i32(anchor.bias)? {
316 proto::Bias::Left => Bias::Left,
317 proto::Bias::Right => Bias::Right,
318 },
319 })
320}