1#![no_std]
20#![deny(unsafe_code)]
21
22extern crate alloc;
23#[cfg(all(feature = "local-writer", target_os = "linux"))]
24extern crate std;
25
26#[cfg(all(feature = "local-writer", target_os = "linux"))]
27pub mod local;
28pub mod ownership;
29use alloc::collections::{BTreeMap, BTreeSet};
30use alloc::string::String;
31use alloc::vec;
32use alloc::vec::Vec;
33
34pub trait Mergeable {
40 fn merge(&mut self, other: &Self);
41}
42
43pub trait Crdt: Mergeable {
45 type Delta;
46
47 fn replica_count(&self) -> Option<usize> {
49 None
50 }
51
52 fn validate_record(&self, _id: RecordId, _delta: &Self::Delta) -> Result<(), WireError> {
54 Ok(())
55 }
56
57 fn apply_delta(&mut self, delta: Self::Delta);
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68pub enum MergeError {
69 ReplicaCountMismatch { own: usize, other: usize },
71}
72
73impl core::fmt::Display for MergeError {
74 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
75 match self {
76 MergeError::ReplicaCountMismatch { own, other } => write!(
77 f,
78 "replica-count mismatch: own={own}, other={other} (fixed replica set violated)"
79 ),
80 }
81 }
82}
83
84impl core::error::Error for MergeError {}
85
86#[derive(Clone, Debug, PartialEq, Eq)]
88pub struct GCounterDelta {
89 pub replica: usize,
90 pub tally: u64,
91}
92
93#[derive(Clone, Copy, Debug, PartialEq, Eq)]
95pub enum CoordinateError {
96 ReplicaOutOfRange {
98 replica: usize,
99 replica_count: usize,
100 },
101}
102
103#[derive(Clone, Debug, PartialEq, Eq)]
111pub struct GCounter {
112 counts: Vec<u64>,
113}
114
115impl GCounter {
116 pub fn new(n: usize) -> Self {
118 GCounter { counts: vec![0; n] }
119 }
120
121 pub fn len(&self) -> usize {
123 self.counts.len()
124 }
125
126 pub fn is_empty(&self) -> bool {
127 self.counts.is_empty()
128 }
129
130 pub fn apply_bump(&mut self, replica: usize, tally: u64) {
139 if let Some(c) = self.counts.get_mut(replica) {
140 if tally > *c {
141 *c = tally;
142 }
143 }
144 }
145
146 pub fn try_apply_bump(&mut self, replica: usize, tally: u64) -> Result<(), CoordinateError> {
152 if replica >= self.counts.len() {
153 return Err(CoordinateError::ReplicaOutOfRange {
154 replica,
155 replica_count: self.counts.len(),
156 });
157 }
158 self.apply_bump(replica, tally);
159 Ok(())
160 }
161
162 pub fn try_merge(&mut self, other: &GCounter) -> Result<(), MergeError> {
167 if self.counts.len() != other.counts.len() {
168 return Err(MergeError::ReplicaCountMismatch {
169 own: self.counts.len(),
170 other: other.counts.len(),
171 });
172 }
173 for (c, o) in self.counts.iter_mut().zip(other.counts.iter()) {
174 if *o > *c {
175 *c = *o;
176 }
177 }
178 Ok(())
179 }
180
181 pub fn merge(&mut self, other: &GCounter) {
189 self.try_merge(other).expect(
190 "GCounter::merge requires equal replica counts; use try_merge for untrusted input",
191 );
192 }
193
194 pub fn state(&self) -> &[u64] {
196 &self.counts
197 }
198
199 pub fn value(&self) -> u64 {
201 self.counts.iter().sum()
202 }
203}
204
205impl Mergeable for GCounter {
206 fn merge(&mut self, other: &Self) {
207 GCounter::merge(self, other);
208 }
209}
210
211impl Crdt for GCounter {
212 type Delta = GCounterDelta;
213
214 fn validate_record(&self, id: RecordId, delta: &Self::Delta) -> Result<(), WireError> {
215 ownership::check_counter_record(self.len(), id, delta)
216 .map_err(|_| WireError::OwnershipViolation)
217 }
218
219 fn replica_count(&self) -> Option<usize> {
220 Some(self.len())
221 }
222
223 fn apply_delta(&mut self, delta: Self::Delta) {
224 self.apply_bump(delta.replica, delta.tally);
225 }
226}
227
228#[derive(Clone, Debug, PartialEq, Eq)]
232pub struct GSet<T: Ord> {
233 elements: BTreeSet<T>,
234}
235
236impl<T: Ord> GSet<T> {
237 pub fn new() -> Self {
238 GSet {
239 elements: BTreeSet::new(),
240 }
241 }
242
243 pub fn insert(&mut self, element: T) {
244 self.elements.insert(element);
245 }
246
247 pub fn merge(&mut self, other: &Self)
248 where
249 T: Clone,
250 {
251 self.elements.extend(other.elements.iter().cloned());
252 }
253
254 pub fn contains(&self, element: &T) -> bool {
255 self.elements.contains(element)
256 }
257
258 pub fn elements(&self) -> &BTreeSet<T> {
259 &self.elements
260 }
261}
262
263impl<T: Ord> Default for GSet<T> {
264 fn default() -> Self {
265 Self::new()
266 }
267}
268
269impl<T: Ord + Clone> Mergeable for GSet<T> {
270 fn merge(&mut self, other: &Self) {
271 GSet::merge(self, other);
272 }
273}
274
275impl<T: Ord + Clone> Crdt for GSet<T> {
276 type Delta = T;
277
278 fn apply_delta(&mut self, delta: Self::Delta) {
279 self.insert(delta);
280 }
281}
282
283#[derive(Clone, Debug, PartialEq, Eq)]
292pub struct PnCounter {
293 p: GCounter,
294 n: GCounter,
295}
296
297#[derive(Clone, Debug, PartialEq, Eq)]
298pub enum PnCounterDelta {
299 Inc { replica: usize, tally: u64 },
300 Dec { replica: usize, tally: u64 },
301}
302
303impl PnCounter {
304 pub fn new(n: usize) -> Self {
306 PnCounter {
307 p: GCounter::new(n),
308 n: GCounter::new(n),
309 }
310 }
311
312 pub fn apply_inc(&mut self, replica: usize, tally: u64) {
316 self.p.apply_bump(replica, tally);
317 }
318
319 pub fn try_apply_inc(&mut self, replica: usize, tally: u64) -> Result<(), CoordinateError> {
325 self.p.try_apply_bump(replica, tally)
326 }
327
328 pub fn apply_dec(&mut self, replica: usize, tally: u64) {
331 self.n.apply_bump(replica, tally);
332 }
333
334 pub fn try_apply_dec(&mut self, replica: usize, tally: u64) -> Result<(), CoordinateError> {
340 self.n.try_apply_bump(replica, tally)
341 }
342
343 pub fn try_merge(&mut self, other: &PnCounter) -> Result<(), MergeError> {
348 if self.p.state().len() != other.p.state().len() {
349 return Err(MergeError::ReplicaCountMismatch {
350 own: self.p.state().len(),
351 other: other.p.state().len(),
352 });
353 }
354 if self.n.state().len() != other.n.state().len() {
355 return Err(MergeError::ReplicaCountMismatch {
356 own: self.n.state().len(),
357 other: other.n.state().len(),
358 });
359 }
360 self.p.try_merge(&other.p)?;
361 self.n.try_merge(&other.n)?;
362 Ok(())
363 }
364
365 pub fn merge(&mut self, other: &PnCounter) {
371 self.try_merge(other).expect(
372 "PnCounter::merge requires equal replica counts; use try_merge for untrusted input",
373 );
374 }
375
376 pub fn p_state(&self) -> &[u64] {
378 self.p.state()
379 }
380
381 pub fn n_state(&self) -> &[u64] {
383 self.n.state()
384 }
385
386 pub fn value(&self) -> i64 {
389 self.p.value() as i64 - self.n.value() as i64
390 }
391}
392
393impl Mergeable for PnCounter {
394 fn merge(&mut self, other: &Self) {
395 PnCounter::merge(self, other);
396 }
397}
398
399impl Crdt for PnCounter {
400 type Delta = PnCounterDelta;
401
402 fn replica_count(&self) -> Option<usize> {
403 Some(self.p.len())
404 }
405
406 fn apply_delta(&mut self, delta: Self::Delta) {
407 match delta {
408 PnCounterDelta::Inc { replica, tally } => self.apply_inc(replica, tally),
409 PnCounterDelta::Dec { replica, tally } => self.apply_dec(replica, tally),
410 }
411 }
412}
413
414#[derive(Clone, Debug, PartialEq, Eq)]
416pub enum OrSetDelta<T, K> {
417 Add { element: T, token: K },
418 Remove { tokens: Vec<K> },
419}
420
421#[derive(Clone, Debug, PartialEq, Eq)]
425pub struct OrSet<T: Ord, K: Ord> {
426 adds: BTreeSet<(T, K)>,
427 tombstones: BTreeSet<K>,
428}
429
430impl<T: Ord, K: Ord> OrSet<T, K> {
431 pub fn new() -> Self {
432 OrSet {
433 adds: BTreeSet::new(),
434 tombstones: BTreeSet::new(),
435 }
436 }
437
438 pub fn add(&mut self, element: T, token: K) {
439 self.adds.insert((element, token));
440 }
441
442 pub fn apply_remove<I>(&mut self, tokens: I)
443 where
444 I: IntoIterator<Item = K>,
445 {
446 self.tombstones.extend(tokens);
447 }
448
449 pub fn merge(&mut self, other: &Self)
450 where
451 T: Clone,
452 K: Clone,
453 {
454 self.adds.extend(other.adds.iter().cloned());
455 self.tombstones.extend(other.tombstones.iter().cloned());
456 }
457
458 pub fn adds(&self) -> &BTreeSet<(T, K)> {
459 &self.adds
460 }
461
462 pub fn tombstones(&self) -> &BTreeSet<K> {
463 &self.tombstones
464 }
465}
466
467impl<T: Ord + Clone, K: Ord + Clone> OrSet<T, K> {
468 pub fn observed_tokens(&self, element: &T) -> BTreeSet<K> {
469 self.adds
470 .iter()
471 .filter_map(|(candidate, token)| {
472 if candidate == element {
473 Some(token.clone())
474 } else {
475 None
476 }
477 })
478 .collect()
479 }
480
481 pub fn contains(&self, element: &T) -> bool {
482 self.adds
483 .iter()
484 .any(|(candidate, token)| candidate == element && !self.tombstones.contains(token))
485 }
486
487 pub fn elements(&self) -> BTreeSet<T> {
488 self.adds
489 .iter()
490 .filter_map(|(element, token)| {
491 if self.tombstones.contains(token) {
492 None
493 } else {
494 Some(element.clone())
495 }
496 })
497 .collect()
498 }
499}
500
501impl<T: Ord, K: Ord> Default for OrSet<T, K> {
502 fn default() -> Self {
503 Self::new()
504 }
505}
506
507impl<T: Ord + Clone, K: Ord + Clone> Mergeable for OrSet<T, K> {
508 fn merge(&mut self, other: &Self) {
509 OrSet::merge(self, other);
510 }
511}
512
513impl<T: Ord + Clone, K: Ord + Clone> Crdt for OrSet<T, K> {
514 type Delta = OrSetDelta<T, K>;
515
516 fn apply_delta(&mut self, delta: Self::Delta) {
517 match delta {
518 OrSetDelta::Add { element, token } => self.add(element, token),
519 OrSetDelta::Remove { tokens } => self.apply_remove(tokens),
520 }
521 }
522}
523
524#[derive(Clone, Debug, PartialEq, Eq)]
526pub enum RgaDelta<P, V> {
527 Insert { position: P, value: V },
528 Delete { position: P },
529}
530
531#[derive(Clone, Debug, PartialEq, Eq)]
537pub struct Rga<P: Ord, V: Ord> {
538 placed: BTreeSet<(P, V)>,
539 tombstones: BTreeSet<P>,
540}
541
542impl<P: Ord, V: Ord> Rga<P, V> {
543 pub fn new() -> Self {
544 Rga {
545 placed: BTreeSet::new(),
546 tombstones: BTreeSet::new(),
547 }
548 }
549
550 pub fn insert(&mut self, position: P, value: V) {
551 self.placed.insert((position, value));
552 }
553
554 pub fn delete(&mut self, position: P) {
555 self.tombstones.insert(position);
556 }
557
558 pub fn merge(&mut self, other: &Self)
559 where
560 P: Clone,
561 V: Clone,
562 {
563 self.placed.extend(other.placed.iter().cloned());
564 self.tombstones.extend(other.tombstones.iter().cloned());
565 }
566
567 pub fn placed(&self) -> &BTreeSet<(P, V)> {
568 &self.placed
569 }
570
571 pub fn tombstones(&self) -> &BTreeSet<P> {
572 &self.tombstones
573 }
574}
575
576impl<P: Ord + Clone, V: Ord + Clone> Rga<P, V> {
577 pub fn live_entries(&self) -> Vec<(P, V)> {
578 self.placed
579 .iter()
580 .filter_map(|(position, value)| {
581 if self.tombstones.contains(position) {
582 None
583 } else {
584 Some((position.clone(), value.clone()))
585 }
586 })
587 .collect()
588 }
589
590 pub fn read_positions(&self) -> Vec<P> {
591 self.live_entries()
592 .into_iter()
593 .map(|(position, _)| position)
594 .collect::<BTreeSet<P>>()
595 .into_iter()
596 .collect()
597 }
598}
599
600impl<P: Ord, V: Ord> Default for Rga<P, V> {
601 fn default() -> Self {
602 Self::new()
603 }
604}
605
606impl<P: Ord + Clone, V: Ord + Clone> Mergeable for Rga<P, V> {
607 fn merge(&mut self, other: &Self) {
608 Rga::merge(self, other);
609 }
610}
611
612impl<P: Ord + Clone, V: Ord + Clone> Crdt for Rga<P, V> {
613 type Delta = RgaDelta<P, V>;
614
615 fn apply_delta(&mut self, delta: Self::Delta) {
616 match delta {
617 RgaDelta::Insert { position, value } => self.insert(position, value),
618 RgaDelta::Delete { position } => self.delete(position),
619 }
620 }
621}
622
623#[derive(Clone, Debug, PartialEq, Eq)]
625pub enum EnableWinsFlagDelta<K> {
626 Enable { token: K },
627 Disable { tokens: Vec<K> },
628}
629
630#[derive(Clone, Debug, PartialEq, Eq)]
636pub struct EnableWinsFlag<K: Ord> {
637 enables: BTreeSet<K>,
638 tombstones: BTreeSet<K>,
639}
640
641impl<K: Ord> EnableWinsFlag<K> {
642 pub fn new() -> Self {
643 EnableWinsFlag {
644 enables: BTreeSet::new(),
645 tombstones: BTreeSet::new(),
646 }
647 }
648
649 pub fn enable(&mut self, token: K) {
650 self.enables.insert(token);
651 }
652
653 pub fn disable<I>(&mut self, tokens: I)
654 where
655 I: IntoIterator<Item = K>,
656 {
657 self.tombstones.extend(tokens);
658 }
659
660 pub fn merge(&mut self, other: &Self)
661 where
662 K: Clone,
663 {
664 self.enables.extend(other.enables.iter().cloned());
665 self.tombstones.extend(other.tombstones.iter().cloned());
666 }
667
668 pub fn enables(&self) -> &BTreeSet<K> {
669 &self.enables
670 }
671
672 pub fn tombstones(&self) -> &BTreeSet<K> {
673 &self.tombstones
674 }
675}
676
677impl<K: Ord + Clone> EnableWinsFlag<K> {
678 pub fn observed_tokens(&self) -> BTreeSet<K> {
679 self.enables.iter().cloned().collect()
680 }
681
682 pub fn value(&self) -> bool {
683 self.enables
684 .iter()
685 .any(|token| !self.tombstones.contains(token))
686 }
687}
688
689impl<K: Ord> Default for EnableWinsFlag<K> {
690 fn default() -> Self {
691 Self::new()
692 }
693}
694
695impl<K: Ord + Clone> Mergeable for EnableWinsFlag<K> {
696 fn merge(&mut self, other: &Self) {
697 EnableWinsFlag::merge(self, other);
698 }
699}
700
701impl<K: Ord + Clone> Crdt for EnableWinsFlag<K> {
702 type Delta = EnableWinsFlagDelta<K>;
703
704 fn apply_delta(&mut self, delta: Self::Delta) {
705 match delta {
706 EnableWinsFlagDelta::Enable { token } => self.enable(token),
707 EnableWinsFlagDelta::Disable { tokens } => self.disable(tokens),
708 }
709 }
710}
711
712#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
714pub struct LwwDot {
715 pub timestamp: u64,
716 pub replica: u64,
717}
718
719#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
721pub struct LwwEntry<V: Ord> {
722 pub dot: LwwDot,
723 pub value: V,
724}
725
726#[derive(Clone, Debug, PartialEq, Eq)]
728pub struct LwwRegisterDelta<V: Ord> {
729 pub timestamp: u64,
730 pub replica: u64,
731 pub value: V,
732}
733
734#[derive(Clone, Debug, PartialEq, Eq)]
740pub struct LwwRegister<V: Ord> {
741 entry: Option<LwwEntry<V>>,
742}
743
744impl<V: Ord> LwwRegister<V> {
745 pub fn new() -> Self {
746 LwwRegister { entry: None }
747 }
748
749 pub fn set(&mut self, timestamp: u64, replica: u64, value: V) {
750 self.apply_entry(LwwEntry {
751 dot: LwwDot { timestamp, replica },
752 value,
753 });
754 }
755
756 pub fn entry(&self) -> Option<&LwwEntry<V>> {
757 self.entry.as_ref()
758 }
759
760 pub fn value(&self) -> Option<&V> {
761 self.entry.as_ref().map(|entry| &entry.value)
762 }
763
764 fn apply_entry(&mut self, entry: LwwEntry<V>) {
765 match &self.entry {
766 Some(current) if current >= &entry => {}
767 _ => self.entry = Some(entry),
768 }
769 }
770}
771
772impl<V: Ord> Default for LwwRegister<V> {
773 fn default() -> Self {
774 Self::new()
775 }
776}
777
778impl<V: Ord + Clone> LwwRegister<V> {
779 pub fn merge(&mut self, other: &Self) {
780 if let Some(entry) = other.entry.clone() {
781 self.apply_entry(entry);
782 }
783 }
784}
785
786impl<V: Ord + Clone> Mergeable for LwwRegister<V> {
787 fn merge(&mut self, other: &Self) {
788 LwwRegister::merge(self, other);
789 }
790}
791
792impl<V: Ord + Clone> Crdt for LwwRegister<V> {
793 type Delta = LwwRegisterDelta<V>;
794
795 fn apply_delta(&mut self, delta: Self::Delta) {
796 self.set(delta.timestamp, delta.replica, delta.value);
797 }
798}
799
800#[derive(Clone, Debug, PartialEq, Eq)]
802pub enum LwwMapDelta<K: Ord, V: Ord> {
803 Set {
804 key: K,
805 timestamp: u64,
806 replica: u64,
807 value: V,
808 },
809 Remove {
810 key: K,
811 timestamp: u64,
812 replica: u64,
813 },
814}
815
816#[derive(Clone, Debug, PartialEq, Eq)]
822pub struct LwwMap<K: Ord, V: Ord> {
823 entries: BTreeMap<K, LwwEntry<V>>,
824 removals: BTreeMap<K, LwwDot>,
825}
826
827impl<K: Ord, V: Ord> LwwMap<K, V> {
828 pub fn new() -> Self {
829 LwwMap {
830 entries: BTreeMap::new(),
831 removals: BTreeMap::new(),
832 }
833 }
834
835 pub fn set(&mut self, key: K, timestamp: u64, replica: u64, value: V) {
836 self.apply_entry(
837 key,
838 LwwEntry {
839 dot: LwwDot { timestamp, replica },
840 value,
841 },
842 );
843 }
844
845 pub fn remove(&mut self, key: K, timestamp: u64, replica: u64) {
846 self.apply_removal(key, LwwDot { timestamp, replica });
847 }
848
849 pub fn get(&self, key: &K) -> Option<&V> {
850 self.visible_entry(key).map(|entry| &entry.value)
851 }
852
853 pub fn visible_entry(&self, key: &K) -> Option<&LwwEntry<V>> {
854 let entry = self.entries.get(key)?;
855 match self.removals.get(key) {
856 Some(removal) if entry.dot <= *removal => None,
857 _ => Some(entry),
858 }
859 }
860
861 pub fn entries(&self) -> &BTreeMap<K, LwwEntry<V>> {
862 &self.entries
863 }
864
865 pub fn removals(&self) -> &BTreeMap<K, LwwDot> {
866 &self.removals
867 }
868
869 fn apply_entry(&mut self, key: K, entry: LwwEntry<V>) {
870 match self.entries.get(&key) {
871 Some(current) if current >= &entry => {}
872 _ => {
873 self.entries.insert(key, entry);
874 }
875 }
876 }
877
878 fn apply_removal(&mut self, key: K, dot: LwwDot) {
879 match self.removals.get(&key) {
880 Some(current) if *current >= dot => {}
881 _ => {
882 self.removals.insert(key, dot);
883 }
884 }
885 }
886}
887
888impl<K: Ord + Clone, V: Ord + Clone> LwwMap<K, V> {
889 pub fn merge(&mut self, other: &Self) {
890 for (key, entry) in other.entries.iter() {
891 self.apply_entry(key.clone(), entry.clone());
892 }
893 for (key, dot) in other.removals.iter() {
894 self.apply_removal(key.clone(), *dot);
895 }
896 }
897
898 pub fn value(&self) -> BTreeMap<K, V> {
899 self.entries
900 .iter()
901 .filter_map(|(key, entry)| {
902 if self.visible_entry(key).is_some() {
903 Some((key.clone(), entry.value.clone()))
904 } else {
905 None
906 }
907 })
908 .collect()
909 }
910}
911
912impl<K: Ord, V: Ord> Default for LwwMap<K, V> {
913 fn default() -> Self {
914 Self::new()
915 }
916}
917
918impl<K: Ord + Clone, V: Ord + Clone> Mergeable for LwwMap<K, V> {
919 fn merge(&mut self, other: &Self) {
920 LwwMap::merge(self, other);
921 }
922}
923
924impl<K: Ord + Clone, V: Ord + Clone> Crdt for LwwMap<K, V> {
925 type Delta = LwwMapDelta<K, V>;
926
927 fn apply_delta(&mut self, delta: Self::Delta) {
928 match delta {
929 LwwMapDelta::Set {
930 key,
931 timestamp,
932 replica,
933 value,
934 } => self.set(key, timestamp, replica, value),
935 LwwMapDelta::Remove {
936 key,
937 timestamp,
938 replica,
939 } => self.remove(key, timestamp, replica),
940 }
941 }
942}
943
944#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
946pub struct RecordId {
947 pub replica: u64,
948 pub sequence: u64,
949}
950
951#[derive(Clone, Debug, PartialEq, Eq)]
953pub struct Record<D> {
954 pub id: RecordId,
955 pub delta: D,
956}
957
958#[derive(Clone, Debug, Default, PartialEq, Eq)]
964pub struct VersionVector {
965 entries: BTreeMap<u64, u64>,
966}
967
968impl VersionVector {
969 pub fn new() -> Self {
970 VersionVector {
971 entries: BTreeMap::new(),
972 }
973 }
974
975 pub fn get(&self, replica: u64) -> u64 {
976 self.entries.get(&replica).copied().unwrap_or(0)
977 }
978
979 pub fn observe(&mut self, id: RecordId) {
984 if self.get(id.replica).checked_add(1) == Some(id.sequence) {
985 self.set(id.replica, id.sequence);
986 }
987 }
988
989 pub fn includes(&self, id: RecordId) -> bool {
990 self.get(id.replica) >= id.sequence
991 }
992
993 pub fn entries(&self) -> &BTreeMap<u64, u64> {
994 &self.entries
995 }
996
997 fn set(&mut self, replica: u64, sequence: u64) {
998 if sequence == 0 {
999 self.entries.remove(&replica);
1000 } else {
1001 self.entries.insert(replica, sequence);
1002 }
1003 }
1004}
1005
1006#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1008pub enum Admission {
1009 Accepted,
1010 Duplicate,
1011 Collision,
1012}
1013
1014#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1015pub enum AppendError {
1016 SequenceExhausted,
1017}
1018
1019#[derive(Clone, Debug, PartialEq, Eq)]
1021pub struct EventLog<D> {
1022 replica_count: Option<usize>,
1023 records: Vec<Record<D>>,
1024 seen: BTreeMap<RecordId, usize>,
1025 version: VersionVector,
1026}
1027
1028impl<D> EventLog<D> {
1029 pub fn new() -> Self {
1030 EventLog {
1031 replica_count: None,
1032 records: Vec::new(),
1033 seen: BTreeMap::new(),
1034 version: VersionVector::new(),
1035 }
1036 }
1037
1038 pub fn with_replica_count(replica_count: usize) -> Self {
1040 Self {
1041 replica_count: Some(replica_count),
1042 ..Self::new()
1043 }
1044 }
1045
1046 pub fn for_crdt<C: Crdt<Delta = D>>(state: &C) -> Self {
1048 Self {
1049 replica_count: state.replica_count(),
1050 ..Self::new()
1051 }
1052 }
1053
1054 pub fn replica_count(&self) -> Option<usize> {
1055 self.replica_count
1056 }
1057
1058 pub fn append(&mut self, replica: u64, delta: D) -> RecordId
1059 where
1060 D: PartialEq,
1061 {
1062 self.append_with(replica, delta, |_| {})
1063 .expect("event log sequence exhausted")
1064 }
1065
1066 pub fn append_with<F>(
1068 &mut self,
1069 replica: u64,
1070 delta: D,
1071 apply: F,
1072 ) -> Result<RecordId, AppendError>
1073 where
1074 D: PartialEq,
1075 F: FnOnce(&D),
1076 {
1077 let sequence = self
1078 .seen
1079 .range(
1080 RecordId {
1081 replica,
1082 sequence: 0,
1083 }..=RecordId {
1084 replica,
1085 sequence: u64::MAX,
1086 },
1087 )
1088 .next_back()
1089 .map(|(id, _)| id.sequence)
1090 .unwrap_or(0)
1091 .checked_add(1)
1092 .ok_or(AppendError::SequenceExhausted)?;
1093 let id = RecordId { replica, sequence };
1094 let outcome = self.admit_with(Record { id, delta }, apply);
1095 debug_assert_eq!(outcome, Admission::Accepted);
1096 Ok(id)
1097 }
1098
1099 pub fn merge_records<I>(&mut self, records: I) -> Vec<Admission>
1100 where
1101 D: PartialEq,
1102 I: IntoIterator<Item = Record<D>>,
1103 {
1104 records.into_iter().map(|r| self.insert_record(r)).collect()
1105 }
1106
1107 #[must_use]
1111 pub fn admit_with<F>(&mut self, record: Record<D>, apply: F) -> Admission
1112 where
1113 D: PartialEq,
1114 F: FnOnce(&D),
1115 {
1116 if let Some(&index) = self.seen.get(&record.id) {
1117 return if self.records[index].delta == record.delta {
1118 Admission::Duplicate
1119 } else {
1120 Admission::Collision
1121 };
1122 }
1123 let id = record.id;
1124 self.seen.insert(id, self.records.len());
1125 self.records.push(record);
1126 self.advance_contiguous_version(id.replica);
1127 apply(&self.records.last().expect("accepted record").delta);
1128 Admission::Accepted
1129 }
1130
1131 pub fn version(&self) -> &VersionVector {
1132 &self.version
1133 }
1134
1135 pub fn records(&self) -> &[Record<D>] {
1136 &self.records
1137 }
1138
1139 pub fn insert_record(&mut self, record: Record<D>) -> Admission
1140 where
1141 D: PartialEq,
1142 {
1143 self.admit_with(record, |_| {})
1144 }
1145
1146 fn advance_contiguous_version(&mut self, replica: u64) {
1147 loop {
1148 let Some(next) = self.version.get(replica).checked_add(1) else {
1149 break;
1150 };
1151 if self.seen.contains_key(&RecordId {
1152 replica,
1153 sequence: next,
1154 }) {
1155 self.version.set(replica, next);
1156 } else {
1157 break;
1158 }
1159 }
1160 }
1161}
1162
1163impl<D: Clone> EventLog<D> {
1164 pub fn since(&self, version: &VersionVector) -> Vec<Record<D>> {
1165 self.records
1166 .iter()
1167 .filter(|record| !version.includes(record.id))
1168 .cloned()
1169 .collect()
1170 }
1171}
1172
1173impl<D> Default for EventLog<D> {
1174 fn default() -> Self {
1175 Self::new()
1176 }
1177}
1178
1179#[derive(Clone, Debug, PartialEq, Eq)]
1180pub struct TransportEnvelope<D> {
1181 pub from: u64,
1182 pub to: u64,
1183 pub records: Vec<Record<D>>,
1184}
1185
1186#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1187pub enum TransportError {
1188 NotSubscribed { peer: u64 },
1189 Disconnected { from: u64, to: u64 },
1190}
1191
1192pub trait TransportAdapter<D> {
1198 fn subscribe(&mut self, peer: u64);
1199 fn is_subscribed(&self, peer: u64) -> bool;
1200 fn set_connected(&mut self, a: u64, b: u64, connected: bool);
1201 fn is_connected(&self, a: u64, b: u64) -> bool;
1202 fn send(&mut self, from: u64, to: u64, records: Vec<Record<D>>) -> Result<(), TransportError>;
1203 fn drain(&mut self, peer: u64) -> Vec<TransportEnvelope<D>>;
1204}
1205
1206#[derive(Clone, Debug, PartialEq, Eq)]
1211pub struct InMemoryTransport<D> {
1212 subscribed: BTreeSet<u64>,
1213 disconnected: BTreeSet<(u64, u64)>,
1214 queue: Vec<TransportEnvelope<D>>,
1215 dropped: Vec<TransportEnvelope<D>>,
1216 drop_next: bool,
1217 duplicate_next: bool,
1218}
1219
1220impl<D> InMemoryTransport<D> {
1221 pub fn new() -> Self {
1222 InMemoryTransport {
1223 subscribed: BTreeSet::new(),
1224 disconnected: BTreeSet::new(),
1225 queue: Vec::new(),
1226 dropped: Vec::new(),
1227 drop_next: false,
1228 duplicate_next: false,
1229 }
1230 }
1231
1232 pub fn drop_next_send(&mut self) {
1233 self.drop_next = true;
1234 }
1235
1236 pub fn duplicate_next_send(&mut self) {
1237 self.duplicate_next = true;
1238 }
1239
1240 pub fn reverse_pending_for(&mut self, peer: u64) {
1241 let mut peer_items = Vec::new();
1242 let mut retained = Vec::new();
1243 for envelope in self.queue.drain(..) {
1244 if envelope.to == peer {
1245 peer_items.push(envelope);
1246 } else {
1247 retained.push(envelope);
1248 }
1249 }
1250 peer_items.reverse();
1251 retained.extend(peer_items);
1252 self.queue = retained;
1253 }
1254
1255 pub fn pending_len(&self) -> usize {
1256 self.queue.len()
1257 }
1258
1259 pub fn dropped_len(&self) -> usize {
1260 self.dropped.len()
1261 }
1262
1263 fn link(a: u64, b: u64) -> (u64, u64) {
1264 if a <= b {
1265 (a, b)
1266 } else {
1267 (b, a)
1268 }
1269 }
1270}
1271
1272impl<D> Default for InMemoryTransport<D> {
1273 fn default() -> Self {
1274 Self::new()
1275 }
1276}
1277
1278impl<D: Clone> TransportAdapter<D> for InMemoryTransport<D> {
1279 fn subscribe(&mut self, peer: u64) {
1280 self.subscribed.insert(peer);
1281 }
1282
1283 fn is_subscribed(&self, peer: u64) -> bool {
1284 self.subscribed.contains(&peer)
1285 }
1286
1287 fn set_connected(&mut self, a: u64, b: u64, connected: bool) {
1288 let link = Self::link(a, b);
1289 if connected {
1290 self.disconnected.remove(&link);
1291 } else {
1292 self.disconnected.insert(link);
1293 }
1294 }
1295
1296 fn is_connected(&self, a: u64, b: u64) -> bool {
1297 a == b || !self.disconnected.contains(&Self::link(a, b))
1298 }
1299
1300 fn send(&mut self, from: u64, to: u64, records: Vec<Record<D>>) -> Result<(), TransportError> {
1301 if !self.is_subscribed(from) {
1302 return Err(TransportError::NotSubscribed { peer: from });
1303 }
1304 if !self.is_subscribed(to) {
1305 return Err(TransportError::NotSubscribed { peer: to });
1306 }
1307 if !self.is_connected(from, to) {
1308 return Err(TransportError::Disconnected { from, to });
1309 }
1310
1311 let envelope = TransportEnvelope { from, to, records };
1312 if self.drop_next {
1313 self.drop_next = false;
1314 self.dropped.push(envelope);
1315 return Ok(());
1316 }
1317
1318 self.queue.push(envelope.clone());
1319 if self.duplicate_next {
1320 self.duplicate_next = false;
1321 self.queue.push(envelope);
1322 }
1323 Ok(())
1324 }
1325
1326 fn drain(&mut self, peer: u64) -> Vec<TransportEnvelope<D>> {
1327 let mut incoming = Vec::new();
1328 let mut retained = Vec::new();
1329 for envelope in self.queue.drain(..) {
1330 if envelope.to == peer {
1331 incoming.push(envelope);
1332 } else {
1333 retained.push(envelope);
1334 }
1335 }
1336 self.queue = retained;
1337 incoming
1338 }
1339}
1340
1341pub fn anti_entropy<D, T>(
1342 transport: &mut T,
1343 from: u64,
1344 to: u64,
1345 local: &EventLog<D>,
1346 remote_version: &VersionVector,
1347) -> Result<(), TransportError>
1348where
1349 D: Clone,
1350 T: TransportAdapter<D>,
1351{
1352 let records = local.since(remote_version);
1353 if records.is_empty() {
1354 Ok(())
1355 } else {
1356 transport.send(from, to, records)
1357 }
1358}
1359
1360const TAG_RECORD: u8 = 0x01;
1361const TAG_EVENT_LOG: u8 = 0x03;
1362const TAG_GCOUNTER_DELTA: u8 = 0x10;
1363const TAG_PNCOUNTER_INC: u8 = 0x11;
1364const TAG_PNCOUNTER_DEC: u8 = 0x12;
1365const TAG_GSET_U64: u8 = 0x20;
1366const TAG_ORSET_U64: u8 = 0x30;
1367const TAG_ORSET_ADD_U64: u8 = 0x31;
1368const TAG_ORSET_REMOVE_U64: u8 = 0x32;
1369const TAG_ORSET_ADD_STRING: u8 = 0x33;
1370const TAG_ORSET_REMOVE_STRING: u8 = 0x34;
1371const TAG_RGA_U64: u8 = 0x40;
1372const TAG_LWW_REGISTER_DELTA_U64: u8 = 0x50;
1373const TAG_LWW_REGISTER_U64: u8 = 0x51;
1374const TAG_ENABLE_WINS_FLAG_ENABLE_U64: u8 = 0x60;
1375const TAG_ENABLE_WINS_FLAG_DISABLE_U64: u8 = 0x61;
1376const TAG_ENABLE_WINS_FLAG_U64: u8 = 0x62;
1377const TAG_LWW_MAP_SET_U64: u8 = 0x70;
1378const TAG_LWW_MAP_REMOVE_U64: u8 = 0x71;
1379const TAG_LWW_MAP_U64: u8 = 0x72;
1380
1381#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1382pub enum WireError {
1383 OwnershipViolation,
1384 UnexpectedEof,
1385 InvalidTag,
1386 TrailingBytes,
1387 LengthOverflow,
1388 RecordCollision,
1389 IntegrityMismatch,
1390 InvalidUtf8,
1391 MissingShape,
1393 DeltaTypeMismatch,
1394 ReplicaCountMismatch {
1395 expected: usize,
1396 actual: usize,
1397 },
1398 ArityKindMismatch,
1400}
1401
1402pub trait WireSchema {
1406 fn wire_schema() -> Vec<u8>;
1407 const REQUIRES_ARITY: bool = false;
1408}
1409
1410macro_rules! wire_schema {
1411 ($ty:ty, $name:literal, $fixed:expr) => {
1412 impl WireSchema for $ty {
1413 fn wire_schema() -> Vec<u8> {
1414 $name.as_bytes().to_vec()
1415 }
1416 const REQUIRES_ARITY: bool = $fixed;
1417 }
1418 };
1419}
1420
1421wire_schema!(GCounterDelta, "safemesh/gcounter-delta/v1", true);
1422wire_schema!(PnCounterDelta, "safemesh/pncounter-delta/v1", true);
1423wire_schema!(GSet<u64>, "safemesh/gset-u64/v1", false);
1424wire_schema!(OrSetDelta<u64, u64>, "safemesh/orset-delta-u64-u64/v1", false);
1425wire_schema!(OrSetDelta<String, u64>, "safemesh/orset-delta-utf8-u64/v1", false);
1426wire_schema!(OrSet<u64, u64>, "safemesh/orset-u64-u64/v1", false);
1427wire_schema!(Rga<u64, u64>, "safemesh/rga-u64-u64/v1", false);
1428wire_schema!(
1429 LwwRegisterDelta<u64>,
1430 "safemesh/lww-register-delta-u64/v1",
1431 false
1432);
1433wire_schema!(LwwRegister<u64>, "safemesh/lww-register-u64/v1", false);
1434wire_schema!(
1435 EnableWinsFlagDelta<u64>,
1436 "safemesh/enable-wins-flag-delta-u64/v1",
1437 false
1438);
1439wire_schema!(
1440 EnableWinsFlag<u64>,
1441 "safemesh/enable-wins-flag-u64/v1",
1442 false
1443);
1444wire_schema!(LwwMapDelta<u64, u64>, "safemesh/lww-map-delta-u64-u64/v1", false);
1445wire_schema!(LwwMap<u64, u64>, "safemesh/lww-map-u64-u64/v1", false);
1446
1447impl<D: WireSchema> WireSchema for Record<D> {
1448 fn wire_schema() -> Vec<u8> {
1449 let mut schema = b"safemesh/record/v1/".to_vec();
1450 schema.extend(D::wire_schema());
1451 schema
1452 }
1453}
1454
1455impl<D: WireSchema> WireSchema for EventLog<D> {
1456 fn wire_schema() -> Vec<u8> {
1457 let mut schema = b"safemesh/event-log/v2/".to_vec();
1458 schema.extend(D::wire_schema());
1459 schema
1460 }
1461}
1462
1463impl<D: WireDecode + WireSchema + PartialEq> EventLog<D> {
1464 pub fn from_wire_bytes_for<C: Crdt<Delta = D>>(
1468 bytes: &[u8],
1469 state: &C,
1470 ) -> Result<Self, WireError> {
1471 let log = Self::from_wire_bytes(bytes)?;
1472 match (state.replica_count(), log.replica_count) {
1473 (Some(expected), Some(actual)) if expected != actual => {
1474 return Err(WireError::ReplicaCountMismatch { expected, actual })
1475 }
1476 (None, Some(_)) | (Some(_), None) => return Err(WireError::ArityKindMismatch),
1477 _ => {}
1478 }
1479 for record in log.records() {
1480 state.validate_record(record.id, &record.delta)?;
1481 }
1482 Ok(log)
1483 }
1484}
1485
1486pub trait WireEncode {
1487 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError>;
1488
1489 fn to_wire_bytes(&self) -> Result<Vec<u8>, WireError> {
1490 let mut out = Vec::new();
1491 self.encode_wire(&mut out)?;
1492 Ok(out)
1493 }
1494}
1495
1496pub trait WireDecode: Sized {
1497 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError>;
1498
1499 fn from_wire_bytes(bytes: &[u8]) -> Result<Self, WireError> {
1500 let mut cursor = WireCursor::new(bytes);
1501 let value = Self::decode_wire(&mut cursor)?;
1502 if cursor.is_empty() {
1503 Ok(value)
1504 } else {
1505 Err(WireError::TrailingBytes)
1506 }
1507 }
1508}
1509
1510pub struct WireCursor<'a> {
1511 bytes: &'a [u8],
1512 offset: usize,
1513}
1514
1515impl<'a> WireCursor<'a> {
1516 pub fn new(bytes: &'a [u8]) -> Self {
1517 WireCursor { bytes, offset: 0 }
1518 }
1519
1520 pub fn is_empty(&self) -> bool {
1521 self.offset == self.bytes.len()
1522 }
1523
1524 fn read_u8(&mut self) -> Result<u8, WireError> {
1525 let byte = *self
1526 .bytes
1527 .get(self.offset)
1528 .ok_or(WireError::UnexpectedEof)?;
1529 self.offset += 1;
1530 Ok(byte)
1531 }
1532
1533 fn read_u32(&mut self) -> Result<u32, WireError> {
1534 let bytes = self.read_exact(4)?;
1535 Ok(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
1536 }
1537
1538 fn read_u64(&mut self) -> Result<u64, WireError> {
1539 let bytes = self.read_exact(8)?;
1540 Ok(u64::from_le_bytes([
1541 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
1542 ]))
1543 }
1544
1545 fn read_len(&mut self) -> Result<usize, WireError> {
1546 usize::try_from(self.read_u32()?).map_err(|_| WireError::LengthOverflow)
1547 }
1548
1549 fn read_exact(&mut self, len: usize) -> Result<&'a [u8], WireError> {
1550 let end = self
1551 .offset
1552 .checked_add(len)
1553 .ok_or(WireError::LengthOverflow)?;
1554 let bytes = self
1555 .bytes
1556 .get(self.offset..end)
1557 .ok_or(WireError::UnexpectedEof)?;
1558 self.offset = end;
1559 Ok(bytes)
1560 }
1561}
1562
1563fn write_u8(out: &mut Vec<u8>, value: u8) {
1564 out.push(value);
1565}
1566
1567fn write_u32(out: &mut Vec<u8>, value: u32) {
1568 out.extend_from_slice(&value.to_le_bytes());
1569}
1570
1571fn write_u64(out: &mut Vec<u8>, value: u64) {
1572 out.extend_from_slice(&value.to_le_bytes());
1573}
1574
1575fn write_len(out: &mut Vec<u8>, len: usize) -> Result<(), WireError> {
1576 let len = u32::try_from(len).map_err(|_| WireError::LengthOverflow)?;
1577 write_u32(out, len);
1578 Ok(())
1579}
1580
1581fn write_bytes(out: &mut Vec<u8>, bytes: &[u8]) -> Result<(), WireError> {
1582 write_len(out, bytes.len())?;
1583 out.extend_from_slice(bytes);
1584 Ok(())
1585}
1586
1587fn read_tag(cursor: &mut WireCursor<'_>, expected: u8) -> Result<(), WireError> {
1588 match cursor.read_u8()? {
1589 tag if tag == expected => Ok(()),
1590 _ => Err(WireError::InvalidTag),
1591 }
1592}
1593
1594impl WireEncode for GCounterDelta {
1595 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1596 write_u8(out, TAG_GCOUNTER_DELTA);
1597 write_u64(
1598 out,
1599 u64::try_from(self.replica).map_err(|_| WireError::LengthOverflow)?,
1600 );
1601 write_u64(out, self.tally);
1602 Ok(())
1603 }
1604}
1605
1606impl WireDecode for GCounterDelta {
1607 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1608 read_tag(cursor, TAG_GCOUNTER_DELTA)?;
1609 let replica = usize::try_from(cursor.read_u64()?).map_err(|_| WireError::LengthOverflow)?;
1610 let tally = cursor.read_u64()?;
1611 Ok(GCounterDelta { replica, tally })
1612 }
1613}
1614
1615impl WireEncode for PnCounterDelta {
1616 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1617 match self {
1618 PnCounterDelta::Inc { replica, tally } => {
1619 write_u8(out, TAG_PNCOUNTER_INC);
1620 write_u64(
1621 out,
1622 u64::try_from(*replica).map_err(|_| WireError::LengthOverflow)?,
1623 );
1624 write_u64(out, *tally);
1625 }
1626 PnCounterDelta::Dec { replica, tally } => {
1627 write_u8(out, TAG_PNCOUNTER_DEC);
1628 write_u64(
1629 out,
1630 u64::try_from(*replica).map_err(|_| WireError::LengthOverflow)?,
1631 );
1632 write_u64(out, *tally);
1633 }
1634 }
1635 Ok(())
1636 }
1637}
1638
1639impl WireDecode for PnCounterDelta {
1640 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1641 let tag = cursor.read_u8()?;
1642 let replica = usize::try_from(cursor.read_u64()?).map_err(|_| WireError::LengthOverflow)?;
1643 let tally = cursor.read_u64()?;
1644 match tag {
1645 TAG_PNCOUNTER_INC => Ok(PnCounterDelta::Inc { replica, tally }),
1646 TAG_PNCOUNTER_DEC => Ok(PnCounterDelta::Dec { replica, tally }),
1647 _ => Err(WireError::InvalidTag),
1648 }
1649 }
1650}
1651
1652impl WireEncode for GSet<u64> {
1653 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1654 write_u8(out, TAG_GSET_U64);
1655 write_len(out, self.elements.len())?;
1656 for element in &self.elements {
1657 write_u64(out, *element);
1658 }
1659 Ok(())
1660 }
1661}
1662
1663impl WireDecode for GSet<u64> {
1664 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1665 read_tag(cursor, TAG_GSET_U64)?;
1666 let mut set = GSet::new();
1667 for _ in 0..cursor.read_len()? {
1668 set.insert(cursor.read_u64()?);
1669 }
1670 Ok(set)
1671 }
1672}
1673
1674impl WireEncode for OrSetDelta<u64, u64> {
1675 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1676 match self {
1677 OrSetDelta::Add { element, token } => {
1678 write_u8(out, TAG_ORSET_ADD_U64);
1679 write_u64(out, *element);
1680 write_u64(out, *token);
1681 }
1682 OrSetDelta::Remove { tokens } => {
1683 write_u8(out, TAG_ORSET_REMOVE_U64);
1684 write_len(out, tokens.len())?;
1685 for token in tokens {
1687 write_u64(out, *token);
1688 }
1689 }
1690 }
1691 Ok(())
1692 }
1693}
1694
1695impl WireDecode for OrSetDelta<u64, u64> {
1696 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1697 match cursor.read_u8()? {
1698 TAG_ORSET_ADD_U64 => Ok(OrSetDelta::Add {
1699 element: cursor.read_u64()?,
1700 token: cursor.read_u64()?,
1701 }),
1702 TAG_ORSET_REMOVE_U64 => {
1703 let mut tokens = Vec::new();
1704 for _ in 0..cursor.read_len()? {
1705 tokens.push(cursor.read_u64()?);
1706 }
1707 Ok(OrSetDelta::Remove { tokens })
1708 }
1709 _ => Err(WireError::InvalidTag),
1710 }
1711 }
1712}
1713
1714impl WireEncode for OrSetDelta<String, u64> {
1718 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1719 match self {
1720 OrSetDelta::Add { element, token } => {
1721 write_u8(out, TAG_ORSET_ADD_STRING);
1722 write_bytes(out, element.as_bytes())?;
1723 write_u64(out, *token);
1724 }
1725 OrSetDelta::Remove { tokens } => {
1726 write_u8(out, TAG_ORSET_REMOVE_STRING);
1727 write_len(out, tokens.len())?;
1728 for token in tokens {
1729 write_u64(out, *token);
1730 }
1731 }
1732 }
1733 Ok(())
1734 }
1735}
1736
1737impl WireDecode for OrSetDelta<String, u64> {
1738 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1739 match cursor.read_u8()? {
1740 TAG_ORSET_ADD_STRING => {
1741 let len = cursor.read_len()?;
1742 let element = core::str::from_utf8(cursor.read_exact(len)?)
1743 .map_err(|_| WireError::InvalidUtf8)?;
1744 let token = cursor.read_u64()?;
1745 Ok(OrSetDelta::Add {
1746 element: String::from(element),
1747 token,
1748 })
1749 }
1750 TAG_ORSET_REMOVE_STRING => {
1751 let mut tokens = Vec::new();
1752 for _ in 0..cursor.read_len()? {
1753 tokens.push(cursor.read_u64()?);
1754 }
1755 Ok(OrSetDelta::Remove { tokens })
1756 }
1757 _ => Err(WireError::InvalidTag),
1758 }
1759 }
1760}
1761
1762impl WireEncode for OrSet<u64, u64> {
1763 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1764 write_u8(out, TAG_ORSET_U64);
1765 write_len(out, self.adds.len())?;
1766 for (element, token) in &self.adds {
1767 write_u64(out, *element);
1768 write_u64(out, *token);
1769 }
1770 write_len(out, self.tombstones.len())?;
1771 for token in &self.tombstones {
1772 write_u64(out, *token);
1773 }
1774 Ok(())
1775 }
1776}
1777
1778impl WireDecode for OrSet<u64, u64> {
1779 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1780 read_tag(cursor, TAG_ORSET_U64)?;
1781 let mut set = OrSet::new();
1782 for _ in 0..cursor.read_len()? {
1783 let element = cursor.read_u64()?;
1784 let token = cursor.read_u64()?;
1785 set.add(element, token);
1786 }
1787 let mut tombstones = Vec::new();
1788 for _ in 0..cursor.read_len()? {
1789 tombstones.push(cursor.read_u64()?);
1790 }
1791 set.apply_remove(tombstones);
1792 Ok(set)
1793 }
1794}
1795
1796impl WireEncode for Rga<u64, u64> {
1797 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1798 write_u8(out, TAG_RGA_U64);
1799 write_len(out, self.placed.len())?;
1800 for (position, value) in &self.placed {
1801 write_u64(out, *position);
1802 write_u64(out, *value);
1803 }
1804 write_len(out, self.tombstones.len())?;
1805 for position in &self.tombstones {
1806 write_u64(out, *position);
1807 }
1808 Ok(())
1809 }
1810}
1811
1812impl WireDecode for Rga<u64, u64> {
1813 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1814 read_tag(cursor, TAG_RGA_U64)?;
1815 let mut rga = Rga::new();
1816 for _ in 0..cursor.read_len()? {
1817 let position = cursor.read_u64()?;
1818 let value = cursor.read_u64()?;
1819 rga.insert(position, value);
1820 }
1821 for _ in 0..cursor.read_len()? {
1822 rga.delete(cursor.read_u64()?);
1823 }
1824 Ok(rga)
1825 }
1826}
1827
1828impl<D: WireEncode> WireEncode for Record<D> {
1829 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1830 write_u8(out, TAG_RECORD);
1831 write_u64(out, self.id.replica);
1832 write_u64(out, self.id.sequence);
1833 write_bytes(out, &self.delta.to_wire_bytes()?)?;
1834 Ok(())
1835 }
1836}
1837
1838impl<D: WireDecode> WireDecode for Record<D> {
1839 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1840 read_tag(cursor, TAG_RECORD)?;
1841 let id = RecordId {
1842 replica: cursor.read_u64()?,
1843 sequence: cursor.read_u64()?,
1844 };
1845 let delta_len = cursor.read_len()?;
1846 let delta_bytes = cursor.read_exact(delta_len)?;
1847 let delta = D::from_wire_bytes(delta_bytes)?;
1848 Ok(Record { id, delta })
1849 }
1850}
1851
1852fn frame_crc32(bytes: &[u8]) -> u32 {
1855 let mut crc = u32::MAX;
1856 for &byte in bytes {
1857 crc ^= u32::from(byte);
1858 for _ in 0..8 {
1859 crc = (crc >> 1) ^ (0xedb8_8320 & 0u32.wrapping_sub(crc & 1));
1860 }
1861 }
1862 !crc
1863}
1864
1865impl<D: WireEncode + WireSchema> WireEncode for EventLog<D> {
1872 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1873 if D::REQUIRES_ARITY && self.replica_count.is_none() {
1874 return Err(WireError::MissingShape);
1875 }
1876 let mut body = Vec::new();
1877 write_u32(&mut body, u32::MAX);
1878 write_bytes(&mut body, &D::wire_schema())?;
1879 match self.replica_count {
1880 Some(count) => {
1881 write_u8(&mut body, 1);
1882 write_u64(
1883 &mut body,
1884 u64::try_from(count).map_err(|_| WireError::LengthOverflow)?,
1885 );
1886 }
1887 None => write_u8(&mut body, 0),
1888 }
1889 write_len(&mut body, self.records.len())?;
1890 for record in &self.records {
1891 write_bytes(&mut body, &record.to_wire_bytes()?)?;
1892 }
1893 let len = u32::try_from(body.len()).map_err(|_| WireError::LengthOverflow)?;
1894 write_u8(out, TAG_EVENT_LOG);
1895 let start = out.len();
1896 write_u32(out, len);
1897 write_u32(out, !len);
1898 out.extend_from_slice(&body);
1899 let checksum = frame_crc32(&out[start..]);
1900 write_u32(out, checksum);
1901 Ok(())
1902 }
1903}
1904
1905impl<D: WireDecode + WireSchema + PartialEq> WireDecode for EventLog<D> {
1906 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1907 read_tag(cursor, TAG_EVENT_LOG)?;
1908 let start = cursor.offset;
1909 let len = cursor.read_u32()?;
1910 if cursor.read_u32()? != !len {
1911 return Err(WireError::IntegrityMismatch);
1912 }
1913 let body =
1914 cursor.read_exact(usize::try_from(len).map_err(|_| WireError::LengthOverflow)?)?;
1915 let checksum = frame_crc32(&cursor.bytes[start..cursor.offset]);
1916 if cursor.read_u32()? != checksum {
1917 return Err(WireError::IntegrityMismatch);
1918 }
1919 let mut body = WireCursor::new(body);
1920 if body.read_u32()? != u32::MAX {
1921 return Err(WireError::MissingShape);
1922 }
1923 let schema_len = body.read_len()?;
1924 if body.read_exact(schema_len)? != D::wire_schema() {
1925 return Err(WireError::DeltaTypeMismatch);
1926 }
1927 let replica_count = match body.read_u8()? {
1928 0 if !D::REQUIRES_ARITY => None,
1929 0 => return Err(WireError::MissingShape),
1930 1 => Some(usize::try_from(body.read_u64()?).map_err(|_| WireError::LengthOverflow)?),
1931 _ => return Err(WireError::ArityKindMismatch),
1932 };
1933 let mut log = EventLog {
1934 replica_count,
1935 ..EventLog::new()
1936 };
1937 for _ in 0..body.read_len()? {
1938 let record_len = body.read_len()?;
1939 let record_bytes = body.read_exact(record_len)?;
1940 if log.insert_record(Record::<D>::from_wire_bytes(record_bytes)?)
1941 == Admission::Collision
1942 {
1943 return Err(WireError::RecordCollision);
1944 }
1945 }
1946 if !body.is_empty() {
1947 return Err(WireError::TrailingBytes);
1948 }
1949 Ok(log)
1950 }
1951}
1952
1953impl WireEncode for LwwRegisterDelta<u64> {
1954 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1955 write_u8(out, TAG_LWW_REGISTER_DELTA_U64);
1956 write_u64(out, self.timestamp);
1957 write_u64(out, self.replica);
1958 write_u64(out, self.value);
1959 Ok(())
1960 }
1961}
1962
1963impl WireDecode for LwwRegisterDelta<u64> {
1964 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1965 read_tag(cursor, TAG_LWW_REGISTER_DELTA_U64)?;
1966 Ok(LwwRegisterDelta {
1967 timestamp: cursor.read_u64()?,
1968 replica: cursor.read_u64()?,
1969 value: cursor.read_u64()?,
1970 })
1971 }
1972}
1973
1974impl WireEncode for LwwRegister<u64> {
1975 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
1976 write_u8(out, TAG_LWW_REGISTER_U64);
1977 match self.entry() {
1978 Some(entry) => {
1979 write_u8(out, 1);
1980 write_u64(out, entry.dot.timestamp);
1981 write_u64(out, entry.dot.replica);
1982 write_u64(out, entry.value);
1983 }
1984 None => write_u8(out, 0),
1985 }
1986 Ok(())
1987 }
1988}
1989
1990impl WireDecode for LwwRegister<u64> {
1991 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
1992 read_tag(cursor, TAG_LWW_REGISTER_U64)?;
1993 let present = cursor.read_u8()?;
1994 match present {
1995 0 => Ok(LwwRegister::new()),
1996 1 => {
1997 let mut register = LwwRegister::new();
1998 register.set(cursor.read_u64()?, cursor.read_u64()?, cursor.read_u64()?);
1999 Ok(register)
2000 }
2001 _ => Err(WireError::InvalidTag),
2002 }
2003 }
2004}
2005
2006impl WireEncode for EnableWinsFlagDelta<u64> {
2007 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
2008 match self {
2009 EnableWinsFlagDelta::Enable { token } => {
2010 write_u8(out, TAG_ENABLE_WINS_FLAG_ENABLE_U64);
2011 write_u64(out, *token);
2012 }
2013 EnableWinsFlagDelta::Disable { tokens } => {
2014 write_u8(out, TAG_ENABLE_WINS_FLAG_DISABLE_U64);
2015 let mut sorted = tokens.clone();
2016 sorted.sort();
2017 sorted.dedup();
2018 write_len(out, sorted.len())?;
2019 for token in sorted {
2020 write_u64(out, token);
2021 }
2022 }
2023 }
2024 Ok(())
2025 }
2026}
2027
2028impl WireDecode for EnableWinsFlagDelta<u64> {
2029 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
2030 let tag = cursor.read_u8()?;
2031 match tag {
2032 TAG_ENABLE_WINS_FLAG_ENABLE_U64 => Ok(EnableWinsFlagDelta::Enable {
2033 token: cursor.read_u64()?,
2034 }),
2035 TAG_ENABLE_WINS_FLAG_DISABLE_U64 => {
2036 let len = cursor.read_len()?;
2037 let mut tokens = Vec::new();
2038 for _ in 0..len {
2039 tokens.push(cursor.read_u64()?);
2040 }
2041 Ok(EnableWinsFlagDelta::Disable { tokens })
2042 }
2043 _ => Err(WireError::InvalidTag),
2044 }
2045 }
2046}
2047
2048impl WireEncode for EnableWinsFlag<u64> {
2049 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
2050 write_u8(out, TAG_ENABLE_WINS_FLAG_U64);
2051 write_len(out, self.enables.len())?;
2052 for token in self.enables.iter() {
2053 write_u64(out, *token);
2054 }
2055 write_len(out, self.tombstones.len())?;
2056 for token in self.tombstones.iter() {
2057 write_u64(out, *token);
2058 }
2059 Ok(())
2060 }
2061}
2062
2063impl WireDecode for EnableWinsFlag<u64> {
2064 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
2065 read_tag(cursor, TAG_ENABLE_WINS_FLAG_U64)?;
2066 let enable_len = cursor.read_len()?;
2067 let mut flag = EnableWinsFlag::new();
2068 for _ in 0..enable_len {
2069 flag.enable(cursor.read_u64()?);
2070 }
2071 let tombstone_len = cursor.read_len()?;
2072 for _ in 0..tombstone_len {
2073 flag.disable([cursor.read_u64()?]);
2074 }
2075 Ok(flag)
2076 }
2077}
2078
2079impl WireEncode for LwwMapDelta<u64, u64> {
2080 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
2081 match self {
2082 LwwMapDelta::Set {
2083 key,
2084 timestamp,
2085 replica,
2086 value,
2087 } => {
2088 write_u8(out, TAG_LWW_MAP_SET_U64);
2089 write_u64(out, *key);
2090 write_u64(out, *timestamp);
2091 write_u64(out, *replica);
2092 write_u64(out, *value);
2093 }
2094 LwwMapDelta::Remove {
2095 key,
2096 timestamp,
2097 replica,
2098 } => {
2099 write_u8(out, TAG_LWW_MAP_REMOVE_U64);
2100 write_u64(out, *key);
2101 write_u64(out, *timestamp);
2102 write_u64(out, *replica);
2103 }
2104 }
2105 Ok(())
2106 }
2107}
2108
2109impl WireDecode for LwwMapDelta<u64, u64> {
2110 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
2111 let tag = cursor.read_u8()?;
2112 match tag {
2113 TAG_LWW_MAP_SET_U64 => Ok(LwwMapDelta::Set {
2114 key: cursor.read_u64()?,
2115 timestamp: cursor.read_u64()?,
2116 replica: cursor.read_u64()?,
2117 value: cursor.read_u64()?,
2118 }),
2119 TAG_LWW_MAP_REMOVE_U64 => Ok(LwwMapDelta::Remove {
2120 key: cursor.read_u64()?,
2121 timestamp: cursor.read_u64()?,
2122 replica: cursor.read_u64()?,
2123 }),
2124 _ => Err(WireError::InvalidTag),
2125 }
2126 }
2127}
2128
2129impl WireEncode for LwwMap<u64, u64> {
2130 fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError> {
2131 write_u8(out, TAG_LWW_MAP_U64);
2132 write_len(out, self.entries.len())?;
2133 for (key, entry) in self.entries.iter() {
2134 write_u64(out, *key);
2135 write_u64(out, entry.dot.timestamp);
2136 write_u64(out, entry.dot.replica);
2137 write_u64(out, entry.value);
2138 }
2139 write_len(out, self.removals.len())?;
2140 for (key, dot) in self.removals.iter() {
2141 write_u64(out, *key);
2142 write_u64(out, dot.timestamp);
2143 write_u64(out, dot.replica);
2144 }
2145 Ok(())
2146 }
2147}
2148
2149impl WireDecode for LwwMap<u64, u64> {
2150 fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError> {
2151 read_tag(cursor, TAG_LWW_MAP_U64)?;
2152 let entry_len = cursor.read_len()?;
2153 let mut map = LwwMap::new();
2154 for _ in 0..entry_len {
2155 map.set(
2156 cursor.read_u64()?,
2157 cursor.read_u64()?,
2158 cursor.read_u64()?,
2159 cursor.read_u64()?,
2160 );
2161 }
2162 let removal_len = cursor.read_len()?;
2163 for _ in 0..removal_len {
2164 map.remove(cursor.read_u64()?, cursor.read_u64()?, cursor.read_u64()?);
2165 }
2166 Ok(map)
2167 }
2168}
2169
2170#[cfg(feature = "laws")]
2171pub mod laws {
2172 use super::{Crdt, Mergeable};
2173 use alloc::vec::Vec;
2174
2175 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
2176 pub enum Law {
2177 Commutative,
2178 Associative,
2179 Idempotent,
2180 Identity,
2181 Convergence,
2182 }
2183
2184 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
2185 pub struct LawFailure {
2186 pub law: Law,
2187 pub a: usize,
2188 pub b: Option<usize>,
2189 pub c: Option<usize>,
2190 }
2191
2192 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
2193 pub struct LawReport {
2194 pub scenarios: usize,
2195 }
2196
2197 pub fn check_merge_laws<T>(identity: &T, samples: &[T]) -> Result<LawReport, LawFailure>
2198 where
2199 T: Mergeable + Clone + PartialEq,
2200 {
2201 let mut scenarios = 0;
2202
2203 for (a_idx, a) in samples.iter().enumerate() {
2204 let mut aa = a.clone();
2205 aa.merge(a);
2206 scenarios += 1;
2207 if aa != *a {
2208 return Err(LawFailure {
2209 law: Law::Idempotent,
2210 a: a_idx,
2211 b: None,
2212 c: None,
2213 });
2214 }
2215
2216 let mut left_identity = identity.clone();
2217 left_identity.merge(a);
2218 let mut right_identity = a.clone();
2219 right_identity.merge(identity);
2220 scenarios += 2;
2221 if left_identity != *a || right_identity != *a {
2222 return Err(LawFailure {
2223 law: Law::Identity,
2224 a: a_idx,
2225 b: None,
2226 c: None,
2227 });
2228 }
2229
2230 for (b_idx, b) in samples.iter().enumerate() {
2231 let mut ab = a.clone();
2232 ab.merge(b);
2233 let mut ba = b.clone();
2234 ba.merge(a);
2235 scenarios += 1;
2236 if ab != ba {
2237 return Err(LawFailure {
2238 law: Law::Commutative,
2239 a: a_idx,
2240 b: Some(b_idx),
2241 c: None,
2242 });
2243 }
2244
2245 for (c_idx, c) in samples.iter().enumerate() {
2246 let mut left = a.clone();
2247 left.merge(b);
2248 left.merge(c);
2249
2250 let mut right_inner = b.clone();
2251 right_inner.merge(c);
2252 let mut right = a.clone();
2253 right.merge(&right_inner);
2254
2255 scenarios += 1;
2256 if left != right {
2257 return Err(LawFailure {
2258 law: Law::Associative,
2259 a: a_idx,
2260 b: Some(b_idx),
2261 c: Some(c_idx),
2262 });
2263 }
2264 }
2265 }
2266 }
2267
2268 Ok(LawReport { scenarios })
2269 }
2270
2271 pub fn check_crdt_convergence<C>(
2272 seed_state: &C,
2273 deltas: &[C::Delta],
2274 ) -> Result<LawReport, LawFailure>
2275 where
2276 C: Crdt + Clone + PartialEq,
2277 C::Delta: Clone,
2278 {
2279 let expected = apply_all(seed_state, deltas.iter().cloned());
2280 let mut scenarios = 1;
2281
2282 let reverse = apply_all(seed_state, deltas.iter().cloned().rev());
2283 scenarios += 1;
2284 if reverse != expected {
2285 return Err(convergence_failure(0));
2286 }
2287
2288 let duplicated = apply_all(
2289 seed_state,
2290 deltas.iter().cloned().flat_map(|d| [d.clone(), d]),
2291 );
2292 scenarios += 1;
2293 if duplicated != expected {
2294 return Err(convergence_failure(1));
2295 }
2296
2297 for (seed_idx, seed) in [0x51a7_3eed_u64, 0xc0ff_ee13_u64, 0x5afe_0001_u64]
2298 .iter()
2299 .copied()
2300 .enumerate()
2301 {
2302 let shuffled = shuffled(deltas, seed);
2303 let shuffled_state = apply_all(seed_state, shuffled.into_iter());
2304 scenarios += 1;
2305 if shuffled_state != expected {
2306 return Err(convergence_failure(2 + seed_idx));
2307 }
2308 }
2309
2310 let mut even = seed_state.clone();
2311 let mut odd = seed_state.clone();
2312 for (idx, delta) in deltas.iter().cloned().enumerate() {
2313 if idx % 2 == 0 {
2314 even.apply_delta(delta);
2315 } else {
2316 odd.apply_delta(delta);
2317 }
2318 }
2319 even.merge(&odd);
2320 scenarios += 1;
2321 if even != expected {
2322 return Err(convergence_failure(5));
2323 }
2324
2325 let mut lossy_a = seed_state.clone();
2326 let mut lossy_b = seed_state.clone();
2327 for (idx, delta) in deltas.iter().cloned().enumerate() {
2328 if idx % 3 == 0 {
2329 lossy_b.apply_delta(delta);
2330 } else {
2331 lossy_a.apply_delta(delta);
2332 }
2333 }
2334 lossy_a.merge(&lossy_b);
2335 scenarios += 1;
2336 if lossy_a != expected {
2337 return Err(convergence_failure(6));
2338 }
2339
2340 Ok(LawReport { scenarios })
2341 }
2342
2343 fn apply_all<C, I>(seed_state: &C, deltas: I) -> C
2344 where
2345 C: Crdt + Clone,
2346 I: IntoIterator<Item = C::Delta>,
2347 {
2348 let mut state = seed_state.clone();
2349 for delta in deltas {
2350 state.apply_delta(delta);
2351 }
2352 state
2353 }
2354
2355 fn convergence_failure(a: usize) -> LawFailure {
2356 LawFailure {
2357 law: Law::Convergence,
2358 a,
2359 b: None,
2360 c: None,
2361 }
2362 }
2363
2364 fn shuffled<T: Clone>(items: &[T], seed: u64) -> Vec<T> {
2365 let mut out = items.to_vec();
2366 let mut rng = XorShift64::new(seed);
2367 let len = out.len();
2368 if len < 2 {
2369 return out;
2370 }
2371 let mut i = len - 1;
2372 while i > 0 {
2373 let j = rng.next_usize(i + 1);
2374 out.swap(i, j);
2375 i -= 1;
2376 }
2377 out
2378 }
2379
2380 struct XorShift64 {
2381 state: u64,
2382 }
2383
2384 impl XorShift64 {
2385 fn new(seed: u64) -> Self {
2386 let state = if seed == 0 {
2387 0x9e37_79b9_7f4a_7c15
2388 } else {
2389 seed
2390 };
2391 XorShift64 { state }
2392 }
2393
2394 fn next_u64(&mut self) -> u64 {
2395 let mut x = self.state;
2396 x ^= x << 13;
2397 x ^= x >> 7;
2398 x ^= x << 17;
2399 self.state = x;
2400 x
2401 }
2402
2403 fn next_usize(&mut self, upper: usize) -> usize {
2404 (self.next_u64() as usize) % upper
2405 }
2406 }
2407}
2408
2409#[cfg(test)]
2410mod frame_tests {
2411 use super::*;
2412 use alloc::vec;
2413
2414 #[test]
2415 fn legacy_integrity_frames_refuse_missing_shape() {
2416 for records in [vec![], vec![record(1, 5)]] {
2417 let mut body = Vec::new();
2418 write_len(&mut body, records.len()).unwrap();
2419 for record in records {
2420 write_bytes(&mut body, &record.to_wire_bytes().unwrap()).unwrap();
2421 }
2422 let mut bytes = vec![TAG_EVENT_LOG];
2423 let len = u32::try_from(body.len()).unwrap();
2424 write_u32(&mut bytes, len);
2425 write_u32(&mut bytes, !len);
2426 bytes.extend(body);
2427 let crc = frame_crc32(&bytes[1..]);
2428 write_u32(&mut bytes, crc);
2429 assert_eq!(
2430 EventLog::<GCounterDelta>::from_wire_bytes(&bytes),
2431 Err(WireError::MissingShape)
2432 );
2433 }
2434 }
2435
2436 #[test]
2437 fn crc32_matches_standard_check_vector() {
2438 assert_eq!(frame_crc32(b"123456789"), 0xcbf4_3926);
2439 }
2440
2441 #[test]
2442 fn binding_collision_fixtures_use_product_encoder() {
2443 extern crate std;
2444 fn fixture<D: WireEncode + WireDecode + WireSchema + PartialEq>(
2445 name: &str,
2446 deltas: [D; 2],
2447 ) {
2448 let mut log = if D::REQUIRES_ARITY {
2449 EventLog::with_replica_count(2)
2450 } else {
2451 EventLog::new()
2452 };
2453 log.records = deltas
2454 .into_iter()
2455 .map(|delta| Record {
2456 id: RecordId {
2457 replica: 1,
2458 sequence: 1,
2459 },
2460 delta,
2461 })
2462 .collect();
2463 let bytes = log.to_wire_bytes().unwrap();
2464 assert!(matches!(
2465 EventLog::<D>::from_wire_bytes(&bytes),
2466 Err(WireError::RecordCollision)
2467 ));
2468 if let Some(directory) = std::env::var_os("SAFEMESH_FRAME_FIXTURE_DIR") {
2469 std::fs::write(std::path::Path::new(&directory).join(name), bytes).unwrap();
2470 }
2471 }
2472 fixture(
2473 "gcounter-collision.bin",
2474 [
2475 GCounterDelta {
2476 replica: 1,
2477 tally: 5,
2478 },
2479 GCounterDelta {
2480 replica: 1,
2481 tally: 9,
2482 },
2483 ],
2484 );
2485 fixture(
2486 "flag-collision.bin",
2487 [
2488 EnableWinsFlagDelta::Enable { token: 5u64 },
2489 EnableWinsFlagDelta::Enable { token: 9u64 },
2490 ],
2491 );
2492 fixture(
2493 "register-collision.bin",
2494 [
2495 LwwRegisterDelta {
2496 timestamp: 1,
2497 replica: 1,
2498 value: 5u64,
2499 },
2500 LwwRegisterDelta {
2501 timestamp: 2,
2502 replica: 1,
2503 value: 9u64,
2504 },
2505 ],
2506 );
2507 fixture(
2508 "map-collision.bin",
2509 [
2510 LwwMapDelta::Set {
2511 key: 1u64,
2512 timestamp: 1,
2513 replica: 1,
2514 value: 5u64,
2515 },
2516 LwwMapDelta::Remove {
2517 key: 1u64,
2518 timestamp: 2,
2519 replica: 1,
2520 },
2521 ],
2522 );
2523 }
2524
2525 fn record(sequence: u64, tally: u64) -> Record<GCounterDelta> {
2526 Record {
2527 id: RecordId {
2528 replica: 1,
2529 sequence,
2530 },
2531 delta: GCounterDelta { replica: 1, tally },
2532 }
2533 }
2534
2535 fn wire_log(records: &[Record<GCounterDelta>]) -> Vec<u8> {
2538 let mut log = EventLog::with_replica_count(2);
2539 log.records = records.to_vec();
2540 log.to_wire_bytes().unwrap()
2541 }
2542 #[test]
2543 fn decoder_surfaces_conflicts_before_deduplication() {
2544 for records in [
2545 vec![record(1, 5), record(1, 9)],
2546 vec![record(1, 9), record(1, 5)],
2547 ] {
2548 assert_eq!(
2549 EventLog::<GCounterDelta>::from_wire_bytes(&wire_log(&records)),
2550 Err(WireError::RecordCollision)
2551 );
2552 }
2553 let decoded =
2554 EventLog::<GCounterDelta>::from_wire_bytes(&wire_log(&[record(1, 5), record(1, 5)]))
2555 .unwrap();
2556 assert_eq!(decoded.records(), &[record(1, 5)]);
2557 }
2558}