crdt_sample/gcounter.rs
1use std::cmp::max;
2use std::collections::HashMap;
3use std::fmt::Display;
4use std::iter::Sum;
5use std::ops::{Add, AddAssign};
6
7use crate::NodeId;
8
9pub struct GCounter<V>
10 where V: Display + AddAssign + Clone + Copy + for<'v> Sum<&'v V> + Ord + Add<Output=V> + Default,
11{
12 /// The identification number of the delta.
13 pub id: NodeId,
14 // The current state of the counter.
15 pub counter: HashMap<NodeId, V>,
16 /// The default value of V. For example, the default value of i32 is 0.
17 pub default_value: V,
18}
19
20impl<V> GCounter<V>
21 where V: Display + AddAssign + Clone + Copy + for<'v> Sum<&'v V> + Ord + Add<Output = V> + Default,
22{
23 pub fn new(id: NodeId) -> Self {
24 GCounter {
25 id,
26 counter: HashMap::new(),
27 default_value: Default::default(),
28 }
29 }
30 /// Returns the current value of the local counter.
31 pub fn local(&self) -> &V {
32 self.counter.get(&self.id).unwrap_or(&self.default_value)
33 }
34
35 /// Returns the sum of all replica values in the counter.
36 pub fn read(&self) -> V {
37 self.counter.values().sum()
38 }
39
40 /// A mutator that performs an increment of `to_sum` in the counter.
41 ///
42 /// # Example
43 /// ```
44 /// use crdt_sample::{GCounter,NodeId};
45 ///
46 /// let id = NodeId::new(1, "a".to_string());
47 /// let mut gcounter: GCounter<i32> = GCounter::new(id);
48 ///
49 /// gcounter.inc(Some(1));
50 /// let result_local = gcounter.local(); // Reads the local replica
51 /// let result_read = gcounter.read(); // Sum of all counters.
52 /// assert_eq!(*result_local, 1);
53 /// assert_eq!(result_read, 1);
54 /// ```
55 pub fn inc(&mut self, to_sum: Option<V>){
56 let inc_value: V = to_sum.unwrap();
57 self.counter
58 .entry(self.id.clone())
59 .and_modify(|val| *val = max(inc_value.clone() + *val, *val))
60 .or_insert(inc_value);
61 }
62
63 /// Joins the delta_gcounter with a delta or another delta_gcounter.
64 ///
65 /// # Examples
66 /// ```
67 /// use crdt_sample::{GCounter, NodeId};
68 /// let id1 = NodeId::new(1, "a".to_string());
69 /// let id2 = NodeId::new(2, "a".to_string());
70 /// let id3 = NodeId::new(3, "a".to_string());
71 /// let mut gcounter_1: GCounter<i32> = GCounter::new(id1);
72 /// let mut gcounter_2: GCounter<i32> = GCounter::new(id2);
73 /// let mut gcounter_3: GCounter<i32> = GCounter::new(id3);
74 ///
75 /// gcounter_1.inc(Some(3));
76 /// gcounter_2.inc(Some(5));
77 /// gcounter_3.inc(Some(1));
78 ///
79 /// // Join gcounter_1
80 /// gcounter_3.join(&gcounter_1);
81 /// let result_read = gcounter_3.read();
82 /// let result_local = gcounter_3.local();
83 /// assert_eq!(result_read, 4);
84 /// assert_eq!(*result_local, 1);
85 ///
86 /// // join gcounter_2
87 /// gcounter_3.join(&gcounter_2);
88 /// let result_read = gcounter_3.read();
89 /// let result_local = gcounter_3.local();
90 /// assert_eq!(result_read, 9);
91 /// assert_eq!(*result_local, 1);
92 /// ```
93 pub fn join(&mut self, gcounter: &GCounter<V>) {
94 for (key, value) in gcounter.counter.iter() {
95 let gcounter_value = gcounter.counter.get(key).unwrap();
96 let new_value = max(gcounter_value, value);
97 self.counter.insert(key.clone(), new_value.clone());
98 }
99 }
100}
101