1use std::collections::BTreeMap;
2
3use crate::Crdt;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct GCounter {
27 actor: String,
28 counts: BTreeMap<String, u64>,
29}
30
31impl GCounter {
32 pub fn new(actor: impl Into<String>) -> Self {
34 Self {
35 actor: actor.into(),
36 counts: BTreeMap::new(),
37 }
38 }
39
40 pub fn increment(&mut self) {
42 *self.counts.entry(self.actor.clone()).or_insert(0) += 1;
43 }
44
45 pub fn increment_by(&mut self, n: u64) {
47 *self.counts.entry(self.actor.clone()).or_insert(0) += n;
48 }
49
50 #[must_use]
52 pub fn value(&self) -> u64 {
53 self.counts.values().sum()
54 }
55
56 #[must_use]
58 pub fn actor(&self) -> &str {
59 &self.actor
60 }
61
62 #[must_use]
64 pub fn count_for(&self, actor: &str) -> u64 {
65 self.counts.get(actor).copied().unwrap_or(0)
66 }
67}
68
69impl Crdt for GCounter {
70 fn merge(&mut self, other: &Self) {
71 for (actor, &count) in &other.counts {
72 let entry = self.counts.entry(actor.clone()).or_insert(0);
73 *entry = (*entry).max(count);
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn new_counter_is_zero() {
84 let c = GCounter::new("a");
85 assert_eq!(c.value(), 0);
86 }
87
88 #[test]
89 fn increment_increases_value() {
90 let mut c = GCounter::new("a");
91 c.increment();
92 assert_eq!(c.value(), 1);
93 c.increment();
94 assert_eq!(c.value(), 2);
95 }
96
97 #[test]
98 fn increment_by() {
99 let mut c = GCounter::new("a");
100 c.increment_by(5);
101 assert_eq!(c.value(), 5);
102 }
103
104 #[test]
105 fn merge_takes_max() {
106 let mut c1 = GCounter::new("a");
107 c1.increment();
108 c1.increment();
109
110 let mut c2 = GCounter::new("a");
111 c2.increment();
112
113 c1.merge(&c2);
115 assert_eq!(c1.value(), 2);
116 }
117
118 #[test]
119 fn merge_different_actors() {
120 let mut c1 = GCounter::new("a");
121 c1.increment();
122
123 let mut c2 = GCounter::new("b");
124 c2.increment();
125 c2.increment();
126
127 c1.merge(&c2);
128 assert_eq!(c1.value(), 3);
129 }
130
131 #[test]
132 fn merge_is_commutative() {
133 let mut c1 = GCounter::new("a");
134 c1.increment();
135
136 let mut c2 = GCounter::new("b");
137 c2.increment();
138 c2.increment();
139
140 let mut left = c1.clone();
141 left.merge(&c2);
142
143 let mut right = c2.clone();
144 right.merge(&c1);
145
146 assert_eq!(left.value(), right.value());
147 }
148
149 #[test]
150 fn merge_is_idempotent() {
151 let mut c1 = GCounter::new("a");
152 c1.increment();
153
154 let mut c2 = GCounter::new("b");
155 c2.increment();
156
157 c1.merge(&c2);
158 let after_first = c1.clone();
159 c1.merge(&c2);
160
161 assert_eq!(c1, after_first);
162 }
163
164 #[test]
165 fn count_for_actor() {
166 let mut c = GCounter::new("a");
167 c.increment();
168 c.increment();
169 assert_eq!(c.count_for("a"), 2);
170 assert_eq!(c.count_for("b"), 0);
171 }
172}