1use std::time::{SystemTime, UNIX_EPOCH};
2
3use crate::Crdt;
4
5#[derive(Debug, Clone)]
23pub struct LWWRegister<T: Clone> {
24 actor: String,
25 value: T,
26 timestamp: u64,
27}
28
29impl<T: Clone + PartialEq> PartialEq for LWWRegister<T> {
30 fn eq(&self, other: &Self) -> bool {
31 self.value == other.value && self.timestamp == other.timestamp
32 }
33}
34
35impl<T: Clone + Eq> Eq for LWWRegister<T> {}
36
37impl<T: Clone> LWWRegister<T> {
38 pub fn new(actor: impl Into<String>, value: T) -> Self {
42 Self {
43 actor: actor.into(),
44 value,
45 timestamp: now(),
46 }
47 }
48
49 pub fn with_timestamp(actor: impl Into<String>, value: T, timestamp: u64) -> Self {
53 Self {
54 actor: actor.into(),
55 value,
56 timestamp,
57 }
58 }
59
60 pub fn set(&mut self, value: T) {
64 self.value = value;
65 self.timestamp = now();
66 }
67
68 pub fn set_with_timestamp(&mut self, value: T, timestamp: u64) {
70 if timestamp >= self.timestamp {
71 self.value = value;
72 self.timestamp = timestamp;
73 }
74 }
75
76 #[must_use]
78 pub fn value(&self) -> &T {
79 &self.value
80 }
81
82 #[must_use]
84 pub fn timestamp(&self) -> u64 {
85 self.timestamp
86 }
87
88 #[must_use]
90 pub fn actor(&self) -> &str {
91 &self.actor
92 }
93}
94
95impl<T: Clone> Crdt for LWWRegister<T> {
96 fn merge(&mut self, other: &Self) {
97 if other.timestamp > self.timestamp
98 || (other.timestamp == self.timestamp && other.actor > self.actor)
99 {
100 self.value = other.value.clone();
101 self.timestamp = other.timestamp;
102 }
103 }
104}
105
106fn now() -> u64 {
107 SystemTime::now()
108 .duration_since(UNIX_EPOCH)
109 .unwrap_or_default()
110 .as_micros() as u64
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn new_register_holds_value() {
119 let r = LWWRegister::with_timestamp("a", 42, 1);
120 assert_eq!(*r.value(), 42);
121 }
122
123 #[test]
124 fn set_updates_value() {
125 let mut r = LWWRegister::with_timestamp("a", 1, 1);
126 r.set_with_timestamp(2, 2);
127 assert_eq!(*r.value(), 2);
128 }
129
130 #[test]
131 fn merge_keeps_later_timestamp() {
132 let mut r1 = LWWRegister::with_timestamp("a", "old", 1);
133 let r2 = LWWRegister::with_timestamp("b", "new", 2);
134
135 r1.merge(&r2);
136 assert_eq!(*r1.value(), "new");
137 }
138
139 #[test]
140 fn merge_keeps_self_if_later() {
141 let mut r1 = LWWRegister::with_timestamp("a", "new", 2);
142 let r2 = LWWRegister::with_timestamp("b", "old", 1);
143
144 r1.merge(&r2);
145 assert_eq!(*r1.value(), "new");
146 }
147
148 #[test]
149 fn merge_breaks_tie_by_actor() {
150 let mut r1 = LWWRegister::with_timestamp("a", "first", 1);
151 let r2 = LWWRegister::with_timestamp("b", "second", 1);
152
153 r1.merge(&r2);
154 assert_eq!(*r1.value(), "second");
156 }
157
158 #[test]
159 fn merge_is_idempotent() {
160 let mut r1 = LWWRegister::with_timestamp("a", "x", 1);
161 let r2 = LWWRegister::with_timestamp("b", "y", 2);
162
163 r1.merge(&r2);
164 let after_first = r1.clone();
165 r1.merge(&r2);
166
167 assert_eq!(r1, after_first);
168 }
169}