1use crdts::quickcheck::{Arbitrary, Gen};
8use serde::{Deserialize, Serialize};
9use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
10
11use crdts::Actor;
12use std::hash::{Hash, Hasher};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Clock<A: Actor> {
17 actor_id: A,
18 counter: u64,
19}
20
21impl<A: Actor> Clock<A> {
22 pub fn new(actor_id: A, counter: Option<u64>) -> Self {
26 Self {
27 actor_id,
28 counter: counter.unwrap_or(0),
29 }
30 }
31
32 pub fn inc(&self) -> Self {
34 Self::new(self.actor_id.clone(), Some(self.counter.saturating_add(1)))
35 }
36
37 pub fn tick(&mut self) -> Self {
39 self.counter = self.counter.saturating_add(1);
40 self.clone()
41 }
42
43 #[inline]
45 pub fn actor_id(&self) -> &A {
46 &self.actor_id
47 }
48
49 #[inline]
51 pub fn counter(&self) -> u64 {
52 self.counter
53 }
54
55 pub fn merge(&self, other: &Self) -> Self {
58 Self::new(
59 self.actor_id.clone(),
60 Some(std::cmp::max(self.counter, other.counter)),
61 )
62 }
63}
64
65impl<A: Actor> Ord for Clock<A> {
66 fn cmp(&self, other: &Self) -> Ordering {
71 match self.counter.cmp(&other.counter) {
72 Ordering::Equal => self.actor_id.cmp(&other.actor_id),
73 Ordering::Greater => Ordering::Greater,
74 Ordering::Less => Ordering::Less,
75 }
76 }
77}
78
79impl<A: Actor> PartialOrd for Clock<A> {
80 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
81 Some(self.cmp(other))
82 }
83}
84
85impl<A: Actor> PartialEq for Clock<A> {
86 fn eq(&self, other: &Self) -> bool {
87 self.cmp(other) == Ordering::Equal
88 }
89}
90
91impl<A: Actor> Eq for Clock<A> {}
92
93impl<A: Actor> Hash for Clock<A> {
94 fn hash<H: Hasher>(&self, state: &mut H) {
95 self.actor_id.hash(state);
96 self.counter.hash(state);
97 }
98}
99
100impl<A: Actor + Arbitrary> Arbitrary for Clock<A> {
102 fn arbitrary<G: Gen>(g: &mut G) -> Self {
103 Self {
104 actor_id: A::arbitrary(g),
105 counter: u64::arbitrary(g),
106 }
107 }
108
109 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
110 let mut shrunk_clocks = Vec::new();
111 if self.counter > 0 {
112 shrunk_clocks.push(Self::new(self.actor_id.clone(), Some(self.counter - 1)));
113 }
114 Box::new(shrunk_clocks.into_iter())
115 }
116}
117
118#[cfg(test)]
119mod test {
120 use super::*;
121 use quickcheck::quickcheck;
122
123 quickcheck! {
124 fn inc_increments_only_the_counter(clock: Clock<u8>) -> bool {
125 clock.inc() == Clock::new(clock.actor_id, Some(clock.counter + 1))
126 }
127
128 fn test_total_order(a: Clock<u8>, b: Clock<u8>) -> bool {
129 let cmp_ab = a.cmp(&b);
130 let cmp_ba = b.cmp(&a);
131
132 match (cmp_ab, cmp_ba) {
133 (Ordering::Less, Ordering::Greater) => a.counter < b.counter || a.counter == b.counter && a.actor_id < b.actor_id,
134 (Ordering::Greater, Ordering::Less) => a.counter > b.counter || a.counter == b.counter && a.actor_id > b.actor_id,
135 (Ordering::Equal, Ordering::Equal) => a.actor_id == b.actor_id && a.counter == b.counter,
136 _ => false,
137 }
138 }
139
140 fn test_partial_order(a: Clock<u8>, b: Clock<u8>) -> bool {
141 let cmp_ab = a.partial_cmp(&b);
142 let cmp_ba = b.partial_cmp(&a);
143
144 match (cmp_ab, cmp_ba) {
145 (None, None) => a.actor_id != b.actor_id,
146 (Some(Ordering::Less), Some(Ordering::Greater)) => a.counter < b.counter || a.counter == b.counter && a.actor_id < b.actor_id,
147 (Some(Ordering::Greater), Some(Ordering::Less)) => a.counter > b.counter || a.counter == b.counter && a.actor_id > b.actor_id,
148 (Some(Ordering::Equal), Some(Ordering::Equal)) => a.actor_id == b.actor_id && a.counter == b.counter,
149 _ => false
150 }
151 }
152 }
153}