1use std::collections::{BTreeMap, BTreeSet};
2
3use crate::{AuthorId, Dot, VersionVector};
4
5#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
7pub enum CrdtError {
8 #[error("one operation dot identifies conflicting values")]
10 ConflictingDot,
11 #[error("value has {0} concurrent alternatives")]
13 Conflict(usize),
14 #[error("immutable value is already set")]
16 ImmutableAlreadySet,
17 #[error("ordered-list predecessor is missing")]
19 MissingPredecessor,
20 #[error("ordered-list element is missing")]
22 MissingElement,
23 #[error("ordered-list removal does not observe the element")]
25 InvalidRemoval,
26 #[error("counter overflow")]
28 CounterOverflow,
29 #[error("commit operation index exhausted")]
31 OperationIndexExhausted,
32 #[error("ordered-list parent graph contains a cycle")]
34 CyclicList,
35}
36
37pub trait Merge {
39 fn merge(&mut self, other: &Self) -> Result<(), CrdtError>;
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
44#[cbor(array)]
45struct Assignment<T> {
46 #[n(0)]
47 value: T,
48 #[n(1)]
49 dot: Dot,
50 #[n(2)]
51 context: VersionVector,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
56#[cbor(array)]
57pub struct Lww<T> {
58 #[n(0)]
59 assignment: Option<Assignment<T>>,
60}
61
62impl<T> Lww<T> {
63 pub const fn new() -> Self {
65 Self { assignment: None }
66 }
67
68 pub fn get(&self) -> Option<&T> {
70 self.assignment.as_ref().map(|entry| &entry.value)
71 }
72
73 pub fn dot(&self) -> Option<Dot> {
75 self.assignment.as_ref().map(|entry| entry.dot)
76 }
77
78 pub fn context(&self) -> Option<&VersionVector> {
80 self.assignment.as_ref().map(|entry| &entry.context)
81 }
82}
83
84impl<T: Clone + Eq> Lww<T> {
85 pub fn assign(&mut self, value: T, dot: Dot, context: VersionVector) -> Result<(), CrdtError> {
87 merge_lww_assignment(
88 &mut self.assignment,
89 Assignment {
90 value,
91 dot,
92 context,
93 },
94 )
95 }
96
97 pub fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
99 Merge::merge(self, other)
100 }
101
102 pub fn canonicalize_for_commit(
104 &self,
105 author: AuthorId,
106 sequence: u64,
107 context: &VersionVector,
108 next_operation: &mut u32,
109 ) -> Result<Self, CrdtError> {
110 let mut canonical = Self::new();
111 if let Some(value) = self.get() {
112 canonical.assign(
113 value.clone(),
114 allocate_dot(author, sequence, next_operation)?,
115 context.clone(),
116 )?;
117 }
118 Ok(canonical)
119 }
120}
121
122impl<T> Default for Lww<T> {
123 fn default() -> Self {
124 Self::new()
125 }
126}
127
128impl<T: Clone + Eq> Merge for Lww<T> {
129 fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
130 if let Some(candidate) = &other.assignment {
131 merge_lww_assignment(&mut self.assignment, candidate.clone())?;
132 }
133 Ok(())
134 }
135}
136
137fn merge_lww_assignment<T: Eq>(
138 current: &mut Option<Assignment<T>>,
139 mut candidate: Assignment<T>,
140) -> Result<(), CrdtError> {
141 let Some(existing) = current else {
142 *current = Some(candidate);
143 return Ok(());
144 };
145
146 if candidate.dot == existing.dot {
147 if candidate.value != existing.value {
148 return Err(CrdtError::ConflictingDot);
149 }
150 existing.context.merge(&candidate.context);
151 return Ok(());
152 }
153
154 let candidate_is_later = candidate.context.covers(&existing.dot);
155 let existing_is_later = existing.context.covers(&candidate.dot);
156 if candidate_is_later || (!existing_is_later && candidate.dot > existing.dot) {
157 candidate.context.merge(&existing.context);
158 *existing = candidate;
159 }
160 Ok(())
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
165#[cbor(array)]
166pub struct OrSet<T: Ord> {
167 #[n(0)]
168 adds: BTreeMap<T, BTreeSet<Dot>>,
169 #[n(1)]
170 removed: BTreeSet<Dot>,
171}
172
173impl<T: Ord> OrSet<T> {
174 pub const fn new() -> Self {
176 Self {
177 adds: BTreeMap::new(),
178 removed: BTreeSet::new(),
179 }
180 }
181
182 pub fn contains(&self, value: &T) -> bool
184 where
185 T: Ord,
186 {
187 self.adds.get(value).is_some_and(|dots| !dots.is_empty())
188 }
189
190 pub fn values(&self) -> impl Iterator<Item = &T> {
192 self.adds.keys()
193 }
194}
195
196impl<T: Clone + Ord> OrSet<T> {
197 pub fn insert(&mut self, value: T, dot: Dot) -> Result<(), CrdtError> {
199 for (existing_value, dots) in &self.adds {
200 if dots.contains(&dot) && existing_value != &value {
201 return Err(CrdtError::ConflictingDot);
202 }
203 }
204 if !self.removed.contains(&dot) {
205 self.adds.entry(value).or_default().insert(dot);
206 }
207 Ok(())
208 }
209
210 pub fn remove(&mut self, value: &T, context: &VersionVector) {
212 let Some(dots) = self.adds.get_mut(value) else {
213 return;
214 };
215 let observed: Vec<_> = dots
216 .iter()
217 .copied()
218 .filter(|dot| context.covers(dot))
219 .collect();
220 for dot in observed {
221 dots.remove(&dot);
222 self.removed.insert(dot);
223 }
224 if dots.is_empty() {
225 self.adds.remove(value);
226 }
227 }
228
229 pub fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
231 Merge::merge(self, other)
232 }
233
234 pub fn canonicalize_for_commit(
236 &self,
237 author: AuthorId,
238 sequence: u64,
239 _context: &VersionVector,
240 next_operation: &mut u32,
241 ) -> Result<Self, CrdtError> {
242 let mut canonical = Self::new();
243 for value in self.values() {
244 canonical.insert(
245 value.clone(),
246 allocate_dot(author, sequence, next_operation)?,
247 )?;
248 }
249 Ok(canonical)
250 }
251}
252
253impl<T: Ord> Default for OrSet<T> {
254 fn default() -> Self {
255 Self::new()
256 }
257}
258
259impl<T: Clone + Ord> Merge for OrSet<T> {
260 fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
261 self.removed.extend(other.removed.iter().copied());
262 for (value, dots) in &other.adds {
263 for &dot in dots {
264 self.insert(value.clone(), dot)?;
265 }
266 }
267 for dots in self.adds.values_mut() {
268 dots.retain(|dot| !self.removed.contains(dot));
269 }
270 self.adds.retain(|_, dots| !dots.is_empty());
271 Ok(())
272 }
273}
274
275#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
277#[cbor(array)]
278pub struct GrowOnlySet<T: Ord> {
279 #[n(0)]
280 values: BTreeSet<T>,
281}
282
283impl<T: Ord> GrowOnlySet<T> {
284 pub const fn new() -> Self {
286 Self {
287 values: BTreeSet::new(),
288 }
289 }
290
291 pub fn values(&self) -> impl Iterator<Item = &T> {
293 self.values.iter()
294 }
295}
296
297impl<T: Clone + Ord> GrowOnlySet<T> {
298 pub fn canonicalize_for_commit(
300 &self,
301 _author: AuthorId,
302 _sequence: u64,
303 _context: &VersionVector,
304 _next_operation: &mut u32,
305 ) -> Result<Self, CrdtError> {
306 Ok(self.clone())
307 }
308}
309
310impl<T: Ord> GrowOnlySet<T> {
311 pub fn insert(&mut self, value: T) -> bool {
313 self.values.insert(value)
314 }
315
316 pub fn merge(&mut self, other: &Self) -> Result<(), CrdtError>
318 where
319 T: Clone,
320 {
321 Merge::merge(self, other)
322 }
323}
324
325impl<T: Ord> Default for GrowOnlySet<T> {
326 fn default() -> Self {
327 Self::new()
328 }
329}
330
331impl<T: Clone + Ord> Merge for GrowOnlySet<T> {
332 fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
333 self.values.extend(other.values.iter().cloned());
334 Ok(())
335 }
336}
337
338#[derive(Debug, Clone, Default, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
340#[cbor(array)]
341pub struct PnCounter {
342 #[n(0)]
343 positive: BTreeMap<AuthorId, u64>,
344 #[n(1)]
345 negative: BTreeMap<AuthorId, u64>,
346}
347
348impl PnCounter {
349 pub const fn new() -> Self {
351 Self {
352 positive: BTreeMap::new(),
353 negative: BTreeMap::new(),
354 }
355 }
356
357 pub fn increment(&mut self, author: AuthorId, amount: u64) -> Result<(), CrdtError> {
359 add_component(&mut self.positive, author, amount)
360 }
361
362 pub fn decrement(&mut self, author: AuthorId, amount: u64) -> Result<(), CrdtError> {
364 add_component(&mut self.negative, author, amount)
365 }
366
367 pub fn value(&self) -> Result<i128, CrdtError> {
369 let positive = sum_components(&self.positive)?;
370 let negative = sum_components(&self.negative)?;
371 positive
372 .checked_sub(negative)
373 .ok_or(CrdtError::CounterOverflow)
374 }
375
376 pub fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
378 Merge::merge(self, other)
379 }
380
381 pub fn canonicalize_for_commit(
383 &self,
384 author: AuthorId,
385 _sequence: u64,
386 _context: &VersionVector,
387 _next_operation: &mut u32,
388 ) -> Result<Self, CrdtError> {
389 let value = self.value()?;
390 let mut canonical = Self::new();
391 if value >= 0 {
392 canonical.increment(
393 author,
394 u64::try_from(value).map_err(|_| CrdtError::CounterOverflow)?,
395 )?;
396 } else {
397 let magnitude = value.checked_abs().ok_or(CrdtError::CounterOverflow)?;
398 canonical.decrement(
399 author,
400 u64::try_from(magnitude).map_err(|_| CrdtError::CounterOverflow)?,
401 )?;
402 }
403 Ok(canonical)
404 }
405}
406
407impl Merge for PnCounter {
408 fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
409 merge_components(&mut self.positive, &other.positive);
410 merge_components(&mut self.negative, &other.negative);
411 self.value().map(|_| ())
412 }
413}
414
415fn add_component(
416 components: &mut BTreeMap<AuthorId, u64>,
417 author: AuthorId,
418 amount: u64,
419) -> Result<(), CrdtError> {
420 let value = components.entry(author).or_default();
421 *value = value
422 .checked_add(amount)
423 .ok_or(CrdtError::CounterOverflow)?;
424 Ok(())
425}
426
427fn merge_components(components: &mut BTreeMap<AuthorId, u64>, other: &BTreeMap<AuthorId, u64>) {
428 for (&author, &other_value) in other {
429 components
430 .entry(author)
431 .and_modify(|value| *value = (*value).max(other_value))
432 .or_insert(other_value);
433 }
434}
435
436fn sum_components(components: &BTreeMap<AuthorId, u64>) -> Result<i128, CrdtError> {
437 components.values().try_fold(0_i128, |total, value| {
438 total
439 .checked_add(i128::from(*value))
440 .ok_or(CrdtError::CounterOverflow)
441 })
442}
443
444#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
446#[cbor(array)]
447pub struct MultiValue<T> {
448 #[n(0)]
449 entries: BTreeMap<Dot, Assignment<T>>,
450}
451
452impl<T> MultiValue<T> {
453 pub const fn new() -> Self {
455 Self {
456 entries: BTreeMap::new(),
457 }
458 }
459
460 pub fn values(&self) -> impl Iterator<Item = &T> {
462 self.entries.values().map(|entry| &entry.value)
463 }
464
465 pub fn read_one(&self) -> Result<Option<&T>, CrdtError> {
467 match self.entries.len() {
468 0 => Ok(None),
469 1 => Ok(self.entries.values().next().map(|entry| &entry.value)),
470 count => Err(CrdtError::Conflict(count)),
471 }
472 }
473}
474
475impl<T: Clone + Eq> MultiValue<T> {
476 pub fn assign(&mut self, value: T, dot: Dot, context: VersionVector) -> Result<(), CrdtError> {
478 if let Some(existing) = self.entries.get_mut(&dot) {
479 if existing.value != value {
480 return Err(CrdtError::ConflictingDot);
481 }
482 existing.context.merge(&context);
483 return Ok(());
484 }
485 if self
486 .entries
487 .values()
488 .any(|existing| existing.context.covers(&dot))
489 {
490 return Ok(());
491 }
492 self.entries
493 .retain(|_, existing| !context.covers(&existing.dot));
494 self.entries.insert(
495 dot,
496 Assignment {
497 value,
498 dot,
499 context,
500 },
501 );
502 Ok(())
503 }
504
505 pub fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
507 Merge::merge(self, other)
508 }
509
510 pub fn canonicalize_for_commit(
512 &self,
513 author: AuthorId,
514 sequence: u64,
515 context: &VersionVector,
516 next_operation: &mut u32,
517 ) -> Result<Self, CrdtError> {
518 let mut canonical = Self::new();
519 for value in self.values() {
520 canonical.assign(
521 value.clone(),
522 allocate_dot(author, sequence, next_operation)?,
523 context.clone(),
524 )?;
525 }
526 Ok(canonical)
527 }
528}
529
530impl<T> Default for MultiValue<T> {
531 fn default() -> Self {
532 Self::new()
533 }
534}
535
536impl<T: Clone + Eq> Merge for MultiValue<T> {
537 fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
538 for (&dot, entry) in &other.entries {
539 if let Some(existing) = self.entries.get_mut(&dot) {
540 if existing.value != entry.value {
541 return Err(CrdtError::ConflictingDot);
542 }
543 existing.context.merge(&entry.context);
544 } else {
545 self.entries.insert(dot, entry.clone());
546 }
547 }
548
549 let entries: Vec<_> = self.entries.values().cloned().collect();
550 self.entries.retain(|dot, _| {
551 !entries
552 .iter()
553 .any(|other| other.dot != *dot && other.context.covers(dot))
554 });
555 Ok(())
556 }
557}
558
559#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
561#[cbor(array)]
562pub struct Immutable<T> {
563 #[n(0)]
564 values: MultiValue<T>,
565}
566
567impl<T> Immutable<T> {
568 pub const fn new() -> Self {
570 Self {
571 values: MultiValue::new(),
572 }
573 }
574
575 pub fn get(&self) -> Result<Option<&T>, CrdtError> {
577 self.values.read_one()
578 }
579
580 pub fn values(&self) -> impl Iterator<Item = &T> {
582 self.values.values()
583 }
584}
585
586impl<T: Clone + Eq> Immutable<T> {
587 pub fn set(&mut self, value: T, dot: Dot, context: VersionVector) -> Result<(), CrdtError> {
589 if self
590 .values
591 .entries
592 .values()
593 .any(|existing| context.covers(&existing.dot))
594 {
595 return Err(CrdtError::ImmutableAlreadySet);
596 }
597 self.values.assign(value, dot, context)
598 }
599
600 pub fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
602 Merge::merge(self, other)
603 }
604
605 pub fn canonicalize_for_commit(
607 &self,
608 author: AuthorId,
609 sequence: u64,
610 context: &VersionVector,
611 next_operation: &mut u32,
612 ) -> Result<Self, CrdtError> {
613 let mut canonical = Self::new();
614 for value in self.values() {
615 canonical.set(
616 value.clone(),
617 allocate_dot(author, sequence, next_operation)?,
618 context.clone(),
619 )?;
620 }
621 Ok(canonical)
622 }
623}
624
625impl<T> Default for Immutable<T> {
626 fn default() -> Self {
627 Self::new()
628 }
629}
630
631impl<T: Clone + Eq> Merge for Immutable<T> {
632 fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
633 for left in self.values.entries.values() {
634 for right in other.values.entries.values() {
635 if left.dot != right.dot
636 && (left.context.covers(&right.dot) || right.context.covers(&left.dot))
637 {
638 return Err(CrdtError::ImmutableAlreadySet);
639 }
640 }
641 }
642 self.values.merge(&other.values)
643 }
644}
645
646#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
647#[cbor(array)]
648struct ListElement<T> {
649 #[n(0)]
650 parent: Option<Dot>,
651 #[n(1)]
652 value: T,
653 #[n(2)]
654 removed: bool,
655}
656
657#[derive(Debug, Clone, PartialEq, Eq, minicbor::Encode, minicbor::Decode)]
659#[cbor(array)]
660pub struct OrderedList<T> {
661 #[n(0)]
662 elements: BTreeMap<Dot, ListElement<T>>,
663}
664
665impl<T> OrderedList<T> {
666 pub const fn new() -> Self {
668 Self {
669 elements: BTreeMap::new(),
670 }
671 }
672
673 pub fn values(&self) -> impl Iterator<Item = &T> {
675 let mut values = Vec::with_capacity(self.elements.len());
676 let mut pending: Vec<_> = self
677 .elements
678 .iter()
679 .rev()
680 .filter_map(|(&dot, element)| element.parent.is_none().then_some(dot))
681 .collect();
682 while let Some(dot) = pending.pop() {
683 let element = &self.elements[&dot];
684 if !element.removed {
685 values.push(&element.value);
686 }
687 pending.extend(
688 self.elements
689 .iter()
690 .rev()
691 .filter_map(|(&child, element)| (element.parent == Some(dot)).then_some(child)),
692 );
693 }
694 values.into_iter()
695 }
696}
697
698impl<T: Clone + Eq> OrderedList<T> {
699 pub fn insert_after(
701 &mut self,
702 parent: Option<Dot>,
703 dot: Dot,
704 value: T,
705 ) -> Result<(), CrdtError> {
706 if parent.is_some_and(|parent| !self.elements.contains_key(&parent)) {
707 return Err(CrdtError::MissingPredecessor);
708 }
709 if let Some(existing) = self.elements.get(&dot) {
710 if existing.parent == parent && existing.value == value {
711 return Ok(());
712 }
713 return Err(CrdtError::ConflictingDot);
714 }
715 self.elements.insert(
716 dot,
717 ListElement {
718 parent,
719 value,
720 removed: false,
721 },
722 );
723 Ok(())
724 }
725
726 pub fn remove(&mut self, dot: Dot, context: &VersionVector) -> Result<(), CrdtError> {
728 let element = self
729 .elements
730 .get_mut(&dot)
731 .ok_or(CrdtError::MissingElement)?;
732 if !context.covers(&dot) {
733 return Err(CrdtError::InvalidRemoval);
734 }
735 element.removed = true;
736 Ok(())
737 }
738
739 pub fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
741 Merge::merge(self, other)
742 }
743
744 pub fn canonicalize_for_commit(
746 &self,
747 author: AuthorId,
748 sequence: u64,
749 _context: &VersionVector,
750 next_operation: &mut u32,
751 ) -> Result<Self, CrdtError> {
752 self.validate_structure()?;
753 let mut canonical = Self::new();
754 let mut parent = None;
755 for value in self.values() {
756 let dot = allocate_dot(author, sequence, next_operation)?;
757 canonical.insert_after(parent, dot, value.clone())?;
758 parent = Some(dot);
759 }
760 Ok(canonical)
761 }
762
763 fn validate_structure(&self) -> Result<(), CrdtError> {
764 for &start in self.elements.keys() {
765 let mut path = BTreeSet::new();
766 let mut current = Some(start);
767 while let Some(dot) = current {
768 if !path.insert(dot) {
769 return Err(CrdtError::CyclicList);
770 }
771 let element = self
772 .elements
773 .get(&dot)
774 .ok_or(CrdtError::MissingPredecessor)?;
775 current = element.parent;
776 }
777 }
778 Ok(())
779 }
780}
781
782impl<T> Default for OrderedList<T> {
783 fn default() -> Self {
784 Self::new()
785 }
786}
787
788impl<T: Clone + Eq> Merge for OrderedList<T> {
789 fn merge(&mut self, other: &Self) -> Result<(), CrdtError> {
790 for (&dot, other_element) in &other.elements {
791 if let Some(element) = self.elements.get_mut(&dot) {
792 if element.parent != other_element.parent || element.value != other_element.value {
793 return Err(CrdtError::ConflictingDot);
794 }
795 element.removed |= other_element.removed;
796 } else {
797 self.elements.insert(dot, other_element.clone());
798 }
799 }
800 if self.elements.values().any(|element| {
801 element
802 .parent
803 .is_some_and(|parent| !self.elements.contains_key(&parent))
804 }) {
805 return Err(CrdtError::MissingPredecessor);
806 }
807 self.validate_structure()?;
808 Ok(())
809 }
810}
811
812fn allocate_dot(
813 author: AuthorId,
814 sequence: u64,
815 next_operation: &mut u32,
816) -> Result<Dot, CrdtError> {
817 let operation = *next_operation;
818 *next_operation = next_operation
819 .checked_add(1)
820 .ok_or(CrdtError::OperationIndexExhausted)?;
821 Ok(Dot::new(author, sequence, operation))
822}