1use alloc::collections::BTreeMap;
2
3use crate::{Crdt, DeltaCrdt, NodeId};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub struct GCounter {
28 actor: NodeId,
29 counts: BTreeMap<NodeId, u64>,
30}
31
32impl GCounter {
33 pub fn new(actor: NodeId) -> Self {
35 Self {
36 actor,
37 counts: BTreeMap::new(),
38 }
39 }
40
41 pub fn increment(&mut self) {
43 *self.counts.entry(self.actor).or_insert(0) += 1;
44 }
45
46 pub fn increment_by(&mut self, n: u64) {
48 *self.counts.entry(self.actor).or_insert(0) += n;
49 }
50
51 #[must_use]
53 pub fn value(&self) -> u64 {
54 self.counts.values().sum()
55 }
56
57 #[must_use]
59 pub fn actor(&self) -> NodeId {
60 self.actor
61 }
62
63 #[must_use]
65 pub fn count_for(&self, actor: NodeId) -> u64 {
66 self.counts.get(&actor).copied().unwrap_or(0)
67 }
68}
69
70impl Crdt for GCounter {
71 fn merge(&mut self, other: &Self) {
72 for (&actor, &count) in &other.counts {
73 let entry = self.counts.entry(actor).or_insert(0);
74 *entry = (*entry).max(count);
75 }
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub struct GCounterDelta {
83 counts: BTreeMap<NodeId, u64>,
84}
85
86impl DeltaCrdt for GCounter {
87 type Delta = GCounterDelta;
88
89 fn delta(&self, other: &Self) -> GCounterDelta {
90 let mut counts = BTreeMap::new();
91 for (&actor, &self_count) in &self.counts {
92 let other_count = other.counts.get(&actor).copied().unwrap_or(0);
93 if self_count > other_count {
94 counts.insert(actor, self_count);
95 }
96 }
97 GCounterDelta { counts }
98 }
99
100 fn apply_delta(&mut self, delta: &GCounterDelta) {
101 for (&actor, &count) in &delta.counts {
102 let entry = self.counts.entry(actor).or_insert(0);
103 *entry = (*entry).max(count);
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn new_counter_is_zero() {
114 let c = GCounter::new(1);
115 assert_eq!(c.value(), 0);
116 }
117
118 #[test]
119 fn increment_increases_value() {
120 let mut c = GCounter::new(1);
121 c.increment();
122 assert_eq!(c.value(), 1);
123 c.increment();
124 assert_eq!(c.value(), 2);
125 }
126
127 #[test]
128 fn increment_by() {
129 let mut c = GCounter::new(1);
130 c.increment_by(5);
131 assert_eq!(c.value(), 5);
132 }
133
134 #[test]
135 fn merge_takes_max() {
136 let mut c1 = GCounter::new(1);
137 c1.increment();
138 c1.increment();
139
140 let mut c2 = GCounter::new(1);
141 c2.increment();
142
143 c1.merge(&c2);
144 assert_eq!(c1.value(), 2);
145 }
146
147 #[test]
148 fn merge_different_actors() {
149 let mut c1 = GCounter::new(1);
150 c1.increment();
151
152 let mut c2 = GCounter::new(2);
153 c2.increment();
154 c2.increment();
155
156 c1.merge(&c2);
157 assert_eq!(c1.value(), 3);
158 }
159
160 #[test]
161 fn merge_is_commutative() {
162 let mut c1 = GCounter::new(1);
163 c1.increment();
164
165 let mut c2 = GCounter::new(2);
166 c2.increment();
167 c2.increment();
168
169 let mut left = c1.clone();
170 left.merge(&c2);
171
172 let mut right = c2.clone();
173 right.merge(&c1);
174
175 assert_eq!(left.value(), right.value());
176 }
177
178 #[test]
179 fn merge_is_idempotent() {
180 let mut c1 = GCounter::new(1);
181 c1.increment();
182
183 let mut c2 = GCounter::new(2);
184 c2.increment();
185
186 c1.merge(&c2);
187 let after_first = c1.clone();
188 c1.merge(&c2);
189
190 assert_eq!(c1, after_first);
191 }
192
193 #[test]
194 fn count_for_actor() {
195 let mut c = GCounter::new(1);
196 c.increment();
197 c.increment();
198 assert_eq!(c.count_for(1), 2);
199 assert_eq!(c.count_for(2), 0);
200 }
201
202 #[test]
203 fn delta_contains_only_new_entries() {
204 let mut c1 = GCounter::new(1);
205 c1.increment();
206 c1.increment();
207
208 let mut c2 = GCounter::new(2);
209 c2.increment();
210
211 let d = c1.delta(&c2);
212 assert_eq!(d.counts.get(&1), Some(&2));
213 assert!(!d.counts.contains_key(&2));
214 }
215
216 #[test]
217 fn apply_delta_updates_state() {
218 let mut c1 = GCounter::new(1);
219 c1.increment();
220 c1.increment();
221
222 let mut c2 = GCounter::new(2);
223 c2.increment();
224
225 let d = c1.delta(&c2);
226 c2.apply_delta(&d);
227 assert_eq!(c2.value(), 3);
228 }
229
230 #[test]
231 fn delta_is_empty_when_equal() {
232 let mut c1 = GCounter::new(1);
233 c1.increment();
234
235 let c2 = c1.clone();
236 let d = c1.delta(&c2);
237 assert!(d.counts.is_empty());
238 }
239
240 #[test]
241 fn delta_equivalent_to_full_merge() {
242 let mut c1 = GCounter::new(1);
243 c1.increment();
244 c1.increment();
245
246 let mut c2 = GCounter::new(2);
247 c2.increment();
248
249 let mut full = c2.clone();
250 full.merge(&c1);
251
252 let mut via_delta = c2.clone();
253 let d = c1.delta(&c2);
254 via_delta.apply_delta(&d);
255
256 assert_eq!(full.value(), via_delta.value());
257 }
258}