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