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}