1use crate::{Crdt, DeltaCrdt, GCounter, GCounterDelta, NodeId};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub struct PNCounter {
29 increments: GCounter,
30 decrements: GCounter,
31}
32
33impl PNCounter {
34 pub fn new(actor: NodeId) -> Self {
36 Self {
37 increments: GCounter::new(actor),
38 decrements: GCounter::new(actor),
39 }
40 }
41
42 pub fn increment(&mut self) {
44 self.increments.increment();
45 }
46
47 pub fn decrement(&mut self) {
49 self.decrements.increment();
50 }
51
52 #[must_use]
54 pub fn value(&self) -> i64 {
55 self.increments.value() as i64 - self.decrements.value() as i64
56 }
57}
58
59impl Crdt for PNCounter {
60 fn merge(&mut self, other: &Self) {
61 self.increments.merge(&other.increments);
62 self.decrements.merge(&other.decrements);
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
69pub struct PNCounterDelta {
70 increments: GCounterDelta,
71 decrements: GCounterDelta,
72}
73
74impl DeltaCrdt for PNCounter {
75 type Delta = PNCounterDelta;
76
77 fn delta(&self, other: &Self) -> PNCounterDelta {
78 PNCounterDelta {
79 increments: self.increments.delta(&other.increments),
80 decrements: self.decrements.delta(&other.decrements),
81 }
82 }
83
84 fn apply_delta(&mut self, delta: &PNCounterDelta) {
85 self.increments.apply_delta(&delta.increments);
86 self.decrements.apply_delta(&delta.decrements);
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn new_counter_is_zero() {
96 let c = PNCounter::new(1);
97 assert_eq!(c.value(), 0);
98 }
99
100 #[test]
101 fn increment_and_decrement() {
102 let mut c = PNCounter::new(1);
103 c.increment();
104 c.increment();
105 c.decrement();
106 assert_eq!(c.value(), 1);
107 }
108
109 #[test]
110 fn can_go_negative() {
111 let mut c = PNCounter::new(1);
112 c.decrement();
113 c.decrement();
114 assert_eq!(c.value(), -2);
115 }
116
117 #[test]
118 fn merge_different_actors() {
119 let mut c1 = PNCounter::new(1);
120 c1.increment();
121 c1.increment();
122
123 let mut c2 = PNCounter::new(2);
124 c2.decrement();
125
126 c1.merge(&c2);
127 assert_eq!(c1.value(), 1);
128 }
129
130 #[test]
131 fn merge_is_commutative() {
132 let mut c1 = PNCounter::new(1);
133 c1.increment();
134
135 let mut c2 = PNCounter::new(2);
136 c2.decrement();
137 c2.decrement();
138
139 let mut left = c1.clone();
140 left.merge(&c2);
141
142 let mut right = c2.clone();
143 right.merge(&c1);
144
145 assert_eq!(left.value(), right.value());
146 }
147
148 #[test]
149 fn merge_is_idempotent() {
150 let mut c1 = PNCounter::new(1);
151 c1.increment();
152
153 let mut c2 = PNCounter::new(2);
154 c2.decrement();
155
156 c1.merge(&c2);
157 let after_first = c1.clone();
158 c1.merge(&c2);
159
160 assert_eq!(c1, after_first);
161 }
162
163 #[test]
164 fn delta_apply_equivalent_to_merge() {
165 let mut c1 = PNCounter::new(1);
166 c1.increment();
167 c1.increment();
168 c1.decrement();
169
170 let mut c2 = PNCounter::new(2);
171 c2.decrement();
172
173 let mut full = c2.clone();
174 full.merge(&c1);
175
176 let mut via_delta = c2.clone();
177 let d = c1.delta(&c2);
178 via_delta.apply_delta(&d);
179
180 assert_eq!(full.value(), via_delta.value());
181 }
182}