leptos_sync_core/crdt/basic/
traits.rs

1//! Core CRDT traits
2
3use super::replica_id::ReplicaId;
4
5/// Trait for types that can be merged with other instances
6pub trait Mergeable: Clone + Send + Sync {
7    type Error: std::error::Error + Send + Sync + 'static + Sized;
8    
9    /// Merge this instance with another instance
10    fn merge(&mut self, other: &Self) -> Result<(), Self::Error>;
11    
12    /// Check if there's a conflict with another instance
13    fn has_conflict(&self, other: &Self) -> bool;
14}
15
16/// Trait for CRDTs that have a replica ID
17pub trait CRDT {
18    fn replica_id(&self) -> &ReplicaId;
19}
20
21#[cfg(test)]
22mod tests {
23    use super::*;
24
25    // Test implementation of the traits
26    #[derive(Debug, Clone, PartialEq)]
27    struct TestCrdt {
28        replica_id: ReplicaId,
29        value: String,
30    }
31
32    impl TestCrdt {
33        fn new(replica_id: ReplicaId, value: String) -> Self {
34            Self { replica_id, value }
35        }
36    }
37
38    impl CRDT for TestCrdt {
39        fn replica_id(&self) -> &ReplicaId {
40            &self.replica_id
41        }
42    }
43
44    impl Mergeable for TestCrdt {
45        type Error = std::io::Error;
46
47        fn merge(&mut self, other: &Self) -> Result<(), Self::Error> {
48            // Simple merge: take the longer string
49            if other.value.len() > self.value.len() {
50                self.value = other.value.clone();
51            }
52            Ok(())
53        }
54
55        fn has_conflict(&self, other: &Self) -> bool {
56            self.value != other.value
57        }
58    }
59
60    #[test]
61    fn test_crdt_trait() {
62        let replica_id = ReplicaId::default();
63        let crdt = TestCrdt::new(replica_id, "test".to_string());
64        
65        assert_eq!(crdt.replica_id(), &replica_id);
66    }
67
68    #[test]
69    fn test_mergeable_trait() {
70        let replica_id = ReplicaId::default();
71        let mut crdt1 = TestCrdt::new(replica_id, "short".to_string());
72        let crdt2 = TestCrdt::new(replica_id, "much longer string".to_string());
73        
74        // Test merge
75        crdt1.merge(&crdt2).unwrap();
76        assert_eq!(crdt1.value, "much longer string");
77        
78        // Test conflict detection
79        let crdt3 = TestCrdt::new(replica_id, "different".to_string());
80        assert!(crdt1.has_conflict(&crdt3));
81        assert!(!crdt1.has_conflict(&crdt2));
82    }
83}