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