leptos_sync_core/crdt/advanced/
lseq.rs1use super::common::{PositionId, AdvancedCrdtError};
4use super::super::{CRDT, Mergeable, ReplicaId};
5use serde::{Deserialize, Serialize};
6use std::collections::BTreeMap;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct LseqElement<T> {
11 pub position: PositionId,
13 pub value: T,
15 pub visible: bool,
17}
18
19impl<T> LseqElement<T> {
20 pub fn new(position: PositionId, value: T) -> Self {
22 Self {
23 position,
24 value,
25 visible: true,
26 }
27 }
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
32pub struct Lseq<T> {
33 replica_id: ReplicaId,
35 elements: BTreeMap<PositionId, LseqElement<T>>,
37 timestamp_counter: u64,
39 disambiguation_counter: u64,
41}
42
43impl<T: Clone + PartialEq> Lseq<T> {
44 pub fn new(replica_id: ReplicaId) -> Self {
46 Self {
47 replica_id,
48 elements: BTreeMap::new(),
49 timestamp_counter: 0,
50 disambiguation_counter: 0,
51 }
52 }
53
54 pub fn insert(&mut self, value: T, _position: Option<PositionId>) -> Result<PositionId, AdvancedCrdtError> {
56 self.timestamp_counter += 1;
57 self.disambiguation_counter += 1;
58
59 let new_position = PositionId::new(
60 self.replica_id.clone(),
61 self.timestamp_counter,
62 self.disambiguation_counter,
63 );
64
65 let element = LseqElement::new(new_position.clone(), value);
66 self.elements.insert(new_position.clone(), element);
67
68 Ok(new_position)
69 }
70
71 pub fn delete(&mut self, position: &PositionId) -> Result<(), AdvancedCrdtError> {
73 if let Some(element) = self.elements.get_mut(position) {
74 element.visible = false;
75 Ok(())
76 } else {
77 Err(AdvancedCrdtError::ElementNotFound(format!("Position {:?}", position)))
78 }
79 }
80
81 pub fn to_vec(&self) -> Vec<T> {
83 self.elements.values()
84 .filter(|e| e.visible)
85 .map(|e| e.value.clone())
86 .collect()
87 }
88
89 pub fn len(&self) -> usize {
91 self.elements.len()
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.elements.is_empty()
97 }
98
99 pub fn get_elements(&self) -> &BTreeMap<PositionId, LseqElement<T>> {
101 &self.elements
102 }
103}
104
105impl<T: Clone + PartialEq> CRDT for Lseq<T> {
106 fn replica_id(&self) -> &ReplicaId {
107 &self.replica_id
108 }
109}
110
111impl<T: Clone + PartialEq + Send + Sync> Mergeable for Lseq<T> {
112 type Error = AdvancedCrdtError;
113
114 fn merge(&mut self, other: &Self) -> Result<(), Self::Error> {
115 for (position, other_element) in &other.elements {
117 if let Some(self_element) = self.elements.get_mut(position) {
118 if other_element.position.timestamp > self_element.position.timestamp {
120 *self_element = other_element.clone();
121 }
122 } else {
123 self.elements.insert(position.clone(), other_element.clone());
125 }
126 }
127
128 Ok(())
129 }
130
131 fn has_conflict(&self, other: &Self) -> bool {
132 for (position, self_element) in &self.elements {
134 if let Some(other_element) = other.elements.get(position) {
135 if self_element.value != other_element.value {
136 return true;
137 }
138 }
139 }
140 false
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use super::super::super::ReplicaId;
148 use uuid::Uuid;
149
150 fn create_replica(id: u64) -> ReplicaId {
151 ReplicaId::from(Uuid::from_u64_pair(0, id))
152 }
153
154 #[test]
155 fn test_lseq_creation() {
156 let replica_id = create_replica(1);
157 let lseq = Lseq::<String>::new(replica_id.clone());
158
159 assert_eq!(lseq.replica_id(), &replica_id);
160 assert!(lseq.is_empty());
161 assert_eq!(lseq.len(), 0);
162 }
163
164 #[test]
165 fn test_lseq_insert_and_delete() {
166 let replica_id = create_replica(1);
167 let mut lseq = Lseq::<String>::new(replica_id);
168
169 let pos1 = lseq.insert("hello".to_string(), None).unwrap();
171 let pos2 = lseq.insert("world".to_string(), None).unwrap();
172 let pos3 = lseq.insert("!".to_string(), None).unwrap();
173
174 assert_eq!(lseq.len(), 3);
175 let elements = lseq.to_vec();
176 assert!(elements.contains(&"hello".to_string()));
177 assert!(elements.contains(&"world".to_string()));
178 assert!(elements.contains(&"!".to_string()));
179
180 lseq.delete(&pos2).unwrap();
182 let elements = lseq.to_vec();
183 assert!(elements.contains(&"hello".to_string()));
184 assert!(!elements.contains(&"world".to_string()));
185 assert!(elements.contains(&"!".to_string()));
186 }
187
188 #[test]
189 fn test_lseq_merge() {
190 let replica_id1 = create_replica(1);
191 let replica_id2 = create_replica(2);
192
193 let mut lseq1 = Lseq::<String>::new(replica_id1);
194 let mut lseq2 = Lseq::<String>::new(replica_id2);
195
196 lseq1.insert("hello".to_string(), None).unwrap();
198 lseq2.insert("world".to_string(), None).unwrap();
199
200 lseq1.merge(&lseq2).unwrap();
202
203 let elements = lseq1.to_vec();
205 assert!(elements.contains(&"hello".to_string()));
206 assert!(elements.contains(&"world".to_string()));
207 }
208}