1use super::{CRDT, Mergeable, ReplicaId};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::error::Error;
5use uuid::Uuid;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct ListError {
10 message: String,
11}
12
13impl ListError {
14 pub fn new(message: String) -> Self {
15 Self { message }
16 }
17}
18
19impl std::fmt::Display for ListError {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 write!(f, "ListError: {}", self.message)
22 }
23}
24
25impl Error for ListError {}
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
29pub struct ElementId {
30 pub id: Uuid,
32 pub replica: ReplicaId,
34}
35
36impl ElementId {
37 pub fn new(replica: ReplicaId) -> Self {
39 Self {
40 id: Uuid::new_v4(),
41 replica,
42 }
43 }
44
45 pub fn from_parts(id: Uuid, replica: ReplicaId) -> Self {
47 Self { id, replica }
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
53pub struct ElementMetadata {
54 pub created_at: u64,
56 pub modified_at: u64,
58 pub deleted: bool,
60 pub last_modified_by: ReplicaId,
62}
63
64impl ElementMetadata {
65 pub fn new(replica: ReplicaId, timestamp: u64) -> Self {
67 Self {
68 created_at: timestamp,
69 modified_at: timestamp,
70 deleted: false,
71 last_modified_by: replica,
72 }
73 }
74
75 pub fn mark_modified(&mut self, replica: ReplicaId, timestamp: u64) {
77 self.modified_at = timestamp;
78 self.last_modified_by = replica;
79 }
80
81 pub fn mark_deleted(&mut self, replica: ReplicaId, timestamp: u64) {
83 self.deleted = true;
84 self.mark_modified(replica, timestamp);
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
90pub struct ListElement<T> {
91 pub id: ElementId,
93 pub value: T,
95 pub metadata: ElementMetadata,
97}
98
99impl<T> ListElement<T> {
100 pub fn new(value: T, replica: ReplicaId, timestamp: u64) -> Self {
102 Self {
103 id: ElementId::new(replica),
104 value,
105 metadata: ElementMetadata::new(replica, timestamp),
106 }
107 }
108
109 pub fn mark_modified(&mut self, replica: ReplicaId, timestamp: u64) {
111 self.metadata.mark_modified(replica, timestamp);
112 }
113
114 pub fn mark_deleted(&mut self, replica: ReplicaId, timestamp: u64) {
116 self.metadata.mark_deleted(replica, timestamp);
117 }
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
122pub enum ListStrategy {
123 AddWins,
125 RemoveWins,
127 LastWriteWins,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
133pub struct ListConfig {
134 pub strategy: ListStrategy,
136 pub preserve_deleted: bool,
138 pub max_elements: Option<usize>,
140}
141
142impl Default for ListConfig {
143 fn default() -> Self {
144 Self {
145 strategy: ListStrategy::AddWins,
146 preserve_deleted: true,
147 max_elements: None,
148 }
149 }
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
157pub struct AddWinsList<T> {
158 config: ListConfig,
160 elements: HashMap<ElementId, ListElement<T>>,
162 replica: ReplicaId,
164}
165
166impl<T: Clone + PartialEq + Eq + Send + Sync> AddWinsList<T> {
167 pub fn new(replica: ReplicaId) -> Self {
169 Self {
170 config: ListConfig::default(),
171 elements: HashMap::new(),
172 replica,
173 }
174 }
175
176 pub fn with_config(replica: ReplicaId, config: ListConfig) -> Self {
178 Self {
179 config,
180 elements: HashMap::new(),
181 replica,
182 }
183 }
184
185 pub fn add(&mut self, value: T, timestamp: u64) -> ElementId {
187 let element = ListElement::new(value, self.replica, timestamp);
188 let id = element.id.clone();
189 self.elements.insert(id.clone(), element);
190 id
191 }
192
193 pub fn update(&mut self, id: &ElementId, value: T, timestamp: u64) -> Result<(), ListError> {
195 if let Some(element) = self.elements.get_mut(id) {
196 element.value = value;
197 element.mark_modified(self.replica, timestamp);
198 Ok(())
199 } else {
200 Err(ListError::new("Element not found".to_string()))
201 }
202 }
203
204 pub fn remove(&mut self, id: &ElementId, timestamp: u64) -> Result<(), ListError> {
206 if let Some(element) = self.elements.get_mut(id) {
207 element.mark_deleted(self.replica, timestamp);
208 Ok(())
209 } else {
210 Err(ListError::new("Element not found".to_string()))
211 }
212 }
213
214 pub fn get(&self, id: &ElementId) -> Option<&ListElement<T>> {
216 self.elements.get(id)
217 }
218
219 pub fn visible_elements(&self) -> Vec<&ListElement<T>> {
221 self.elements
222 .values()
223 .filter(|e| !e.metadata.deleted)
224 .collect()
225 }
226
227 pub fn all_elements(&self) -> Vec<&ListElement<T>> {
229 self.elements.values().collect()
230 }
231
232 pub fn contains(&self, id: &ElementId) -> bool {
234 self.elements.contains_key(id)
235 }
236
237 pub fn len(&self) -> usize {
239 self.visible_elements().len()
240 }
241
242 pub fn is_empty(&self) -> bool {
244 self.len() == 0
245 }
246
247 pub fn clear(&mut self) {
249 self.elements.clear();
250 }
251}
252
253impl<T: Clone + PartialEq + Eq + Send + Sync> CRDT for AddWinsList<T> {
254 fn replica_id(&self) -> &ReplicaId {
255 &self.replica
256 }
257}
258
259impl<T: Clone + PartialEq + Eq + Send + Sync> Mergeable for AddWinsList<T> {
260 type Error = ListError;
261
262 fn merge(&mut self, other: &Self) -> Result<(), Self::Error> {
263 for (id, element) in &other.elements {
264 match self.elements.get(id) {
265 Some(existing) => {
266 if element.metadata.modified_at > existing.metadata.modified_at {
268 self.elements.insert(id.clone(), element.clone());
269 }
270 }
271 None => {
272 self.elements.insert(id.clone(), element.clone());
274 }
275 }
276 }
277 Ok(())
278 }
279
280 fn has_conflict(&self, other: &Self) -> bool {
281 for (id, element) in &other.elements {
282 if let Some(existing) = self.elements.get(id) {
283 if element.metadata.modified_at == existing.metadata.modified_at
285 && element.metadata.last_modified_by != existing.metadata.last_modified_by
286 {
287 return true;
288 }
289 }
290 }
291 false
292 }
293}
294
295#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
300pub struct RemoveWinsList<T> {
301 config: ListConfig,
303 elements: HashMap<ElementId, ListElement<T>>,
305 replica: ReplicaId,
307}
308
309impl<T: Clone + PartialEq + Eq + Send + Sync> RemoveWinsList<T> {
310 pub fn new(replica: ReplicaId) -> Self {
312 Self {
313 config: ListConfig {
314 strategy: ListStrategy::RemoveWins,
315 preserve_deleted: false,
316 max_elements: None,
317 },
318 elements: HashMap::new(),
319 replica,
320 }
321 }
322
323 pub fn with_config(replica: ReplicaId, config: ListConfig) -> Self {
325 Self {
326 config,
327 elements: HashMap::new(),
328 replica,
329 }
330 }
331
332 pub fn add(&mut self, value: T, timestamp: u64) -> ElementId {
334 let element = ListElement::new(value, self.replica, timestamp);
335 let id = element.id.clone();
336 self.elements.insert(id.clone(), element);
337 id
338 }
339
340 pub fn update(&mut self, id: &ElementId, value: T, timestamp: u64) -> Result<(), ListError> {
342 if let Some(element) = self.elements.get_mut(id) {
343 element.value = value;
344 element.mark_modified(self.replica, timestamp);
345 Ok(())
346 } else {
347 Err(ListError::new("Element not found".to_string()))
348 }
349 }
350
351 pub fn remove(&mut self, id: &ElementId) -> Result<(), ListError> {
353 if self.elements.remove(id).is_some() {
354 Ok(())
355 } else {
356 Err(ListError::new("Element not found".to_string()))
357 }
358 }
359
360 pub fn get(&self, id: &ElementId) -> Option<&ListElement<T>> {
362 self.elements.get(id)
363 }
364
365 pub fn elements(&self) -> Vec<&ListElement<T>> {
367 self.elements.values().collect()
368 }
369
370 pub fn contains(&self, id: &ElementId) -> bool {
372 self.elements.contains_key(id)
373 }
374
375 pub fn len(&self) -> usize {
377 self.elements.len()
378 }
379
380 pub fn is_empty(&self) -> bool {
382 self.elements.is_empty()
383 }
384
385 pub fn clear(&mut self) {
387 self.elements.clear();
388 }
389}
390
391impl<T: Clone + PartialEq + Eq + Send + Sync> CRDT for RemoveWinsList<T> {
392 fn replica_id(&self) -> &ReplicaId {
393 &self.replica
394 }
395}
396
397impl<T: Clone + PartialEq + Eq + Send + Sync> Mergeable for RemoveWinsList<T> {
398 type Error = ListError;
399
400 fn merge(&mut self, other: &Self) -> Result<(), Self::Error> {
401 for (id, element) in &other.elements {
402 match self.elements.get(id) {
403 Some(existing) => {
404 if element.metadata.modified_at > existing.metadata.modified_at {
406 self.elements.insert(id.clone(), element.clone());
407 }
408 }
409 None => {
410 self.elements.insert(id.clone(), element.clone());
412 }
413 }
414 }
415 Ok(())
416 }
417
418 fn has_conflict(&self, other: &Self) -> bool {
419 for (id, element) in &other.elements {
420 if let Some(existing) = self.elements.get(id) {
421 if element.metadata.modified_at == existing.metadata.modified_at
423 && element.metadata.last_modified_by != existing.metadata.last_modified_by
424 {
425 return true;
426 }
427 }
428 }
429 false
430 }
431}
432
433#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
438pub struct LwwList<T> {
439 config: ListConfig,
441 elements: HashMap<ElementId, ListElement<T>>,
443 replica: ReplicaId,
445}
446
447impl<T: Clone + PartialEq + Eq + Send + Sync> LwwList<T> {
448 pub fn new(replica: ReplicaId) -> Self {
450 Self {
451 config: ListConfig {
452 strategy: ListStrategy::LastWriteWins,
453 preserve_deleted: true,
454 max_elements: None,
455 },
456 elements: HashMap::new(),
457 replica,
458 }
459 }
460
461 pub fn with_config(replica: ReplicaId, config: ListConfig) -> Self {
463 Self {
464 config,
465 elements: HashMap::new(),
466 replica,
467 }
468 }
469
470 pub fn add(&mut self, value: T, timestamp: u64) -> ElementId {
472 let element = ListElement::new(value, self.replica, timestamp);
473 let id = element.id.clone();
474 self.elements.insert(id.clone(), element);
475 id
476 }
477
478 pub fn update(&mut self, id: &ElementId, value: T, timestamp: u64) -> Result<(), ListError> {
480 if let Some(element) = self.elements.get_mut(id) {
481 element.value = value;
482 element.mark_modified(self.replica, timestamp);
483 Ok(())
484 } else {
485 Err(ListError::new("Element not found".to_string()))
486 }
487 }
488
489 pub fn remove(&mut self, id: &ElementId, timestamp: u64) -> Result<(), ListError> {
491 if let Some(element) = self.elements.get_mut(id) {
492 element.mark_deleted(self.replica, timestamp);
493 Ok(())
494 } else {
495 Err(ListError::new("Element not found".to_string()))
496 }
497 }
498
499 pub fn get(&self, id: &ElementId) -> Option<&ListElement<T>> {
501 self.elements.get(id)
502 }
503
504 pub fn visible_elements(&self) -> Vec<&ListElement<T>> {
506 self.elements
507 .values()
508 .filter(|e| !e.metadata.deleted)
509 .collect()
510 }
511
512 pub fn all_elements(&self) -> Vec<&ListElement<T>> {
514 self.elements.values().collect()
515 }
516
517 pub fn contains(&self, id: &ElementId) -> bool {
519 self.elements.contains_key(id)
520 }
521
522 pub fn len(&self) -> usize {
524 self.visible_elements().len()
525 }
526
527 pub fn is_empty(&self) -> bool {
529 self.len() == 0
530 }
531
532 pub fn clear(&mut self) {
534 self.elements.clear();
535 }
536}
537
538impl<T: Clone + PartialEq + Eq + Send + Sync> CRDT for LwwList<T> {
539 fn replica_id(&self) -> &ReplicaId {
540 &self.replica
541 }
542}
543
544impl<T: Clone + PartialEq + Eq + Send + Sync> Mergeable for LwwList<T> {
545 type Error = ListError;
546
547 fn merge(&mut self, other: &Self) -> Result<(), Self::Error> {
548 for (id, element) in &other.elements {
549 match self.elements.get(id) {
550 Some(existing) => {
551 if element.metadata.modified_at > existing.metadata.modified_at {
553 self.elements.insert(id.clone(), element.clone());
554 }
555 }
556 None => {
557 self.elements.insert(id.clone(), element.clone());
559 }
560 }
561 }
562 Ok(())
563 }
564
565 fn has_conflict(&self, other: &Self) -> bool {
566 for (id, element) in &other.elements {
567 if let Some(existing) = self.elements.get(id) {
568 if element.metadata.modified_at == existing.metadata.modified_at
570 && element.metadata.last_modified_by != existing.metadata.last_modified_by
571 {
572 return true;
573 }
574 }
575 }
576 false
577 }
578}
579
580#[cfg(test)]
581mod tests {
582 use super::*;
583 use super::super::ReplicaId;
584 use uuid::Uuid;
585
586 fn create_replica(id: u64) -> ReplicaId {
587 ReplicaId::from(Uuid::from_u64_pair(0, id))
588 }
589
590 #[test]
591 fn test_element_id_creation() {
592 let replica = create_replica(1);
593 let element_id = ElementId::new(replica);
594
595 assert_eq!(element_id.replica, replica);
596 assert_ne!(element_id.id, Uuid::nil());
597 }
598
599 #[test]
600 fn test_list_element_creation() {
601 let replica = create_replica(1);
602 let timestamp = 1234567890;
603 let element = ListElement::new("test_value", replica, timestamp);
604
605 assert_eq!(element.value, "test_value");
606 assert_eq!(element.metadata.created_at, timestamp);
607 assert_eq!(element.metadata.modified_at, timestamp);
608 assert_eq!(element.metadata.deleted, false);
609 assert_eq!(element.metadata.last_modified_by, replica);
610 }
611
612 #[test]
613 fn test_add_wins_list_basic_operations() {
614 let replica = create_replica(1);
615 let mut list = AddWinsList::new(replica);
616
617 let id1 = list.add("first", 1000);
619 let id2 = list.add("second", 2000);
620
621 assert_eq!(list.len(), 2);
622 assert!(list.contains(&id1));
623 assert!(list.contains(&id2));
624
625 list.update(&id1, "updated_first", 3000).unwrap();
627 assert_eq!(list.get(&id1).unwrap().value, "updated_first");
628
629 list.remove(&id2, 4000).unwrap();
631 assert_eq!(list.len(), 1); assert!(list.get(&id2).unwrap().metadata.deleted);
633 }
634
635 #[test]
636 fn test_remove_wins_list_basic_operations() {
637 let replica = create_replica(1);
638 let mut list = RemoveWinsList::new(replica);
639
640 let id1 = list.add("first", 1000);
642 let id2 = list.add("second", 2000);
643
644 assert_eq!(list.len(), 2);
645
646 list.remove(&id2).unwrap();
648 assert_eq!(list.len(), 1);
649 assert!(!list.contains(&id2));
650 }
651
652 #[test]
653 fn test_lww_list_basic_operations() {
654 let replica = create_replica(1);
655 let mut list = LwwList::new(replica);
656
657 let id1 = list.add("first", 1000);
659 let id2 = list.add("second", 2000);
660
661 assert_eq!(list.len(), 2);
662
663 list.update(&id1, "updated_first", 3000).unwrap();
665 assert_eq!(list.get(&id1).unwrap().value, "updated_first");
666
667 list.remove(&id2, 4000).unwrap();
669 assert_eq!(list.len(), 1);
670 assert!(list.get(&id2).unwrap().metadata.deleted);
671 }
672
673 #[test]
674 fn test_list_merge() {
675 let replica1 = create_replica(1);
676 let replica2 = create_replica(2);
677
678 let mut list1 = AddWinsList::new(replica1);
679 let mut list2 = AddWinsList::new(replica2);
680
681 let id1 = list1.add("from_replica1", 1000);
683 let id2 = list2.add("from_replica2", 2000);
684
685 list1.merge(&list2).unwrap();
687
688 assert_eq!(list1.len(), 2);
690 assert!(list1.contains(&id1));
691 assert!(list1.contains(&id2));
692 }
693
694 #[test]
695 fn test_list_merge_conflict_resolution() {
696 let replica1 = create_replica(1);
697 let replica2 = create_replica(2);
698
699 let mut list1 = AddWinsList::new(replica1);
700 let mut list2 = AddWinsList::new(replica2);
701
702 let id = list1.add("value1", 1000);
704 list2.elements.insert(id.clone(), ListElement::new("value2", replica2, 2000));
705
706 list1.merge(&list2).unwrap();
708 assert_eq!(list1.get(&id).unwrap().value, "value2");
709 }
710
711 #[test]
712 fn test_list_configuration() {
713 let replica = create_replica(1);
714 let config = ListConfig {
715 strategy: ListStrategy::RemoveWins,
716 preserve_deleted: false,
717 max_elements: Some(100),
718 };
719
720 let list: AddWinsList<String> = AddWinsList::with_config(replica, config);
721 assert_eq!(list.config.strategy, ListStrategy::RemoveWins);
722 assert_eq!(list.config.max_elements, Some(100));
723 }
724}