safemesh_crdt/crdt/
orset.rs1use crate::{Crdt, MergeError, Mergeable, RecordId, WireError};
6use alloc::{collections::BTreeSet, vec::Vec};
7
8#[derive(Clone, Debug)]
10pub enum OrSetDelta<T, K> {
11 Add { element: T, token: K },
12 Remove { tokens: Vec<K> },
13}
14
15impl<T: PartialEq, K: Ord> PartialEq for OrSetDelta<T, K> {
18 fn eq(&self, other: &Self) -> bool {
19 match (self, other) {
20 (
21 Self::Add {
22 element: a,
23 token: x,
24 },
25 Self::Add {
26 element: b,
27 token: y,
28 },
29 ) => a == b && x == y,
30 (Self::Remove { tokens: a }, Self::Remove { tokens: b }) => {
31 a.iter().collect::<BTreeSet<_>>() == b.iter().collect::<BTreeSet<_>>()
32 }
33 _ => false,
34 }
35 }
36}
37
38impl<T: Eq, K: Ord> Eq for OrSetDelta<T, K> {}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
44pub struct OrSet<T: Ord, K: Ord> {
45 pub(super) adds: BTreeSet<(T, K)>,
46 pub(super) tombstones: BTreeSet<K>,
47}
48
49impl<T: Ord, K: Ord> OrSet<T, K> {
50 pub fn new() -> Self {
51 OrSet {
52 adds: BTreeSet::new(),
53 tombstones: BTreeSet::new(),
54 }
55 }
56
57 pub fn add(&mut self, element: T, token: K) {
58 self.adds.insert((element, token));
59 }
60
61 pub fn apply_remove<I>(&mut self, tokens: I)
62 where
63 I: IntoIterator<Item = K>,
64 {
65 self.tombstones.extend(tokens);
66 }
67
68 pub fn merge(&mut self, other: &Self)
69 where
70 T: Clone,
71 K: Clone,
72 {
73 self.adds.extend(other.adds.iter().cloned());
74 self.tombstones.extend(other.tombstones.iter().cloned());
75 }
76
77 pub fn adds(&self) -> &BTreeSet<(T, K)> {
78 &self.adds
79 }
80
81 pub fn tombstones(&self) -> &BTreeSet<K> {
82 &self.tombstones
83 }
84}
85
86impl<T: Ord + Clone, K: Ord + Clone> OrSet<T, K> {
87 pub fn observed_tokens(&self, element: &T) -> BTreeSet<K> {
89 self.adds
90 .iter()
91 .filter_map(|(candidate, token)| {
92 if candidate == element && !self.tombstones.contains(token) {
93 Some(token.clone())
94 } else {
95 None
96 }
97 })
98 .collect()
99 }
100
101 pub fn contains(&self, element: &T) -> bool {
102 self.adds
103 .iter()
104 .any(|(candidate, token)| candidate == element && !self.tombstones.contains(token))
105 }
106
107 pub fn elements(&self) -> BTreeSet<T> {
108 self.adds
109 .iter()
110 .filter_map(|(element, token)| {
111 if self.tombstones.contains(token) {
112 None
113 } else {
114 Some(element.clone())
115 }
116 })
117 .collect()
118 }
119}
120
121impl<T: Ord, K: Ord> Default for OrSet<T, K> {
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127impl<T: Ord + Clone, K: Ord + Clone> Mergeable for OrSet<T, K> {
128 fn merge(&mut self, other: &Self) -> Result<(), MergeError> {
129 OrSet::merge(self, other);
130 Ok(())
131 }
132}
133
134impl<T: Ord + Clone, K: Ord + Clone> Crdt for OrSet<T, K> {
135 type Delta = OrSetDelta<T, K>;
136
137 fn validate_record(&self, id: RecordId, delta: &Self::Delta) -> Result<(), WireError> {
153 match delta {
154 OrSetDelta::Add { .. } if id.sequence == 0 => Err(WireError::ZeroSequenceAdd {
155 replica: id.replica,
156 }),
157 OrSetDelta::Remove { .. } if id.sequence == 0 => Err(WireError::ZeroSequenceRemove {
158 replica: id.replica,
159 }),
160 _ => Ok(()),
161 }
162 }
163
164 fn apply_delta(&mut self, delta: Self::Delta) {
165 match delta {
166 OrSetDelta::Add { element, token } => self.add(element, token),
167 OrSetDelta::Remove { tokens } => self.apply_remove(tokens),
168 }
169 }
170}