y_octo/doc/common/
state.rs1use std::ops::{Deref, DerefMut};
2
3use super::{
4 Client, ClientMap, Clock, CrdtRead, CrdtReader, CrdtWrite, CrdtWriter, HASHMAP_SAFE_CAPACITY, HashMapExt, Id,
5 JwstCodecResult,
6};
7
8#[derive(Default, Debug, PartialEq, Clone)]
9pub struct StateVector(ClientMap<Clock>);
10
11impl StateVector {
12 pub fn set_max(&mut self, client: Client, clock: Clock) {
13 self.entry(client)
14 .and_modify(|m_clock| {
15 if *m_clock < clock {
16 *m_clock = clock;
17 }
18 })
19 .or_insert(clock);
20 }
21
22 pub fn get(&self, client: &Client) -> Clock {
23 *self.0.get(client).unwrap_or(&0)
24 }
25
26 pub fn contains(&self, id: &Id) -> bool {
27 id.clock <= self.get(&id.client)
28 }
29
30 pub fn set_min(&mut self, client: Client, clock: Clock) {
31 self.entry(client)
32 .and_modify(|m_clock| {
33 if *m_clock > clock {
34 *m_clock = clock;
35 }
36 })
37 .or_insert(clock);
38 }
39
40 pub fn iter(&self) -> impl Iterator<Item = (&Client, &Clock)> {
41 self.0.iter()
42 }
43
44 pub fn merge_with(&mut self, other: &Self) {
45 for (client, clock) in other.iter() {
46 self.set_min(*client, *clock);
47 }
48 }
49}
50
51impl Deref for StateVector {
52 type Target = ClientMap<Clock>;
53
54 fn deref(&self) -> &Self::Target {
55 &self.0
56 }
57}
58
59impl DerefMut for StateVector {
60 fn deref_mut(&mut self) -> &mut Self::Target {
61 &mut self.0
62 }
63}
64
65impl<const N: usize> From<[(Client, Clock); N]> for StateVector {
66 fn from(value: [(Client, Clock); N]) -> Self {
67 let mut map = ClientMap::with_capacity(N);
68
69 for (client, clock) in value {
70 map.insert(client, clock);
71 }
72
73 Self(map)
74 }
75}
76
77impl<R: CrdtReader> CrdtRead<R> for StateVector {
78 fn read(decoder: &mut R) -> JwstCodecResult<Self> {
79 let len = decoder.read_var_u64()? as usize;
80
81 let mut map = ClientMap::with_capacity(len.min(HASHMAP_SAFE_CAPACITY));
83 for _ in 0..len {
84 let client = decoder.read_var_u64()?;
85 let clock = decoder.read_var_u64()?;
86 map.insert(client, clock);
87 }
88
89 map.shrink_to_fit();
90 Ok(Self(map))
91 }
92}
93
94impl<W: CrdtWriter> CrdtWrite<W> for StateVector {
95 fn write(&self, encoder: &mut W) -> JwstCodecResult {
96 encoder.write_var_u64(self.len() as u64)?;
97
98 for (client, clock) in self.iter() {
99 encoder.write_var_u64(*client)?;
100 encoder.write_var_u64(*clock)?;
101 }
102
103 Ok(())
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_state_vector_basic() {
113 let mut state_vector = StateVector::from([(1, 1), (2, 2), (3, 3)]);
114 assert_eq!(state_vector.len(), 3);
115 assert_eq!(state_vector.get(&1), 1);
116
117 state_vector.set_min(1, 0);
118 assert_eq!(state_vector.get(&1), 0);
119
120 state_vector.set_max(1, 4);
121 assert_eq!(state_vector.get(&1), 4);
122
123 state_vector.set_max(4, 1);
125 assert_eq!(state_vector.get(&4), 1);
126
127 assert!(!state_vector.contains(&(1, 5).into()));
129 }
130
131 #[test]
132 fn test_state_vector_merge() {
133 let mut state_vector = StateVector::from([(1, 1), (2, 2), (3, 3)]);
134 let other_state_vector = StateVector::from([(1, 5), (2, 6), (3, 7)]);
135 state_vector.merge_with(&other_state_vector);
136 assert_eq!(state_vector, StateVector::from([(3, 3), (1, 1), (2, 2)]));
137 }
138}