use crate::error::CRDTResult;
use crate::memory::MemoryConfig;
pub trait CRDT<C: MemoryConfig> {
type Error;
fn merge(&mut self, other: &Self) -> CRDTResult<()>;
fn eq(&self, other: &Self) -> bool;
fn size_bytes(&self) -> usize;
fn validate(&self) -> CRDTResult<()>;
fn state_hash(&self) -> u32;
fn can_merge(&self, other: &Self) -> bool;
}
pub trait PartiallyOrdered<C: MemoryConfig>: CRDT<C> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering>;
fn happens_before(&self, other: &Self) -> bool {
matches!(self.partial_cmp(other), Some(core::cmp::Ordering::Less))
}
fn is_concurrent(&self, other: &Self) -> bool {
self.partial_cmp(other).is_none()
}
}
pub trait DeltaCRDT<C: MemoryConfig>: CRDT<C> {
type Delta;
fn delta_since(&self, other: &Self) -> Option<Self::Delta>;
fn apply_delta(&mut self, delta: &Self::Delta) -> CRDTResult<()>;
fn merge_deltas(delta1: &Self::Delta, delta2: &Self::Delta) -> Self::Delta;
fn delta_size(delta: &Self::Delta) -> usize;
}
pub trait CausalCRDT<C: MemoryConfig>: CRDT<C> {
type CausalContext;
fn causal_context(&self) -> &Self::CausalContext;
fn is_causally_ready(&self, context: &Self::CausalContext) -> bool;
fn update_causal_context(&mut self, context: Self::CausalContext);
fn check_causality(&self, other: &Self) -> CRDTResult<()>;
}
pub trait SerializableCRDT<C: MemoryConfig>: CRDT<C> {
fn serialize(&self, buffer: &mut [u8]) -> CRDTResult<usize>;
fn deserialize(buffer: &[u8]) -> CRDTResult<Self>
where
Self: Sized;
fn max_serialized_size() -> usize;
fn serialized_size(&self) -> usize;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::CRDTError;
use crate::memory::DefaultConfig;
struct MockCRDT {
value: u32,
}
impl CRDT<DefaultConfig> for MockCRDT {
type Error = CRDTError;
fn merge(&mut self, other: &Self) -> CRDTResult<()> {
self.value = self.value.max(other.value);
Ok(())
}
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
fn size_bytes(&self) -> usize {
core::mem::size_of::<u32>()
}
fn validate(&self) -> CRDTResult<()> {
Ok(())
}
fn state_hash(&self) -> u32 {
self.value
}
fn can_merge(&self, _other: &Self) -> bool {
true
}
}
#[test]
fn test_crdt_merge() {
let mut crdt1 = MockCRDT { value: 10 };
let crdt2 = MockCRDT { value: 20 };
assert!(crdt1.merge(&crdt2).is_ok());
assert_eq!(crdt1.value, 20);
}
#[test]
fn test_crdt_equality() {
let crdt1 = MockCRDT { value: 10 };
let crdt2 = MockCRDT { value: 10 };
let crdt3 = MockCRDT { value: 20 };
assert!(crdt1.eq(&crdt2));
assert!(!crdt1.eq(&crdt3));
}
#[test]
fn test_crdt_properties() {
let crdt = MockCRDT { value: 42 };
assert_eq!(crdt.size_bytes(), 4);
assert_eq!(crdt.state_hash(), 42);
assert!(crdt.validate().is_ok());
assert!(crdt.can_merge(&crdt));
}
}