leptos_sync_core/crdt/basic/
lww_register.rs1use super::{replica_id::ReplicaId, traits::{CRDT, Mergeable}};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8pub struct LwwRegister<T> {
9 value: T,
10 timestamp: chrono::DateTime<chrono::Utc>,
11 replica_id: ReplicaId,
12}
13
14impl<T: Default> Default for LwwRegister<T> {
15 fn default() -> Self {
16 Self {
17 value: T::default(),
18 timestamp: chrono::Utc::now(),
19 replica_id: ReplicaId::default(),
20 }
21 }
22}
23
24impl<T> LwwRegister<T> {
25 pub fn new(value: T, replica_id: ReplicaId) -> Self {
26 Self {
27 value,
28 timestamp: chrono::Utc::now(),
29 replica_id,
30 }
31 }
32
33 pub fn value(&self) -> &T {
34 &self.value
35 }
36
37 pub fn timestamp(&self) -> chrono::DateTime<chrono::Utc> {
38 self.timestamp
39 }
40
41 pub fn replica_id(&self) -> ReplicaId {
42 self.replica_id
43 }
44
45 pub fn update(&mut self, value: T, replica_id: ReplicaId) {
46 self.value = value;
47 self.timestamp = chrono::Utc::now();
48 self.replica_id = replica_id;
49 }
50
51 pub fn with_timestamp(mut self, timestamp: chrono::DateTime<chrono::Utc>) -> Self {
52 self.timestamp = timestamp;
53 self
54 }
55}
56
57impl<T: Clone + PartialEq + Send + Sync> Mergeable for LwwRegister<T> {
58 type Error = std::io::Error;
59
60 fn merge(&mut self, other: &Self) -> Result<(), Self::Error> {
61 if other.timestamp > self.timestamp ||
62 (other.timestamp == self.timestamp && other.replica_id.0 > self.replica_id.0) {
63 self.value = other.value.clone();
64 self.timestamp = other.timestamp;
65 self.replica_id = other.replica_id;
66 }
67 Ok(())
68 }
69
70 fn has_conflict(&self, other: &Self) -> bool {
71 self.timestamp == other.timestamp && self.replica_id != other.replica_id
72 }
73}
74
75impl<T> CRDT for LwwRegister<T> {
76 fn replica_id(&self) -> &ReplicaId {
77 &self.replica_id
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_lww_register_creation() {
87 let replica_id = ReplicaId::default();
88 let register = LwwRegister::new("test_value", replica_id);
89
90 assert_eq!(register.value(), &"test_value");
91 assert_eq!(register.replica_id(), replica_id);
92 }
93
94 #[test]
95 fn test_lww_register_update() {
96 let replica_id = ReplicaId::default();
97 let mut register = LwwRegister::new("old_value", replica_id);
98
99 register.update("new_value", replica_id);
100 assert_eq!(register.value(), &"new_value");
101 }
102
103 #[test]
104 fn test_lww_register_merge() {
105 let mut reg1 = LwwRegister::new("value1", ReplicaId::default());
106 let reg2 = LwwRegister::new("value2", ReplicaId::default());
107
108 std::thread::sleep(std::time::Duration::from_millis(1));
110
111 reg1.merge(®2).unwrap();
112 assert_eq!(reg1.value(), &"value2");
113 }
114
115 #[test]
116 fn test_lww_register_conflict_detection() {
117 let replica_id1 = ReplicaId::default();
118 let replica_id2 = ReplicaId::default();
119
120 let timestamp = chrono::Utc::now();
122 let reg1 = LwwRegister::new("value1", replica_id1).with_timestamp(timestamp);
123 let reg2 = LwwRegister::new("value2", replica_id2).with_timestamp(timestamp);
124
125 assert!(reg1.has_conflict(®2));
126 }
127
128 #[test]
129 fn test_lww_register_serialization() {
130 let replica_id = ReplicaId::default();
131 let register = LwwRegister::new("test", replica_id);
132
133 let serialized = serde_json::to_string(®ister).unwrap();
134 let deserialized: LwwRegister<String> = serde_json::from_str(&serialized).unwrap();
135
136 assert_eq!(register.value(), deserialized.value());
137 assert_eq!(register.replica_id(), deserialized.replica_id());
138 }
139}