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 diagnostics,
61 lamport_timestamp,
62 } => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics {
63 replica_id: lamport_timestamp.replica_id as u32,
64 lamport_timestamp: lamport_timestamp.value,
65 diagnostics: serialize_diagnostics(diagnostics.iter()),
66 }),
67 }),
68 }
69}
70
71pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
72 let ranges = operation
73 .ranges
74 .iter()
75 .map(|range| proto::Range {
76 start: range.start.0 as u64,
77 end: range.end.0 as u64,
78 })
79 .collect();
80 proto::operation::Edit {
81 replica_id: operation.timestamp.replica_id as u32,
82 local_timestamp: operation.timestamp.local,
83 lamport_timestamp: operation.timestamp.lamport,
84 version: From::from(&operation.version),
85 ranges,
86 new_text: operation.new_text.clone(),
87 }
88}
89
90pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
91 selections
92 .iter()
93 .map(|selection| proto::Selection {
94 id: selection.id as u64,
95 start: Some(serialize_anchor(&selection.start)),
96 end: Some(serialize_anchor(&selection.end)),
97 reversed: selection.reversed,
98 })
99 .collect()
100}
101
102pub fn serialize_diagnostics<'a>(
103 diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
104) -> Vec<proto::Diagnostic> {
105 diagnostics
106 .into_iter()
107 .map(|entry| proto::Diagnostic {
108 start: Some(serialize_anchor(&entry.range.start)),
109 end: Some(serialize_anchor(&entry.range.end)),
110 message: entry.diagnostic.message.clone(),
111 severity: match entry.diagnostic.severity {
112 DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
113 DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
114 DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
115 DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
116 _ => proto::diagnostic::Severity::None,
117 } as i32,
118 group_id: entry.diagnostic.group_id as u64,
119 is_primary: entry.diagnostic.is_primary,
120 code: entry.diagnostic.code.clone(),
121 source: entry.diagnostic.source.clone(),
122 })
123 .collect()
124}
125
126fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
127 proto::Anchor {
128 replica_id: anchor.timestamp.replica_id as u32,
129 local_timestamp: anchor.timestamp.value,
130 offset: anchor.offset as u64,
131 bias: match anchor.bias {
132 Bias::Left => proto::Bias::Left as i32,
133 Bias::Right => proto::Bias::Right as i32,
134 },
135 }
136}
137
138pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
139 Ok(
140 match message
141 .variant
142 .ok_or_else(|| anyhow!("missing operation variant"))?
143 {
144 proto::operation::Variant::Edit(edit) => {
145 Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
146 }
147 proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
148 lamport_timestamp: clock::Lamport {
149 replica_id: undo.replica_id as ReplicaId,
150 value: undo.lamport_timestamp,
151 },
152 undo: UndoOperation {
153 id: clock::Local {
154 replica_id: undo.replica_id as ReplicaId,
155 value: undo.local_timestamp,
156 },
157 counts: undo
158 .counts
159 .into_iter()
160 .map(|c| {
161 (
162 clock::Local {
163 replica_id: c.replica_id as ReplicaId,
164 value: c.local_timestamp,
165 },
166 c.count,
167 )
168 })
169 .collect(),
170 ranges: undo
171 .ranges
172 .into_iter()
173 .map(|r| FullOffset(r.start as usize)..FullOffset(r.end as usize))
174 .collect(),
175 version: undo.version.into(),
176 },
177 }),
178 proto::operation::Variant::UpdateSelections(message) => {
179 let selections = message
180 .selections
181 .into_iter()
182 .filter_map(|selection| {
183 Some(Selection {
184 id: selection.id as usize,
185 start: deserialize_anchor(selection.start?)?,
186 end: deserialize_anchor(selection.end?)?,
187 reversed: selection.reversed,
188 goal: SelectionGoal::None,
189 })
190 })
191 .collect::<Vec<_>>();
192
193 Operation::UpdateSelections {
194 replica_id: message.replica_id as ReplicaId,
195 lamport_timestamp: clock::Lamport {
196 replica_id: message.replica_id as ReplicaId,
197 value: message.lamport_timestamp,
198 },
199 selections: Arc::from(selections),
200 }
201 }
202 proto::operation::Variant::RemoveSelections(message) => Operation::RemoveSelections {
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 },
209 proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
210 diagnostics: Arc::from(deserialize_diagnostics(message.diagnostics)),
211 lamport_timestamp: clock::Lamport {
212 replica_id: message.replica_id as ReplicaId,
213 value: message.lamport_timestamp,
214 },
215 },
216 },
217 )
218}
219
220pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
221 let ranges = edit
222 .ranges
223 .into_iter()
224 .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
225 .collect();
226 EditOperation {
227 timestamp: InsertionTimestamp {
228 replica_id: edit.replica_id as ReplicaId,
229 local: edit.local_timestamp,
230 lamport: edit.lamport_timestamp,
231 },
232 version: edit.version.into(),
233 ranges,
234 new_text: edit.new_text,
235 }
236}
237
238pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
239 Arc::from(
240 selections
241 .into_iter()
242 .filter_map(|selection| {
243 Some(Selection {
244 id: selection.id as usize,
245 start: deserialize_anchor(selection.start?)?,
246 end: deserialize_anchor(selection.end?)?,
247 reversed: selection.reversed,
248 goal: SelectionGoal::None,
249 })
250 })
251 .collect::<Vec<_>>(),
252 )
253}
254
255pub fn deserialize_diagnostics(
256 diagnostics: Vec<proto::Diagnostic>,
257) -> Vec<DiagnosticEntry<Anchor>> {
258 diagnostics
259 .into_iter()
260 .filter_map(|diagnostic| {
261 Some(DiagnosticEntry {
262 range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
263 diagnostic: Diagnostic {
264 severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
265 proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
266 proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
267 proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
268 proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
269 proto::diagnostic::Severity::None => return None,
270 },
271 message: diagnostic.message,
272 group_id: diagnostic.group_id as usize,
273 is_primary: diagnostic.is_primary,
274 code: diagnostic.code,
275 source: diagnostic.source,
276 },
277 })
278 })
279 .collect()
280}
281
282fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
283 Some(Anchor {
284 timestamp: clock::Local {
285 replica_id: anchor.replica_id as ReplicaId,
286 value: anchor.local_timestamp,
287 },
288 offset: anchor.offset as usize,
289 bias: match proto::Bias::from_i32(anchor.bias)? {
290 proto::Bias::Left => Bias::Left,
291 proto::Bias::Right => Bias::Right,
292 },
293 })
294}