1use std::sync::Arc;
2
3use crate::Diagnostic;
4
5use super::Operation;
6use anyhow::{anyhow, Result};
7use buffer::*;
8use clock::ReplicaId;
9use lsp::DiagnosticSeverity;
10use rpc::proto;
11
12pub use proto::Buffer;
13
14pub fn serialize_operation(operation: &Operation) -> proto::Operation {
15 proto::Operation {
16 variant: Some(match operation {
17 Operation::Buffer(buffer::Operation::Edit(edit)) => {
18 proto::operation::Variant::Edit(serialize_edit_operation(edit))
19 }
20 Operation::Buffer(buffer::Operation::Undo {
21 undo,
22 lamport_timestamp,
23 }) => proto::operation::Variant::Undo(proto::operation::Undo {
24 replica_id: undo.id.replica_id as u32,
25 local_timestamp: undo.id.value,
26 lamport_timestamp: lamport_timestamp.value,
27 ranges: undo
28 .ranges
29 .iter()
30 .map(|r| proto::Range {
31 start: r.start.0 as u64,
32 end: r.end.0 as u64,
33 })
34 .collect(),
35 counts: undo
36 .counts
37 .iter()
38 .map(|(edit_id, count)| proto::operation::UndoCount {
39 replica_id: edit_id.replica_id as u32,
40 local_timestamp: edit_id.value,
41 count: *count,
42 })
43 .collect(),
44 version: From::from(&undo.version),
45 }),
46 Operation::Buffer(buffer::Operation::UpdateSelections {
47 set_id,
48 selections,
49 lamport_timestamp,
50 }) => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
51 replica_id: set_id.replica_id as u32,
52 local_timestamp: set_id.value,
53 lamport_timestamp: lamport_timestamp.value,
54 version: selections.version().into(),
55 selections: selections
56 .full_offset_ranges()
57 .map(|(range, state)| proto::Selection {
58 id: state.id as u64,
59 start: range.start.0 as u64,
60 end: range.end.0 as u64,
61 reversed: state.reversed,
62 })
63 .collect(),
64 }),
65 Operation::Buffer(buffer::Operation::RemoveSelections {
66 set_id,
67 lamport_timestamp,
68 }) => proto::operation::Variant::RemoveSelections(proto::operation::RemoveSelections {
69 replica_id: set_id.replica_id as u32,
70 local_timestamp: set_id.value,
71 lamport_timestamp: lamport_timestamp.value,
72 }),
73 Operation::Buffer(buffer::Operation::SetActiveSelections {
74 set_id,
75 lamport_timestamp,
76 }) => proto::operation::Variant::SetActiveSelections(
77 proto::operation::SetActiveSelections {
78 replica_id: lamport_timestamp.replica_id as u32,
79 local_timestamp: set_id.map(|set_id| set_id.value),
80 lamport_timestamp: lamport_timestamp.value,
81 },
82 ),
83 Operation::UpdateDiagnostics(diagnostic_set) => {
84 proto::operation::Variant::UpdateDiagnostics(serialize_diagnostics(diagnostic_set))
85 }
86 }),
87 }
88}
89
90pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
91 let ranges = operation
92 .ranges
93 .iter()
94 .map(|range| proto::Range {
95 start: range.start.0 as u64,
96 end: range.end.0 as u64,
97 })
98 .collect();
99 proto::operation::Edit {
100 replica_id: operation.timestamp.replica_id as u32,
101 local_timestamp: operation.timestamp.local,
102 lamport_timestamp: operation.timestamp.lamport,
103 version: From::from(&operation.version),
104 ranges,
105 new_text: operation.new_text.clone(),
106 }
107}
108
109pub fn serialize_selection_set(set: &SelectionSet) -> proto::SelectionSet {
110 let version = set.selections.version();
111 let entries = set.selections.full_offset_ranges();
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 version: version.into(),
117 selections: entries
118 .map(|(range, state)| proto::Selection {
119 id: state.id as u64,
120 start: range.start.0 as u64,
121 end: range.end.0 as u64,
122 reversed: state.reversed,
123 })
124 .collect(),
125 }
126}
127
128pub fn serialize_diagnostics(map: &AnchorRangeMultimap<Diagnostic>) -> proto::DiagnosticSet {
129 proto::DiagnosticSet {
130 version: map.version().into(),
131 diagnostics: map
132 .full_offset_ranges()
133 .map(|(range, diagnostic)| proto::Diagnostic {
134 start: range.start.0 as u64,
135 end: range.end.0 as u64,
136 message: diagnostic.message.clone(),
137 severity: match diagnostic.severity {
138 DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
139 DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
140 DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
141 DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
142 _ => proto::diagnostic::Severity::None,
143 } as i32,
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(buffer::Operation::Edit(deserialize_edit_operation(edit)))
157 }
158 proto::operation::Variant::Undo(undo) => Operation::Buffer(buffer::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), Bias::Left)
196 ..(FullOffset(selection.end as usize), Bias::Right);
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(version, entries);
206
207 Operation::Buffer(buffer::Operation::UpdateSelections {
208 set_id: clock::Lamport {
209 replica_id: message.replica_id as ReplicaId,
210 value: message.local_timestamp,
211 },
212 lamport_timestamp: clock::Lamport {
213 replica_id: message.replica_id as ReplicaId,
214 value: message.lamport_timestamp,
215 },
216 selections: Arc::from(selections),
217 })
218 }
219 proto::operation::Variant::RemoveSelections(message) => {
220 Operation::Buffer(buffer::Operation::RemoveSelections {
221 set_id: clock::Lamport {
222 replica_id: message.replica_id as ReplicaId,
223 value: message.local_timestamp,
224 },
225 lamport_timestamp: clock::Lamport {
226 replica_id: message.replica_id as ReplicaId,
227 value: message.lamport_timestamp,
228 },
229 })
230 }
231 proto::operation::Variant::SetActiveSelections(message) => {
232 Operation::Buffer(buffer::Operation::SetActiveSelections {
233 set_id: message.local_timestamp.map(|value| clock::Lamport {
234 replica_id: message.replica_id as ReplicaId,
235 value,
236 }),
237 lamport_timestamp: clock::Lamport {
238 replica_id: message.replica_id as ReplicaId,
239 value: message.lamport_timestamp,
240 },
241 })
242 }
243 proto::operation::Variant::UpdateDiagnostics(message) => {
244 Operation::UpdateDiagnostics(deserialize_diagnostics(message))
245 }
246 },
247 )
248}
249
250pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
251 let ranges = edit
252 .ranges
253 .into_iter()
254 .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
255 .collect();
256 EditOperation {
257 timestamp: InsertionTimestamp {
258 replica_id: edit.replica_id as ReplicaId,
259 local: edit.local_timestamp,
260 lamport: edit.lamport_timestamp,
261 },
262 version: edit.version.into(),
263 ranges,
264 new_text: edit.new_text,
265 }
266}
267
268pub fn deserialize_selection_set(set: proto::SelectionSet) -> SelectionSet {
269 SelectionSet {
270 id: clock::Lamport {
271 replica_id: set.replica_id as u16,
272 value: set.lamport_timestamp,
273 },
274 active: set.is_active,
275 selections: Arc::new(AnchorRangeMap::from_full_offset_ranges(
276 set.version.into(),
277 set.selections
278 .into_iter()
279 .map(|selection| {
280 let range = (FullOffset(selection.start as usize), Bias::Left)
281 ..(FullOffset(selection.end as usize), Bias::Right);
282 let state = SelectionState {
283 id: selection.id as usize,
284 reversed: selection.reversed,
285 goal: SelectionGoal::None,
286 };
287 (range, state)
288 })
289 .collect(),
290 )),
291 }
292}
293
294pub fn deserialize_diagnostics(message: proto::DiagnosticSet) -> AnchorRangeMultimap<Diagnostic> {
295 AnchorRangeMultimap::from_full_offset_ranges(
296 message.version.into(),
297 Bias::Left,
298 Bias::Right,
299 message.diagnostics.into_iter().filter_map(|diagnostic| {
300 Some((
301 FullOffset(diagnostic.start as usize)..FullOffset(diagnostic.end as usize),
302 Diagnostic {
303 severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
304 proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
305 proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
306 proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
307 proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
308 proto::diagnostic::Severity::None => return None,
309 },
310 message: diagnostic.message,
311 },
312 ))
313 }),
314 )
315}