crdtosphere/traits/
crdt.rs

1//! Base CRDT trait definition
2//!
3//! This module defines the fundamental CRDT trait that all Conflict-free
4//! Replicated Data Types must implement.
5
6use crate::error::CRDTResult;
7use crate::memory::MemoryConfig;
8
9/// Base trait for all Conflict-free Replicated Data Types
10///
11/// This trait defines the fundamental operations that all CRDTs must support.
12/// The trait is parameterized by a memory configuration to enable compile-time
13/// resource management.
14pub trait CRDT<C: MemoryConfig> {
15    /// The error type for CRDT operations
16    type Error;
17
18    /// Merges another CRDT instance into this one
19    ///
20    /// This operation must be:
21    /// - Commutative: merge(a, b) = merge(b, a)
22    /// - Associative: merge(merge(a, b), c) = merge(a, merge(b, c))
23    /// - Idempotent: merge(a, a) = a
24    ///
25    /// # Arguments
26    ///
27    /// * `other` - The other CRDT instance to merge
28    ///
29    /// # Returns
30    ///
31    /// Returns `Ok(())` if the merge was successful, or an error if the merge failed.
32    fn merge(&mut self, other: &Self) -> CRDTResult<()>;
33
34    /// Checks if this CRDT is equal to another
35    ///
36    /// Two CRDTs are considered equal if they represent the same logical state,
37    /// regardless of their internal representation or history.
38    fn eq(&self, other: &Self) -> bool;
39
40    /// Returns the current size of the CRDT in bytes
41    ///
42    /// This includes all internal state and metadata required for the CRDT
43    /// to function correctly.
44    fn size_bytes(&self) -> usize;
45
46    /// Validates the internal consistency of the CRDT
47    ///
48    /// This method checks that the CRDT's internal state is consistent and
49    /// that all invariants are maintained.
50    fn validate(&self) -> CRDTResult<()>;
51
52    /// Returns a hash of the CRDT's logical state
53    ///
54    /// This hash should be the same for CRDTs that represent the same logical
55    /// state, regardless of their internal representation.
56    fn state_hash(&self) -> u32;
57
58    /// Checks if the CRDT can be merged with another without exceeding limits
59    ///
60    /// This method allows checking merge compatibility before attempting the
61    /// actual merge operation.
62    fn can_merge(&self, other: &Self) -> bool;
63}
64
65/// Trait for CRDTs that support partial ordering
66///
67/// Some CRDTs have a natural partial ordering based on their logical state.
68/// This trait provides methods to compare CRDT instances.
69pub trait PartiallyOrdered<C: MemoryConfig>: CRDT<C> {
70    /// Checks if this CRDT is less than or equal to another
71    ///
72    /// Returns `Some(true)` if this CRDT is less than or equal to the other,
73    /// `Some(false)` if it is greater, or `None` if they are incomparable.
74    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering>;
75
76    /// Checks if this CRDT is causally before another
77    /// In a sense, this is causality check.
78    fn happens_before(&self, other: &Self) -> bool {
79        matches!(self.partial_cmp(other), Some(core::cmp::Ordering::Less))
80    }
81
82    /// Checks if this CRDT is concurrent with another
83    fn is_concurrent(&self, other: &Self) -> bool {
84        self.partial_cmp(other).is_none()
85    }
86}
87
88/// Trait for CRDTs that support delta operations
89///
90/// Delta CRDTs can generate and apply deltas (incremental changes) rather
91/// than merging entire states, which can be more efficient for network
92/// transmission.
93pub trait DeltaCRDT<C: MemoryConfig>: CRDT<C> {
94    /// The type representing a delta (incremental change)
95    type Delta;
96
97    /// Generates a delta representing changes since the given state
98    fn delta_since(&self, other: &Self) -> Option<Self::Delta>;
99
100    /// Applies a delta to this CRDT
101    fn apply_delta(&mut self, delta: &Self::Delta) -> CRDTResult<()>;
102
103    /// Merges two deltas into a single delta
104    fn merge_deltas(delta1: &Self::Delta, delta2: &Self::Delta) -> Self::Delta;
105
106    /// Returns the size of a delta in bytes
107    fn delta_size(delta: &Self::Delta) -> usize;
108}
109
110/// Trait for CRDTs that support causal consistency
111///
112/// Causal CRDTs maintain causal relationships between operations and can
113/// detect causality violations.
114pub trait CausalCRDT<C: MemoryConfig>: CRDT<C> {
115    /// The type representing a causal context (e.g., vector clock)
116    type CausalContext;
117
118    /// Returns the current causal context
119    fn causal_context(&self) -> &Self::CausalContext;
120
121    /// Checks if an operation is causally ready to be applied
122    fn is_causally_ready(&self, context: &Self::CausalContext) -> bool;
123
124    /// Updates the causal context after an operation
125    fn update_causal_context(&mut self, context: Self::CausalContext);
126
127    /// Checks for causal violations
128    fn check_causality(&self, other: &Self) -> CRDTResult<()>;
129}
130
131/// Trait for CRDTs that support serialization
132///
133/// This trait provides methods for serializing and deserializing CRDTs
134/// for network transmission or persistent storage.
135pub trait SerializableCRDT<C: MemoryConfig>: CRDT<C> {
136    /// Serializes the CRDT to a byte buffer
137    ///
138    /// The buffer must be pre-allocated with sufficient capacity.
139    fn serialize(&self, buffer: &mut [u8]) -> CRDTResult<usize>;
140
141    /// Deserializes a CRDT from a byte buffer
142    fn deserialize(buffer: &[u8]) -> CRDTResult<Self>
143    where
144        Self: Sized;
145
146    /// Returns the maximum serialized size in bytes
147    fn max_serialized_size() -> usize;
148
149    /// Returns the actual serialized size for this instance
150    fn serialized_size(&self) -> usize;
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156    use crate::error::CRDTError;
157    use crate::memory::DefaultConfig;
158
159    // Mock CRDT implementation for testing
160    struct MockCRDT {
161        value: u32,
162    }
163
164    impl CRDT<DefaultConfig> for MockCRDT {
165        type Error = CRDTError;
166
167        fn merge(&mut self, other: &Self) -> CRDTResult<()> {
168            self.value = self.value.max(other.value);
169            Ok(())
170        }
171
172        fn eq(&self, other: &Self) -> bool {
173            self.value == other.value
174        }
175
176        fn size_bytes(&self) -> usize {
177            core::mem::size_of::<u32>()
178        }
179
180        fn validate(&self) -> CRDTResult<()> {
181            Ok(())
182        }
183
184        fn state_hash(&self) -> u32 {
185            self.value
186        }
187
188        fn can_merge(&self, _other: &Self) -> bool {
189            true
190        }
191    }
192
193    #[test]
194    fn test_crdt_merge() {
195        let mut crdt1 = MockCRDT { value: 10 };
196        let crdt2 = MockCRDT { value: 20 };
197
198        assert!(crdt1.merge(&crdt2).is_ok());
199        assert_eq!(crdt1.value, 20);
200    }
201
202    #[test]
203    fn test_crdt_equality() {
204        let crdt1 = MockCRDT { value: 10 };
205        let crdt2 = MockCRDT { value: 10 };
206        let crdt3 = MockCRDT { value: 20 };
207
208        assert!(crdt1.eq(&crdt2));
209        assert!(!crdt1.eq(&crdt3));
210    }
211
212    #[test]
213    fn test_crdt_properties() {
214        let crdt = MockCRDT { value: 42 };
215
216        assert_eq!(crdt.size_bytes(), 4);
217        assert_eq!(crdt.state_hash(), 42);
218        assert!(crdt.validate().is_ok());
219        assert!(crdt.can_merge(&crdt));
220    }
221}