1mod system_clock;
2
3use smallvec::SmallVec;
4use std::{
5 cmp::{self, Ordering},
6 fmt, iter,
7};
8
9pub use system_clock::*;
10
11/// A unique identifier for each distributed node.
12pub type ReplicaId = u16;
13
14/// A [Lamport sequence number](https://en.wikipedia.org/wiki/Lamport_timestamp).
15pub type Seq = u32;
16
17/// A [Lamport timestamp](https://en.wikipedia.org/wiki/Lamport_timestamp),
18/// used to determine the ordering of events in the editor.
19#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
20pub struct Lamport {
21 pub replica_id: ReplicaId,
22 pub value: Seq,
23}
24
25/// A [vector clock](https://en.wikipedia.org/wiki/Vector_clock).
26#[derive(Clone, Default, Hash, Eq, PartialEq)]
27pub struct Global(SmallVec<[u32; 8]>);
28
29impl Global {
30 pub fn new() -> Self {
31 Self::default()
32 }
33
34 pub fn get(&self, replica_id: ReplicaId) -> Seq {
35 self.0.get(replica_id as usize).copied().unwrap_or(0) as Seq
36 }
37
38 pub fn observe(&mut self, timestamp: Lamport) {
39 if timestamp.value > 0 {
40 let new_len = timestamp.replica_id as usize + 1;
41 if new_len > self.0.len() {
42 self.0.resize(new_len, 0);
43 }
44
45 let entry = &mut self.0[timestamp.replica_id as usize];
46 *entry = cmp::max(*entry, timestamp.value);
47 }
48 }
49
50 pub fn join(&mut self, other: &Self) {
51 if other.0.len() > self.0.len() {
52 self.0.resize(other.0.len(), 0);
53 }
54
55 for (left, right) in self.0.iter_mut().zip(&other.0) {
56 *left = cmp::max(*left, *right);
57 }
58 }
59
60 pub fn meet(&mut self, other: &Self) {
61 if other.0.len() > self.0.len() {
62 self.0.resize(other.0.len(), 0);
63 }
64
65 let mut new_len = 0;
66 for (ix, (left, right)) in self
67 .0
68 .iter_mut()
69 .zip(other.0.iter().chain(iter::repeat(&0)))
70 .enumerate()
71 {
72 if *left == 0 {
73 *left = *right;
74 } else if *right > 0 {
75 *left = cmp::min(*left, *right);
76 }
77
78 if *left != 0 {
79 new_len = ix + 1;
80 }
81 }
82 self.0.resize(new_len, 0);
83 }
84
85 pub fn observed(&self, timestamp: Lamport) -> bool {
86 self.get(timestamp.replica_id) >= timestamp.value
87 }
88
89 pub fn observed_any(&self, other: &Self) -> bool {
90 self.0
91 .iter()
92 .zip(other.0.iter())
93 .any(|(left, right)| *right > 0 && left >= right)
94 }
95
96 pub fn observed_all(&self, other: &Self) -> bool {
97 let mut rhs = other.0.iter();
98 self.0.iter().all(|left| match rhs.next() {
99 Some(right) => left >= right,
100 None => true,
101 }) && rhs.next().is_none()
102 }
103
104 pub fn changed_since(&self, other: &Self) -> bool {
105 self.0.len() > other.0.len()
106 || self
107 .0
108 .iter()
109 .zip(other.0.iter())
110 .any(|(left, right)| left > right)
111 }
112
113 pub fn iter(&self) -> impl Iterator<Item = Lamport> + '_ {
114 self.0.iter().enumerate().map(|(replica_id, seq)| Lamport {
115 replica_id: replica_id as ReplicaId,
116 value: *seq,
117 })
118 }
119}
120
121impl FromIterator<Lamport> for Global {
122 fn from_iter<T: IntoIterator<Item = Lamport>>(locals: T) -> Self {
123 let mut result = Self::new();
124 for local in locals {
125 result.observe(local);
126 }
127 result
128 }
129}
130
131impl Ord for Lamport {
132 fn cmp(&self, other: &Self) -> Ordering {
133 // Use the replica id to break ties between concurrent events.
134 self.value
135 .cmp(&other.value)
136 .then_with(|| self.replica_id.cmp(&other.replica_id))
137 }
138}
139
140impl PartialOrd for Lamport {
141 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
142 Some(self.cmp(other))
143 }
144}
145
146impl Lamport {
147 pub const MIN: Self = Self {
148 replica_id: ReplicaId::MIN,
149 value: Seq::MIN,
150 };
151
152 pub const MAX: Self = Self {
153 replica_id: ReplicaId::MAX,
154 value: Seq::MAX,
155 };
156
157 pub fn new(replica_id: ReplicaId) -> Self {
158 Self {
159 value: 1,
160 replica_id,
161 }
162 }
163
164 pub fn tick(&mut self) -> Self {
165 let timestamp = *self;
166 self.value += 1;
167 timestamp
168 }
169
170 pub fn observe(&mut self, timestamp: Self) {
171 self.value = cmp::max(self.value, timestamp.value) + 1;
172 }
173}
174
175impl fmt::Debug for Lamport {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 write!(f, "Lamport {{{}: {}}}", self.replica_id, self.value)
178 }
179}
180
181impl fmt::Debug for Global {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 write!(f, "Global {{")?;
184 for timestamp in self.iter() {
185 if timestamp.replica_id > 0 {
186 write!(f, ", ")?;
187 }
188 write!(f, "{}: {}", timestamp.replica_id, timestamp.value)?;
189 }
190 write!(f, "}}")
191 }
192}