1use crate::node_id::NodeId;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct LwwRegister<T> {
34 value: T,
35 timestamp: u64,
36 node_id: NodeId,
37}
38
39impl<T> LwwRegister<T> {
40 pub const fn new(value: T, node_id: NodeId, timestamp: u64) -> Self {
42 Self {
43 value,
44 timestamp,
45 node_id,
46 }
47 }
48
49 #[inline]
51 pub const fn value(&self) -> &T {
52 &self.value
53 }
54
55 #[inline]
57 pub const fn timestamp(&self) -> u64 {
58 self.timestamp
59 }
60
61 #[inline]
63 pub const fn node_id(&self) -> NodeId {
64 self.node_id
65 }
66
67 pub fn update(&mut self, value: T, node_id: NodeId, timestamp: u64) -> bool {
76 if self.should_accept(timestamp, node_id) {
77 self.value = value;
78 self.timestamp = timestamp;
79 self.node_id = node_id;
80 true
81 } else {
82 false
83 }
84 }
85
86 pub fn merge(&mut self, other: Self) {
90 if self.should_accept(other.timestamp, other.node_id) {
91 *self = other;
92 }
93 }
94
95 fn should_accept(&self, timestamp: u64, node_id: NodeId) -> bool {
97 timestamp > self.timestamp
98 || (timestamp == self.timestamp && node_id.as_u32() > self.node_id.as_u32())
99 }
100}
101
102impl<T: Default> Default for LwwRegister<T> {
103 fn default() -> Self {
104 Self {
105 value: T::default(),
106 timestamp: 0,
107 node_id: NodeId::NULL,
108 }
109 }
110}
111
112impl<T: Clone> LwwRegister<T> {
113 pub fn value_cloned(&self) -> T {
115 self.value.clone()
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
125pub struct Position {
126 pub lat_microdeg: i32,
128 pub lon_microdeg: i32,
130 pub alt_cm: i32,
132}
133
134impl Position {
135 #[cfg(feature = "std")]
137 pub fn from_degrees(lat: f64, lon: f64, alt_m: f32) -> Self {
138 Self {
139 lat_microdeg: (lat * 1_000_000.0) as i32,
140 lon_microdeg: (lon * 1_000_000.0) as i32,
141 alt_cm: (alt_m * 100.0) as i32,
142 }
143 }
144
145 #[cfg(feature = "std")]
147 pub fn to_degrees(&self) -> (f64, f64, f32) {
148 (
149 self.lat_microdeg as f64 / 1_000_000.0,
150 self.lon_microdeg as f64 / 1_000_000.0,
151 self.alt_cm as f32 / 100.0,
152 )
153 }
154
155 pub fn encode(&self) -> [u8; 12] {
157 let mut buf = [0u8; 12];
158 buf[0..4].copy_from_slice(&self.lat_microdeg.to_le_bytes());
159 buf[4..8].copy_from_slice(&self.lon_microdeg.to_le_bytes());
160 buf[8..12].copy_from_slice(&self.alt_cm.to_le_bytes());
161 buf
162 }
163
164 pub fn decode(data: &[u8; 12]) -> Self {
166 Self {
167 lat_microdeg: i32::from_le_bytes([data[0], data[1], data[2], data[3]]),
168 lon_microdeg: i32::from_le_bytes([data[4], data[5], data[6], data[7]]),
169 alt_cm: i32::from_le_bytes([data[8], data[9], data[10], data[11]]),
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_lww_basic() {
180 let mut reg = LwwRegister::new(10, NodeId::new(1), 100);
181 assert_eq!(reg.value(), &10);
182
183 assert!(reg.update(20, NodeId::new(2), 200));
185 assert_eq!(reg.value(), &20);
186
187 assert!(!reg.update(30, NodeId::new(3), 150));
189 assert_eq!(reg.value(), &20);
190 }
191
192 #[test]
193 fn test_lww_tiebreaker() {
194 let mut reg = LwwRegister::new(10, NodeId::new(1), 100);
195
196 assert!(reg.update(20, NodeId::new(5), 100));
198 assert_eq!(reg.value(), &20);
199 assert_eq!(reg.node_id(), NodeId::new(5));
200
201 assert!(!reg.update(30, NodeId::new(3), 100));
203 assert_eq!(reg.value(), &20);
204 }
205
206 #[test]
207 fn test_lww_merge() {
208 let mut reg1 = LwwRegister::new(10, NodeId::new(1), 100);
209 let reg2 = LwwRegister::new(20, NodeId::new(2), 200);
210
211 reg1.merge(reg2);
212 assert_eq!(reg1.value(), &20);
213 }
214
215 #[test]
216 fn test_position_encode_decode() {
217 let pos = Position {
218 lat_microdeg: 37_774_929, lon_microdeg: -122_419_416, alt_cm: 1000, };
222
223 let encoded = pos.encode();
224 let decoded = Position::decode(&encoded);
225 assert_eq!(pos, decoded);
226 }
227
228 #[cfg(feature = "std")]
229 #[test]
230 fn test_position_degrees() {
231 let pos = Position::from_degrees(37.774929, -122.419416, 10.0);
232 let (lat, lon, alt) = pos.to_degrees();
233
234 assert!((lat - 37.774929).abs() < 0.000001);
235 assert!((lon - (-122.419416)).abs() < 0.000001);
236 assert!((alt - 10.0).abs() < 0.01);
237 }
238}