1use std::collections::{BTreeMap, BTreeSet};
3use std::fmt;
4
5pub const MAX_SAFE_INTEGER: u64 = 9_007_199_254_740_991;
6pub const MAX_FRAME_BYTES: usize = 8 * 1024 * 1024;
7pub const MAX_PATCH_BYTES: usize = 1024 * 1024;
8pub const MAX_VECTOR_ENTRIES: usize = 1024;
9pub const MAX_MESSAGE_ROWS: usize = 4096;
10pub const MAX_SCHEMA_NODES: usize = 300_000;
11const MAX_ROW_BATCH_NODES: usize = MAX_SCHEMA_NODES - (3 * MAX_VECTOR_ENTRIES + 16);
12pub type VersionVector = Vec<(u64, u64)>;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct Error {
16 pub code: &'static str,
17 pub message: String,
18}
19impl Error {
20 fn new(code: &'static str, message: &str) -> Self {
21 Self {
22 code,
23 message: message.into(),
24 }
25 }
26}
27impl fmt::Display for Error {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "{}: {}", self.code, self.message)
30 }
31}
32impl std::error::Error for Error {}
33type Result<T> = std::result::Result<T, Error>;
34fn invalid(message: &str) -> Error {
35 Error::new("INVALID_MESSAGE", message)
36}
37fn limit(message: &str) -> Error {
38 Error::new("LIMIT_EXCEEDED", message)
39}
40
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct PatchRow {
43 pub doc_id: String,
44 pub sid: u64,
45 pub clock: u64,
46 pub span: u64,
47 pub dependencies: VersionVector,
48 pub operations: Vec<u8>,
49}
50impl PatchRow {
51 pub fn end(&self) -> u64 {
52 self.clock.saturating_add(self.span)
53 }
54 fn validate(&self, doc_id: &str) -> Result<()> {
55 validate_vector(&self.dependencies)?;
56 if self.doc_id != doc_id
57 || self.sid < 65536
58 || self.sid > MAX_SAFE_INTEGER
59 || self.clock == 0
60 || self.span == 0
61 || self.end() > MAX_SAFE_INTEGER
62 || self.operations.is_empty()
63 || own_clock(&self.dependencies, self.sid) > self.clock
64 {
65 return Err(invalid("Invalid patch segment"));
66 }
67 if self.operations.len() > MAX_PATCH_BYTES {
68 return Err(limit("Patch exceeds 1 MiB"));
69 }
70 Ok(())
71 }
72}
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub enum Body {
75 Connect {
76 vv: VersionVector,
77 },
78 Sync {
79 found: bool,
80 complete: bool,
81 vv: VersionVector,
82 rows: Vec<PatchRow>,
83 },
84 SyncBack {
85 vv: VersionVector,
86 rows: Vec<PatchRow>,
87 },
88 Update {
89 vv: VersionVector,
90 rows: Vec<PatchRow>,
91 },
92 Ack {
93 vv: VersionVector,
94 },
95 Error {
96 code: String,
97 message: String,
98 },
99}
100#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct Message {
102 pub doc_id: String,
103 pub request_id: u64,
104 pub body: Body,
105}
106impl Message {
107 fn validate(&self) -> Result<()> {
108 if self.doc_id.is_empty()
109 || self.doc_id.contains('\0')
110 || self.doc_id.encode_utf16().count() > 1024
111 || self.request_id > MAX_SAFE_INTEGER
112 {
113 return Err(invalid("Invalid message header"));
114 }
115 match &self.body {
116 Body::Connect { vv } | Body::Ack { vv } => validate_vector(vv)?,
117 Body::Sync { vv, rows, .. }
118 | Body::SyncBack { vv, rows }
119 | Body::Update { vv, rows } => {
120 validate_vector(vv)?;
121 if rows.len() > MAX_MESSAGE_ROWS {
122 return Err(limit("Too many rows"));
123 }
124 for row in rows {
125 row.validate(&self.doc_id)?;
126 }
127 }
128 Body::Error { .. } => {}
129 }
130 let nodes = match &self.body {
131 Body::Connect { vv } | Body::Ack { vv } => 8 + 3 * vv.len(),
132 Body::Sync { vv, rows, .. } => {
133 11 + 3 * vv.len() + rows.iter().map(row_nodes).sum::<usize>()
134 }
135 Body::SyncBack { vv, rows } | Body::Update { vv, rows } => {
136 9 + 3 * vv.len() + rows.iter().map(row_nodes).sum::<usize>()
137 }
138 Body::Error { .. } => 9,
139 };
140 if nodes > MAX_SCHEMA_NODES {
141 return Err(limit("Structure limit exceeded"));
142 }
143 Ok(())
144 }
145}
146fn own_clock(vv: &VersionVector, sid: u64) -> u64 {
147 vv.iter()
148 .find(|(id, _)| *id == sid)
149 .map(|(_, clock)| *clock)
150 .unwrap_or(0)
151}
152pub fn validate_vector(vv: &VersionVector) -> Result<()> {
153 if vv.len() > MAX_VECTOR_ENTRIES {
154 return Err(invalid("Too many actors"));
155 }
156 let mut previous = None;
157 for &(sid, clock) in vv {
158 if sid > MAX_SAFE_INTEGER
159 || clock == 0
160 || clock > MAX_SAFE_INTEGER
161 || previous.is_some_and(|id| sid <= id)
162 {
163 return Err(invalid(
164 "Vector must have unique sorted actors and positive clocks",
165 ));
166 }
167 previous = Some(sid);
168 }
169 Ok(())
170}
171fn covers(have: &BTreeMap<u64, u64>, required: &VersionVector) -> bool {
172 required
173 .iter()
174 .all(|(sid, clock)| have.get(sid).copied().unwrap_or(0) >= *clock)
175}
176
177struct Writer(Vec<u8>);
178impl Writer {
179 fn uint(&mut self, mut value: u64) {
180 while value >= 128 {
181 self.0.push((value as u8 & 127) | 128);
182 value >>= 7;
183 }
184 self.0.push(value as u8);
185 }
186 fn bytes(&mut self, value: &[u8]) {
187 self.uint(value.len() as u64);
188 self.0.extend_from_slice(value);
189 }
190 fn text(&mut self, value: &str) {
191 self.bytes(value.as_bytes());
192 }
193 fn vector(&mut self, vv: &VersionVector) {
194 self.uint(vv.len() as u64);
195 for (sid, clock) in vv {
196 self.uint(*sid);
197 self.uint(*clock);
198 }
199 }
200 fn rows(&mut self, rows: &[PatchRow]) {
201 self.uint(rows.len() as u64);
202 for row in rows {
203 self.text(&row.doc_id);
204 self.uint(row.sid);
205 self.uint(row.clock);
206 self.uint(row.span);
207 self.vector(&row.dependencies);
208 self.bytes(&row.operations);
209 }
210 }
211}
212struct Reader<'a> {
213 bytes: &'a [u8],
214 pos: usize,
215}
216impl<'a> Reader<'a> {
217 fn byte(&mut self) -> Result<u8> {
218 let b = self
219 .bytes
220 .get(self.pos)
221 .copied()
222 .ok_or_else(|| invalid("Truncated frame"))?;
223 self.pos += 1;
224 Ok(b)
225 }
226 fn uint(&mut self) -> Result<u64> {
227 let mut result = 0_u64;
228 for i in 0..8 {
229 let b = self.byte()?;
230 result |= u64::from(b & 127) << (7 * i);
231 if result > MAX_SAFE_INTEGER {
232 return Err(invalid("Integer overflow"));
233 }
234 if b < 128 {
235 if i > 0 && b == 0 {
236 return Err(invalid("Non-canonical varint"));
237 }
238 return Ok(result);
239 }
240 }
241 Err(invalid("Integer overflow"))
242 }
243 fn count(&mut self, max: usize) -> Result<usize> {
244 let n = self.uint()?;
245 if n > max as u64 {
246 return Err(limit("Collection limit exceeded"));
247 }
248 Ok(n as usize)
249 }
250 fn bytes(&mut self, max: usize) -> Result<Vec<u8>> {
251 let n = self.count(max)?;
252 let end = self
253 .pos
254 .checked_add(n)
255 .ok_or_else(|| invalid("Length overflow"))?;
256 let result = self
257 .bytes
258 .get(self.pos..end)
259 .ok_or_else(|| invalid("Truncated bytes"))?
260 .to_vec();
261 self.pos = end;
262 Ok(result)
263 }
264 fn text(&mut self) -> Result<String> {
265 String::from_utf8(self.bytes(MAX_FRAME_BYTES)?).map_err(|_| invalid("Invalid UTF-8"))
266 }
267 fn boolean(&mut self) -> Result<bool> {
268 match self.byte()? {
269 0 => Ok(false),
270 1 => Ok(true),
271 _ => Err(invalid("Invalid boolean")),
272 }
273 }
274 fn vector(&mut self) -> Result<VersionVector> {
275 let n = self.count(MAX_VECTOR_ENTRIES)?;
276 let mut result = Vec::with_capacity(n);
277 for _ in 0..n {
278 result.push((self.uint()?, self.uint()?));
279 }
280 validate_vector(&result)?;
281 Ok(result)
282 }
283 fn rows(&mut self) -> Result<Vec<PatchRow>> {
284 let n = self.count(MAX_MESSAGE_ROWS)?;
285 let mut result = Vec::with_capacity(n);
286 for _ in 0..n {
287 result.push(PatchRow {
288 doc_id: self.text()?,
289 sid: self.uint()?,
290 clock: self.uint()?,
291 span: self.uint()?,
292 dependencies: self.vector()?,
293 operations: self.bytes(MAX_PATCH_BYTES)?,
294 });
295 }
296 Ok(result)
297 }
298}
299fn uint_size(mut n: u64) -> usize {
302 let mut size = 1;
303 while n >= 128 {
304 size += 1;
305 n >>= 7;
306 }
307 size
308}
309impl Reader<'_> {
310 fn run_rows(&mut self, doc_id: &str, vv_len: usize) -> Result<Vec<PatchRow>> {
311 let sid = self.uint()?;
312 let clock = self.uint()?;
313 let count = self.count(MAX_MESSAGE_ROWS)?;
314 let lamport = self.uint()?;
315 if sid < 65536
316 || clock == 0
317 || lamport == 0
318 || count < 2
319 || clock + count as u64 > MAX_SAFE_INTEGER
320 || lamport + count as u64 > MAX_SAFE_INTEGER
321 {
322 return Err(invalid("Invalid run range"));
323 }
324 let schema = self.text()?;
325 let target = self.text()?;
326 let tag = self.uint()?;
327 if tag > 1 {
328 return Err(invalid("Invalid run field"));
329 }
330 let field_text = if tag == 0 { Some(self.text()?) } else { None };
331 let field_number = if tag == 1 { self.uint()? } else { 0 };
332 let layout = self.uint()?;
333 let external = self.vector()?;
334 if external.iter().any(|(actor, _)| *actor == sid)
335 || external.len() + 1 > MAX_VECTOR_ENTRIES
336 {
337 return Err(invalid("Invalid run dependencies"));
338 }
339 if 16 + vv_len * 3 + count * (7 + 3 * (external.len() + 1)) > MAX_SCHEMA_NODES {
340 return Err(limit("Expanded run node limit"));
341 }
342 let mut prefix = Writer(Vec::new());
343 prefix.text(&schema);
344 prefix.uint(1);
345 prefix.uint(1);
346 prefix.text(&target);
347 prefix.uint(tag);
348 if let Some(field) = field_text {
349 prefix.text(&field);
350 } else {
351 prefix.uint(field_number);
352 }
353 prefix.uint(layout);
354 let mut values = Vec::with_capacity(count);
355 let mut expanded = self.bytes.len();
356 for i in 0..count {
357 let value = self.bytes(MAX_PATCH_BYTES)?;
358 let op_bytes = 1
359 + uint_size(lamport + i as u64)
360 + prefix.0.len()
361 + uint_size(value.len() as u64)
362 + value.len()
363 + 2;
364 if op_bytes > MAX_PATCH_BYTES {
365 return Err(limit("Expanded run payload limit"));
366 }
367 expanded += op_bytes
368 + (external.len() + usize::from(clock + i as u64 > 1)) * 16
369 + doc_id.encode_utf16().count() * 2
370 + 40;
371 if expanded > 64 * 1024 * 1024 {
372 return Err(limit("Expanded run byte limit"));
373 }
374 values.push(value);
375 }
376 let mut rows = Vec::with_capacity(count);
377 for (i, value) in values.into_iter().enumerate() {
378 let mut operations = Writer(vec![3]);
379 operations.uint(lamport + i as u64);
380 operations.0.extend_from_slice(&prefix.0);
381 operations.bytes(&value);
382 operations.uint(0);
383 operations.uint(0);
384 let mut dependencies = external.clone();
385 if clock + i as u64 > 1 {
386 let at = dependencies.partition_point(|(actor, _)| *actor < sid);
387 dependencies.insert(at, (sid, clock + i as u64));
388 }
389 rows.push(PatchRow {
390 doc_id: doc_id.to_owned(),
391 sid,
392 clock: clock + i as u64,
393 span: 1,
394 dependencies,
395 operations: operations.0,
396 });
397 }
398 Ok(rows)
399 }
400}
401
402pub fn encode(message: &Message) -> Result<Vec<u8>> {
403 message.validate()?;
404 let mut writer = Writer(vec![1, 3]);
405 writer.uint(match message.body {
406 Body::Connect { .. } => 1,
407 Body::Sync { .. } => 2,
408 Body::SyncBack { .. } => 3,
409 Body::Update { .. } => 4,
410 Body::Ack { .. } => 5,
411 Body::Error { .. } => 6,
412 });
413 writer.text(&message.doc_id);
414 writer.uint(message.request_id);
415 match &message.body {
416 Body::Connect { vv } | Body::Ack { vv } => writer.vector(vv),
417 Body::Sync {
418 found,
419 complete,
420 vv,
421 rows,
422 } => {
423 writer.0.push(*found as u8);
424 writer.0.push(*complete as u8);
425 writer.vector(vv);
426 writer.rows(rows);
427 }
428 Body::SyncBack { vv, rows } | Body::Update { vv, rows } => {
429 writer.vector(vv);
430 writer.rows(rows);
431 }
432 Body::Error { code, message } => {
433 writer.text(code);
434 writer.text(message);
435 }
436 }
437 if writer.0.len() > MAX_FRAME_BYTES {
438 return Err(limit("Frame exceeds 8 MiB"));
439 }
440 Ok(writer.0)
441}
442pub fn decode(bytes: &[u8]) -> Result<Message> {
443 if bytes.len() > MAX_FRAME_BYTES {
444 return Err(limit("Frame exceeds 8 MiB"));
445 }
446 let mut reader = Reader { bytes, pos: 0 };
447 let protocol = reader.uint()?;
448 let operations = reader.uint()?;
449 if !((protocol == 1 || protocol == 2) && operations == 3) {
450 return Err(Error::new(
451 "UNSUPPORTED_VERSION",
452 "Unsupported protocol or operation version",
453 ));
454 }
455 let kind = reader.uint()?;
456 if !(1..=6).contains(&kind) {
457 return Err(invalid("Unknown message kind"));
458 }
459 let doc_id = reader.text()?;
460 let request_id = reader.uint()?;
461 if protocol == 2 && !(2..=4).contains(&kind) {
462 return Err(invalid("Invalid run message kind"));
463 }
464 let body = match kind {
465 1 => Body::Connect {
466 vv: reader.vector()?,
467 },
468 2 => {
469 let found = reader.boolean()?;
470 let complete = reader.boolean()?;
471 let vv = reader.vector()?;
472 let rows = if protocol == 2 {
473 reader.run_rows(&doc_id, vv.len())?
474 } else {
475 reader.rows()?
476 };
477 Body::Sync {
478 found,
479 complete,
480 vv,
481 rows,
482 }
483 }
484 3 | 4 => {
485 let vv = reader.vector()?;
486 let rows = if protocol == 2 {
487 reader.run_rows(&doc_id, vv.len())?
488 } else {
489 reader.rows()?
490 };
491 if kind == 3 {
492 Body::SyncBack { vv, rows }
493 } else {
494 Body::Update { vv, rows }
495 }
496 }
497 5 => Body::Ack {
498 vv: reader.vector()?,
499 },
500 6 => Body::Error {
501 code: reader.text()?,
502 message: reader.text()?,
503 },
504 _ => unreachable!(),
505 };
506 if reader.pos != bytes.len() {
507 return Err(invalid("Trailing bytes"));
508 }
509 let message = Message {
510 doc_id,
511 request_id,
512 body,
513 };
514 message.validate()?;
515 Ok(message)
516}
517
518#[derive(Clone, Debug)]
520pub struct PatchLog {
521 pub doc_id: String,
522 rows: BTreeMap<(u64, u64), PatchRow>,
523 pending: BTreeSet<(u64, u64)>,
524 frontier: BTreeMap<u64, u64>,
525 bytes: usize,
526}
527impl PatchLog {
528 pub fn new(doc_id: &str) -> Self {
529 Self {
530 doc_id: doc_id.into(),
531 rows: BTreeMap::new(),
532 pending: BTreeSet::new(),
533 frontier: BTreeMap::new(),
534 bytes: 0,
535 }
536 }
537 pub fn vector(&self) -> VersionVector {
538 self.frontier
539 .iter()
540 .map(|(sid, clock)| (*sid, *clock))
541 .collect()
542 }
543 pub fn pending_count(&self) -> usize {
544 self.pending.len()
545 }
546 pub fn missing(&self, vv: &VersionVector) -> Vec<PatchRow> {
547 self.rows
548 .values()
549 .filter(|row| row.end() > own_clock(vv, row.sid))
550 .cloned()
551 .collect()
552 }
553 pub fn append(&mut self, rows: &[PatchRow]) -> Result<()> {
554 let mut next = self.clone();
555 for row in rows {
556 row.validate(&self.doc_id)?;
557 let key = (row.sid, row.clock);
558 if let Some(existing) = next.rows.get(&key) {
559 if existing != row {
560 return Err(Error::new("CONFLICT", "Conflicting segment"));
561 }
562 continue;
563 }
564 for other in next.rows.values().filter(|other| other.sid == row.sid) {
565 if row.clock < other.end() && other.clock < row.end() {
566 return Err(Error::new("CONFLICT", "Overlapping segments"));
567 }
568 let (previous, after) = if row.clock > other.clock {
569 (other, row)
570 } else {
571 (row, other)
572 };
573 if own_clock(&after.dependencies, row.sid) < previous.end() {
574 return Err(Error::new("CONFLICT", "Actor history fork"));
575 }
576 }
577 next.bytes += row.operations.len()
578 + row.dependencies.len() * 16
579 + row.doc_id.encode_utf16().count() * 2
580 + 40;
581 if next.rows.len() >= 100_000 || next.bytes > 64 * 1024 * 1024 {
582 return Err(limit("Document history limit exceeded"));
583 }
584 next.rows.insert(key, row.clone());
585 next.pending.insert(key);
586 }
587 loop {
588 let ready: Vec<_> = next
589 .pending
590 .iter()
591 .filter(|key| {
592 let row = &next.rows[key];
593 covers(&next.frontier, &row.dependencies)
594 && row.clock == next.frontier.get(&row.sid).copied().unwrap_or(1)
595 })
596 .copied()
597 .collect();
598 if ready.is_empty() {
599 break;
600 }
601 for key in ready {
602 let row = &next.rows[&key];
603 next.frontier
604 .entry(row.sid)
605 .and_modify(|clock| *clock = (*clock).max(row.end()))
606 .or_insert(row.end());
607 next.pending.remove(&key);
608 }
609 }
610 if next.frontier.len() > MAX_VECTOR_ENTRIES {
611 return Err(limit("Too many actors"));
612 }
613 *self = next;
614 Ok(())
615 }
616}
617
618fn row_nodes(row: &PatchRow) -> usize {
619 7 + 3 * row.dependencies.len()
620}
621
622fn chunk_rows(rows: Vec<PatchRow>) -> Vec<Vec<PatchRow>> {
623 let mut chunks = Vec::new();
624 let mut chunk = Vec::new();
625 let mut bytes = 0;
626 let mut nodes = 0;
627 for row in rows {
628 let size = row.operations.len()
629 + row.dependencies.len() * 16
630 + row.doc_id.encode_utf16().count() * 4
631 + 64;
632 let cost = row_nodes(&row);
633 if !chunk.is_empty()
634 && (bytes + size > 2 * MAX_PATCH_BYTES
635 || chunk.len() >= MAX_MESSAGE_ROWS
636 || nodes + cost > MAX_ROW_BATCH_NODES)
637 {
638 chunks.push(std::mem::take(&mut chunk));
639 bytes = 0;
640 nodes = 0;
641 }
642 bytes += size;
643 nodes += cost;
644 chunk.push(row);
645 }
646 if !chunk.is_empty() || chunks.is_empty() {
647 chunks.push(chunk);
648 }
649 chunks
650}
651
652#[derive(Default)]
654pub struct Relay {
655 documents: BTreeMap<String, PatchLog>,
656}
657impl Relay {
658 pub fn receive(&mut self, message: Message) -> Result<Vec<Message>> {
659 message.validate()?;
660 let Message {
661 doc_id,
662 request_id,
663 body,
664 } = message;
665 let responses = match body {
666 Body::Connect { vv } => {
667 let log = self.documents.get(&doc_id);
668 let rows = log.map(|log| log.missing(&vv)).unwrap_or_default();
669 let vector = log.map(PatchLog::vector).unwrap_or_default();
670 let chunks = chunk_rows(rows);
671 let last = chunks.len() - 1;
672 chunks
673 .into_iter()
674 .enumerate()
675 .map(|(i, rows)| Message {
676 doc_id: doc_id.clone(),
677 request_id,
678 body: Body::Sync {
679 found: log.is_some(),
680 complete: i == last,
681 vv: vector.clone(),
682 rows,
683 },
684 })
685 .collect()
686 }
687 Body::SyncBack { rows, .. } | Body::Update { rows, .. } => {
688 let log = self
689 .documents
690 .entry(doc_id.clone())
691 .or_insert_with(|| PatchLog::new(&doc_id));
692 match log.append(&rows) {
693 Ok(()) => vec![Message {
694 doc_id,
695 request_id,
696 body: Body::Ack { vv: log.vector() },
697 }],
698 Err(error) => vec![Message {
699 doc_id,
700 request_id,
701 body: Body::Error {
702 code: error.code.into(),
703 message: error.message,
704 },
705 }],
706 }
707 }
708 _ => return Err(invalid("Expected connect or patch upload")),
709 };
710 Ok(responses)
711 }
712}
713
714#[cfg(test)]
715mod tests {
716 use super::*;
717 #[test]
718 fn dense_vectors_are_chunked_within_the_shared_structure_budget() {
719 let vv: VersionVector = (0..1024).map(|i| (65536 + i, 1)).collect();
720 let rows: Vec<_> = (0..127)
721 .map(|i| PatchRow {
722 doc_id: "dense".into(),
723 sid: 200_000 + i,
724 clock: 1,
725 span: 1,
726 dependencies: vv.clone(),
727 operations: vec![1],
728 })
729 .collect();
730 let message = Message {
731 doc_id: "dense".into(),
732 request_id: 1,
733 body: Body::Update {
734 vv: vv.clone(),
735 rows: rows.clone(),
736 },
737 };
738 assert!(encode(&message).is_err());
739 let mut unchecked = Writer(vec![1, 3, 4]);
740 unchecked.text("dense");
741 unchecked.uint(1);
742 unchecked.vector(&vv);
743 unchecked.rows(&rows);
744 assert!(decode(&unchecked.0).is_err());
745 let chunks = chunk_rows(rows);
746 assert_eq!(chunks.len(), 2);
747 for rows in chunks {
748 let message = Message {
749 doc_id: "dense".into(),
750 request_id: 1,
751 body: Body::Sync {
752 found: true,
753 complete: true,
754 vv: vv.clone(),
755 rows,
756 },
757 };
758 assert_eq!(decode(&encode(&message).unwrap()).unwrap(), message);
759 }
760 }
761 #[test]
762 fn shared_binary_fixtures() {
763 let fixtures: serde_json::Value =
764 serde_json::from_str(include_str!("../../../fixtures/protocol.json")).unwrap();
765 for fixture in fixtures["messages"].as_array().unwrap() {
766 let bytes: Vec<u8> = fixture["bytes"]
767 .as_array()
768 .unwrap()
769 .iter()
770 .map(|b| b.as_u64().unwrap() as u8)
771 .collect();
772 let message = decode(&bytes).unwrap();
773 assert_eq!(encode(&message).unwrap(), bytes, "{}", fixture["name"]);
774 for i in 0..bytes.len() {
775 assert!(decode(&bytes[..i]).is_err());
776 }
777 let mut trailing = bytes.clone();
778 trailing.push(0);
779 assert!(decode(&trailing).is_err());
780 }
781 }
782 #[test]
783 fn malformed_values() {
784 assert!(decode(&[1, 3, 99]).is_err());
785 assert!(decode(&[2, 1]).is_err());
786 assert!(decode(&[3, 3, 4]).is_err());
788 assert!(decode(&[1, 3, 1, 128, 0]).is_err());
789 assert!(validate_vector(&vec![(65536, 1), (65536, 2)]).is_err());
790 assert!(validate_vector(&vec![(65536, MAX_SAFE_INTEGER + 1)]).is_err());
791 let mut seed = 42_u32;
792 for n in 0..1000 {
793 let mut bytes = vec![1, 3];
794 for _ in 0..n % 64 {
795 seed = seed.wrapping_mul(1664525).wrapping_add(1013904223);
796 bytes.push(seed as u8);
797 }
798 let _ = decode(&bytes);
799 }
800 }
801 #[test]
802 fn gaps_duplicates_and_conflicts() {
803 let first = PatchRow {
804 doc_id: "test".into(),
805 sid: 65536,
806 clock: 1,
807 span: 2,
808 dependencies: vec![],
809 operations: vec![1],
810 };
811 let second = PatchRow {
812 clock: 3,
813 dependencies: vec![(65536, 3)],
814 ..first.clone()
815 };
816 let mut log = PatchLog::new("test");
817 log.append(&[second.clone()]).unwrap();
818 assert_eq!(log.vector(), vec![]);
819 log.append(&[first.clone()]).unwrap();
820 assert_eq!(log.vector(), vec![(65536, 5)]);
821 assert_eq!(log.pending_count(), 0);
822 log.append(&[first.clone(), second]).unwrap();
823 assert!(log
824 .append(&[PatchRow {
825 operations: vec![2],
826 ..first.clone()
827 }])
828 .is_err());
829 assert!(log.append(&[PatchRow { clock: 2, ..first }]).is_err());
830 assert!(log.missing(&log.vector()).is_empty());
831 }
832 #[test]
833 fn actor_frontier_does_not_skip_an_undeclared_gap() {
834 let mut log = PatchLog::new("gap");
835 log.append(&[PatchRow {
836 doc_id: "gap".into(),
837 sid: 65536,
838 clock: 10,
839 span: 1,
840 dependencies: vec![],
841 operations: vec![1],
842 }])
843 .unwrap();
844 assert!(log.vector().is_empty());
845 assert_eq!(log.pending_count(), 1);
846 assert!(encode(&Message {
847 doc_id: "bad\0id".into(),
848 request_id: 1,
849 body: Body::Connect { vv: vec![] }
850 })
851 .is_err());
852 }
853}