leptos_sync_core/crdt/advanced/
yjs_tree.rs1use super::common::{PositionId, AdvancedCrdtError};
4use super::super::{CRDT, Mergeable, ReplicaId};
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct YjsNode<T> {
11 pub id: PositionId,
13 pub value: T,
15 pub parent: Option<PositionId>,
17 pub children: Vec<PositionId>,
19 pub visible: bool,
21}
22
23impl<T> YjsNode<T> {
24 pub fn new(id: PositionId, value: T, parent: Option<PositionId>) -> Self {
26 Self {
27 id,
28 value,
29 parent,
30 children: Vec::new(),
31 visible: true,
32 }
33 }
34}
35
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
38pub struct YjsTreeNode<T> {
39 pub id: PositionId,
41 pub value: T,
43 pub children: Vec<YjsTreeNode<T>>,
45}
46
47#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
49pub struct YjsTree<T> {
50 replica_id: ReplicaId,
52 nodes: HashMap<PositionId, YjsNode<T>>,
54 root: Option<PositionId>,
56 timestamp_counter: u64,
58 disambiguation_counter: u64,
60}
61
62impl<T: Clone + PartialEq> YjsTree<T> {
63 pub fn new(replica_id: ReplicaId) -> Self {
65 Self {
66 replica_id,
67 nodes: HashMap::new(),
68 root: None,
69 timestamp_counter: 0,
70 disambiguation_counter: 0,
71 }
72 }
73
74 pub fn add_root(&mut self, value: T) -> Result<PositionId, AdvancedCrdtError> {
76 self.timestamp_counter += 1;
77 self.disambiguation_counter += 1;
78
79 let id = PositionId::new(
80 self.replica_id.clone(),
81 self.timestamp_counter,
82 self.disambiguation_counter,
83 );
84
85 let node = YjsNode::new(id.clone(), value, None);
86 self.nodes.insert(id.clone(), node);
87 self.root = Some(id.clone());
88
89 Ok(id)
90 }
91
92 pub fn add_child(&mut self, parent_id: &PositionId, value: T) -> Result<PositionId, AdvancedCrdtError> {
94 if !self.nodes.contains_key(parent_id) {
95 return Err(AdvancedCrdtError::ElementNotFound(format!("Parent {:?}", parent_id)));
96 }
97
98 self.timestamp_counter += 1;
99 self.disambiguation_counter += 1;
100
101 let id = PositionId::new(
102 self.replica_id.clone(),
103 self.timestamp_counter,
104 self.disambiguation_counter,
105 );
106
107 let node = YjsNode::new(id.clone(), value, Some(parent_id.clone()));
108 self.nodes.insert(id.clone(), node);
109
110 if let Some(parent) = self.nodes.get_mut(parent_id) {
112 parent.children.push(id.clone());
113 }
114
115 Ok(id)
116 }
117
118 pub fn delete(&mut self, node_id: &PositionId) -> Result<(), AdvancedCrdtError> {
120 if let Some(node) = self.nodes.get_mut(node_id) {
121 node.visible = false;
122 Ok(())
123 } else {
124 Err(AdvancedCrdtError::ElementNotFound(format!("Node {:?}", node_id)))
125 }
126 }
127
128 pub fn to_tree(&self) -> Option<YjsTreeNode<T>> {
130 if let Some(root_id) = &self.root {
131 self.build_tree_node(root_id)
132 } else {
133 None
134 }
135 }
136
137 fn build_tree_node(&self, node_id: &PositionId) -> Option<YjsTreeNode<T>> {
139 if let Some(node) = self.nodes.get(node_id) {
140 if !node.visible {
141 return None;
142 }
143
144 let children: Vec<YjsTreeNode<T>> = node.children
145 .iter()
146 .filter_map(|child_id| self.build_tree_node(child_id))
147 .collect();
148
149 Some(YjsTreeNode {
150 id: node.id.clone(),
151 value: node.value.clone(),
152 children,
153 })
154 } else {
155 None
156 }
157 }
158
159 pub fn len(&self) -> usize {
161 self.nodes.len()
162 }
163
164 pub fn is_empty(&self) -> bool {
166 self.nodes.is_empty()
167 }
168}
169
170impl<T: Clone + PartialEq> CRDT for YjsTree<T> {
171 fn replica_id(&self) -> &ReplicaId {
172 &self.replica_id
173 }
174}
175
176impl<T: Clone + PartialEq + Send + Sync> Mergeable for YjsTree<T> {
177 type Error = AdvancedCrdtError;
178
179 fn merge(&mut self, other: &Self) -> Result<(), Self::Error> {
180 for (node_id, other_node) in &other.nodes {
182 if let Some(self_node) = self.nodes.get_mut(node_id) {
183 if other_node.id.timestamp > self_node.id.timestamp {
185 *self_node = other_node.clone();
186 }
187 } else {
188 self.nodes.insert(node_id.clone(), other_node.clone());
190 }
191 }
192
193 if let Some(other_root) = &other.root {
195 if self.root.is_none() {
196 self.root = Some(other_root.clone());
197 } else if let Some(self_root) = &self.root {
198 if let (Some(other_root_node), Some(self_root_node)) = (
199 other.nodes.get(other_root),
200 self.nodes.get(self_root)
201 ) {
202 if other_root_node.id.timestamp > self_root_node.id.timestamp {
203 self.root = Some(other_root.clone());
204 }
205 }
206 }
207 }
208
209 Ok(())
210 }
211
212 fn has_conflict(&self, other: &Self) -> bool {
213 for (node_id, self_node) in &self.nodes {
215 if let Some(other_node) = other.nodes.get(node_id) {
216 if self_node.value != other_node.value {
217 return true;
218 }
219 }
220 }
221 false
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228 use super::super::super::ReplicaId;
229 use uuid::Uuid;
230
231 fn create_replica(id: u64) -> ReplicaId {
232 ReplicaId::from(Uuid::from_u64_pair(0, id))
233 }
234
235 #[test]
236 fn test_yjs_tree_creation() {
237 let replica_id = create_replica(1);
238 let tree = YjsTree::<String>::new(replica_id.clone());
239
240 assert_eq!(tree.replica_id(), &replica_id);
241 assert!(tree.is_empty());
242 assert_eq!(tree.len(), 0);
243 }
244
245 #[test]
246 fn test_yjs_tree_operations() {
247 let replica_id = create_replica(1);
248 let mut tree = YjsTree::<String>::new(replica_id);
249
250 let root_id = tree.add_root("root".to_string()).unwrap();
252 assert_eq!(tree.len(), 1);
253
254 let child1_id = tree.add_child(&root_id, "child1".to_string()).unwrap();
256 let child2_id = tree.add_child(&root_id, "child2".to_string()).unwrap();
257 assert_eq!(tree.len(), 3);
258
259 let grandchild_id = tree.add_child(&child1_id, "grandchild".to_string()).unwrap();
261 assert_eq!(tree.len(), 4);
262
263 tree.delete(&child2_id).unwrap();
265 assert_eq!(tree.len(), 4); let tree_structure = tree.to_tree().unwrap();
269 assert_eq!(tree_structure.value, "root");
270 assert_eq!(tree_structure.children.len(), 1); assert_eq!(tree_structure.children[0].value, "child1");
272 assert_eq!(tree_structure.children[0].children.len(), 1);
273 assert_eq!(tree_structure.children[0].children[0].value, "grandchild");
274 }
275
276 #[test]
277 fn test_yjs_tree_merge() {
278 let replica_id1 = create_replica(1);
279 let replica_id2 = create_replica(2);
280
281 let mut tree1 = YjsTree::<String>::new(replica_id1);
282 let mut tree2 = YjsTree::<String>::new(replica_id2);
283
284 let root1_id = tree1.add_root("root1".to_string()).unwrap();
286 let root2_id = tree2.add_root("root2".to_string()).unwrap();
287
288 tree1.add_child(&root1_id, "child1".to_string()).unwrap();
290 tree2.add_child(&root2_id, "child2".to_string()).unwrap();
291
292 tree1.merge(&tree2).unwrap();
294
295 assert_eq!(tree1.len(), 4); }
298}