1use std::sync::Arc;
2
3use crate::{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 version: selections.version().into(),
53 selections: selections
54 .full_offset_ranges()
55 .map(|(range, state)| proto::Selection {
56 id: state.id as u64,
57 start: range.start.0 as u64,
58 end: range.end.0 as u64,
59 reversed: state.reversed,
60 })
61 .collect(),
62 }),
63 Operation::Buffer(text::Operation::RemoveSelections {
64 set_id,
65 lamport_timestamp,
66 }) => proto::operation::Variant::RemoveSelections(proto::operation::RemoveSelections {
67 replica_id: set_id.replica_id as u32,
68 local_timestamp: set_id.value,
69 lamport_timestamp: lamport_timestamp.value,
70 }),
71 Operation::Buffer(text::Operation::SetActiveSelections {
72 set_id,
73 lamport_timestamp,
74 }) => proto::operation::Variant::SetActiveSelections(
75 proto::operation::SetActiveSelections {
76 replica_id: lamport_timestamp.replica_id as u32,
77 local_timestamp: set_id.map(|set_id| set_id.value),
78 lamport_timestamp: lamport_timestamp.value,
79 },
80 ),
81 Operation::UpdateDiagnostics(diagnostic_set) => {
82 proto::operation::Variant::UpdateDiagnostics(serialize_diagnostics(diagnostic_set))
83 }
84 }),
85 }
86}
87
88pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
89 let ranges = operation
90 .ranges
91 .iter()
92 .map(|range| proto::Range {
93 start: range.start.0 as u64,
94 end: range.end.0 as u64,
95 })
96 .collect();
97 proto::operation::Edit {
98 replica_id: operation.timestamp.replica_id as u32,
99 local_timestamp: operation.timestamp.local,
100 lamport_timestamp: operation.timestamp.lamport,
101 version: From::from(&operation.version),
102 ranges,
103 new_text: operation.new_text.clone(),
104 }
105}
106
107pub fn serialize_selection_set(set: &SelectionSet) -> proto::SelectionSet {
108 let version = set.selections.version();
109 let entries = set.selections.full_offset_ranges();
110 proto::SelectionSet {
111 replica_id: set.id.replica_id as u32,
112 lamport_timestamp: set.id.value as u32,
113 is_active: set.active,
114 version: version.into(),
115 selections: entries
116 .map(|(range, state)| proto::Selection {
117 id: state.id as u64,
118 start: range.start.0 as u64,
119 end: range.end.0 as u64,
120 reversed: state.reversed,
121 })
122 .collect(),
123 }
124}
125
126pub fn serialize_diagnostics(map: &AnchorRangeMultimap<Diagnostic>) -> proto::DiagnosticSet {
127 proto::DiagnosticSet {
128 version: map.version().into(),
129 diagnostics: map
130 .full_offset_ranges()
131 .map(|(range, diagnostic)| proto::Diagnostic {
132 start: range.start.0 as u64,
133 end: range.end.0 as u64,
134 message: diagnostic.message.clone(),
135 severity: match diagnostic.severity {
136 DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
137 DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
138 DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
139 DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
140 _ => proto::diagnostic::Severity::None,
141 } as i32,
142 group_id: diagnostic.group_id as u64,
143 is_primary: diagnostic.is_primary,
144 })
145 .collect(),
146 }
147}
148
149pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
150 Ok(
151 match message
152 .variant
153 .ok_or_else(|| anyhow!("missing operation variant"))?
154 {
155 proto::operation::Variant::Edit(edit) => {
156 Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
157 }
158 proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
159 lamport_timestamp: clock::Lamport {
160 replica_id: undo.replica_id as ReplicaId,
161 value: undo.lamport_timestamp,
162 },
163 undo: UndoOperation {
164 id: clock::Local {
165 replica_id: undo.replica_id as ReplicaId,
166 value: undo.local_timestamp,
167 },
168 counts: undo
169 .counts
170 .into_iter()
171 .map(|c| {
172 (
173 clock::Local {
174 replica_id: c.replica_id as ReplicaId,
175 value: c.local_timestamp,
176 },
177 c.count,
178 )
179 })
180 .collect(),
181 ranges: undo
182 .ranges
183 .into_iter()
184 .map(|r| FullOffset(r.start as usize)..FullOffset(r.end as usize))
185 .collect(),
186 version: undo.version.into(),
187 },
188 }),
189 proto::operation::Variant::UpdateSelections(message) => {
190 let version = message.version.into();
191 let entries = message
192 .selections
193 .iter()
194 .map(|selection| {
195 let range = FullOffset(selection.start as usize)
196 ..FullOffset(selection.end as usize);
197 let state = SelectionState {
198 id: selection.id as usize,
199 reversed: selection.reversed,
200 goal: SelectionGoal::None,
201 };
202 (range, state)
203 })
204 .collect();
205 let selections = AnchorRangeMap::from_full_offset_ranges(
206 version,
207 Bias::Left,
208 Bias::Left,
209 entries,
210 );
211
212 Operation::Buffer(text::Operation::UpdateSelections {
213 set_id: clock::Lamport {
214 replica_id: message.replica_id as ReplicaId,
215 value: message.local_timestamp,
216 },
217 lamport_timestamp: clock::Lamport {
218 replica_id: message.replica_id as ReplicaId,
219 value: message.lamport_timestamp,
220 },
221 selections: Arc::from(selections),
222 })
223 }
224 proto::operation::Variant::RemoveSelections(message) => {
225 Operation::Buffer(text::Operation::RemoveSelections {
226 set_id: clock::Lamport {
227 replica_id: message.replica_id as ReplicaId,
228 value: message.local_timestamp,
229 },
230 lamport_timestamp: clock::Lamport {
231 replica_id: message.replica_id as ReplicaId,
232 value: message.lamport_timestamp,
233 },
234 })
235 }
236 proto::operation::Variant::SetActiveSelections(message) => {
237 Operation::Buffer(text::Operation::SetActiveSelections {
238 set_id: message.local_timestamp.map(|value| clock::Lamport {
239 replica_id: message.replica_id as ReplicaId,
240 value,
241 }),
242 lamport_timestamp: clock::Lamport {
243 replica_id: message.replica_id as ReplicaId,
244 value: message.lamport_timestamp,
245 },
246 })
247 }
248 proto::operation::Variant::UpdateDiagnostics(message) => {
249 Operation::UpdateDiagnostics(deserialize_diagnostics(message))
250 }
251 },
252 )
253}
254
255pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
256 let ranges = edit
257 .ranges
258 .into_iter()
259 .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
260 .collect();
261 EditOperation {
262 timestamp: InsertionTimestamp {
263 replica_id: edit.replica_id as ReplicaId,
264 local: edit.local_timestamp,
265 lamport: edit.lamport_timestamp,
266 },
267 version: edit.version.into(),
268 ranges,
269 new_text: edit.new_text,
270 }
271}
272
273pub fn deserialize_selection_set(set: proto::SelectionSet) -> SelectionSet {
274 SelectionSet {
275 id: clock::Lamport {
276 replica_id: set.replica_id as u16,
277 value: set.lamport_timestamp,
278 },
279 active: set.is_active,
280 selections: Arc::new(AnchorRangeMap::from_full_offset_ranges(
281 set.version.into(),
282 Bias::Left,
283 Bias::Left,
284 set.selections
285 .into_iter()
286 .map(|selection| {
287 let range =
288 FullOffset(selection.start as usize)..FullOffset(selection.end as usize);
289 let state = SelectionState {
290 id: selection.id as usize,
291 reversed: selection.reversed,
292 goal: SelectionGoal::None,
293 };
294 (range, state)
295 })
296 .collect(),
297 )),
298 }
299}
300
301pub fn deserialize_diagnostics(message: proto::DiagnosticSet) -> AnchorRangeMultimap<Diagnostic> {
302 AnchorRangeMultimap::from_full_offset_ranges(
303 message.version.into(),
304 Bias::Left,
305 Bias::Right,
306 message.diagnostics.into_iter().filter_map(|diagnostic| {
307 Some((
308 FullOffset(diagnostic.start as usize)..FullOffset(diagnostic.end as usize),
309 Diagnostic {
310 severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
311 proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
312 proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
313 proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
314 proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
315 proto::diagnostic::Severity::None => return None,
316 },
317 message: diagnostic.message,
318 group_id: diagnostic.group_id as usize,
319 is_primary: diagnostic.is_primary,
320 },
321 ))
322 }),
323 )
324}