1#[cfg(not(feature = "std"))]
28use alloc::vec::Vec;
29
30use crate::sync::crdt::{EmergencyEvent, EventType, GCounter, Peripheral, PeripheralEvent};
31use crate::NodeId;
32
33pub const EXTENDED_MARKER: u8 = 0xAB;
35
36pub const EMERGENCY_MARKER: u8 = 0xAC;
38
39pub const ENCRYPTED_MARKER: u8 = 0xAE;
53
54pub const PEER_E2EE_MARKER: u8 = 0xAF;
69
70pub const KEY_EXCHANGE_MARKER: u8 = 0xB0;
81
82pub const MIN_DOCUMENT_SIZE: usize = 8;
84
85pub const MAX_MESH_SIZE: usize = 20;
91
92pub const TARGET_DOCUMENT_SIZE: usize = 244;
96
97pub const MAX_DOCUMENT_SIZE: usize = 512;
101
102#[derive(Debug, Clone)]
107pub struct HiveDocument {
108 pub version: u32,
110
111 pub node_id: NodeId,
113
114 pub counter: GCounter,
116
117 pub peripheral: Option<Peripheral>,
119
120 pub emergency: Option<EmergencyEvent>,
122}
123
124impl Default for HiveDocument {
125 fn default() -> Self {
126 Self {
127 version: 1,
128 node_id: NodeId::default(),
129 counter: GCounter::new(),
130 peripheral: None,
131 emergency: None,
132 }
133 }
134}
135
136impl HiveDocument {
137 pub fn new(node_id: NodeId) -> Self {
139 Self {
140 version: 1,
141 node_id,
142 counter: GCounter::new(),
143 peripheral: None,
144 emergency: None,
145 }
146 }
147
148 pub fn with_peripheral(mut self, peripheral: Peripheral) -> Self {
150 self.peripheral = Some(peripheral);
151 self
152 }
153
154 pub fn with_emergency(mut self, emergency: EmergencyEvent) -> Self {
156 self.emergency = Some(emergency);
157 self
158 }
159
160 pub fn increment_version(&mut self) {
162 self.version = self.version.wrapping_add(1);
163 }
164
165 pub fn increment_counter(&mut self) {
167 self.counter.increment(&self.node_id, 1);
168 self.increment_version();
169 }
170
171 pub fn set_event(&mut self, event_type: EventType, timestamp: u64) {
173 if let Some(ref mut peripheral) = self.peripheral {
174 peripheral.set_event(event_type, timestamp);
175 self.increment_counter();
176 }
177 }
178
179 pub fn clear_event(&mut self) {
181 if let Some(ref mut peripheral) = self.peripheral {
182 peripheral.clear_event();
183 self.increment_version();
184 }
185 }
186
187 pub fn set_emergency(&mut self, source_node: u32, timestamp: u64, known_peers: &[u32]) {
192 self.emergency = Some(EmergencyEvent::new(source_node, timestamp, known_peers));
193 self.increment_counter();
194 }
195
196 pub fn ack_emergency(&mut self, node_id: u32) -> bool {
200 if let Some(ref mut emergency) = self.emergency {
201 if emergency.ack(node_id) {
202 self.increment_version();
203 return true;
204 }
205 }
206 false
207 }
208
209 pub fn clear_emergency(&mut self) {
211 if self.emergency.is_some() {
212 self.emergency = None;
213 self.increment_version();
214 }
215 }
216
217 pub fn get_emergency(&self) -> Option<&EmergencyEvent> {
219 self.emergency.as_ref()
220 }
221
222 pub fn has_emergency(&self) -> bool {
224 self.emergency.is_some()
225 }
226
227 pub fn merge(&mut self, other: &HiveDocument) -> bool {
231 let mut changed = false;
232
233 let old_value = self.counter.value();
235 self.counter.merge(&other.counter);
236 if self.counter.value() != old_value {
237 changed = true;
238 }
239
240 if let Some(ref other_emergency) = other.emergency {
242 match &mut self.emergency {
243 Some(ref mut our_emergency) => {
244 if our_emergency.merge(other_emergency) {
245 changed = true;
246 }
247 }
248 None => {
249 self.emergency = Some(other_emergency.clone());
250 changed = true;
251 }
252 }
253 }
254
255 if changed {
256 self.increment_version();
257 }
258 changed
259 }
260
261 pub fn current_event(&self) -> Option<EventType> {
263 self.peripheral
264 .as_ref()
265 .and_then(|p| p.last_event.as_ref())
266 .map(|e| e.event_type)
267 }
268
269 pub fn encode(&self) -> Vec<u8> {
273 let counter_data = self.counter.encode();
274 let peripheral_data = self.peripheral.as_ref().map(|p| p.encode());
275 let emergency_data = self.emergency.as_ref().map(|e| e.encode());
276
277 let mut size = 8 + counter_data.len(); if let Some(ref pdata) = peripheral_data {
280 size += 4 + pdata.len(); }
282 if let Some(ref edata) = emergency_data {
283 size += 4 + edata.len(); }
285
286 let mut buf = Vec::with_capacity(size);
287
288 buf.extend_from_slice(&self.version.to_le_bytes());
290 buf.extend_from_slice(&self.node_id.as_u32().to_le_bytes());
291
292 buf.extend_from_slice(&counter_data);
294
295 if let Some(pdata) = peripheral_data {
297 buf.push(EXTENDED_MARKER);
298 buf.push(0); buf.extend_from_slice(&(pdata.len() as u16).to_le_bytes());
300 buf.extend_from_slice(&pdata);
301 }
302
303 if let Some(edata) = emergency_data {
305 buf.push(EMERGENCY_MARKER);
306 buf.push(0); buf.extend_from_slice(&(edata.len() as u16).to_le_bytes());
308 buf.extend_from_slice(&edata);
309 }
310
311 buf
312 }
313
314 #[inline]
319 pub fn to_bytes(&self) -> Vec<u8> {
320 self.encode()
321 }
322
323 pub fn decode(data: &[u8]) -> Option<Self> {
327 if data.len() < MIN_DOCUMENT_SIZE {
328 return None;
329 }
330
331 let version = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
333 let node_id = NodeId::new(u32::from_le_bytes([data[4], data[5], data[6], data[7]]));
334
335 let counter = GCounter::decode(&data[8..])?;
337
338 let num_entries = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize;
340 let mut offset = 8 + 4 + num_entries * 12;
341
342 let mut peripheral = None;
343 let mut emergency = None;
344
345 while offset < data.len() {
347 let marker = data[offset];
348
349 if marker == EXTENDED_MARKER {
350 if data.len() < offset + 4 {
352 break;
353 }
354 let _reserved = data[offset + 1];
355 let section_len = u16::from_le_bytes([data[offset + 2], data[offset + 3]]) as usize;
356
357 let section_start = offset + 4;
358 if data.len() < section_start + section_len {
359 break;
360 }
361
362 peripheral = Peripheral::decode(&data[section_start..section_start + section_len]);
363 offset = section_start + section_len;
364 } else if marker == EMERGENCY_MARKER {
365 if data.len() < offset + 4 {
367 break;
368 }
369 let _reserved = data[offset + 1];
370 let section_len = u16::from_le_bytes([data[offset + 2], data[offset + 3]]) as usize;
371
372 let section_start = offset + 4;
373 if data.len() < section_start + section_len {
374 break;
375 }
376
377 emergency =
378 EmergencyEvent::decode(&data[section_start..section_start + section_len]);
379 offset = section_start + section_len;
380 } else {
381 break;
383 }
384 }
385
386 Some(Self {
387 version,
388 node_id,
389 counter,
390 peripheral,
391 emergency,
392 })
393 }
394
395 #[inline]
400 pub fn from_bytes(data: &[u8]) -> Option<Self> {
401 Self::decode(data)
402 }
403
404 pub fn total_count(&self) -> u64 {
406 self.counter.value()
407 }
408
409 pub fn encoded_size(&self) -> usize {
413 let counter_size = 4 + self.counter.node_count_total() * 12;
414 let peripheral_size = self.peripheral.as_ref().map_or(0, |p| 4 + p.encode().len());
415 let emergency_size = self.emergency.as_ref().map_or(0, |e| 4 + e.encode().len());
416 8 + counter_size + peripheral_size + emergency_size
417 }
418
419 pub fn exceeds_target_size(&self) -> bool {
423 self.encoded_size() > TARGET_DOCUMENT_SIZE
424 }
425
426 pub fn exceeds_max_size(&self) -> bool {
430 self.encoded_size() > MAX_DOCUMENT_SIZE
431 }
432}
433
434#[derive(Debug, Clone)]
436pub struct MergeResult {
437 pub source_node: NodeId,
439
440 pub event: Option<PeripheralEvent>,
442
443 pub counter_changed: bool,
445
446 pub emergency_changed: bool,
448
449 pub total_count: u64,
451}
452
453impl MergeResult {
454 pub fn is_emergency(&self) -> bool {
456 self.event
457 .as_ref()
458 .is_some_and(|e| e.event_type == EventType::Emergency)
459 }
460
461 pub fn is_ack(&self) -> bool {
463 self.event
464 .as_ref()
465 .is_some_and(|e| e.event_type == EventType::Ack)
466 }
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472 use crate::sync::crdt::PeripheralType;
473
474 #[test]
475 fn test_document_encode_decode_minimal() {
476 let node_id = NodeId::new(0x12345678);
477 let doc = HiveDocument::new(node_id);
478
479 let encoded = doc.encode();
480 assert_eq!(encoded.len(), 12); let decoded = HiveDocument::decode(&encoded).unwrap();
483 assert_eq!(decoded.version, 1);
484 assert_eq!(decoded.node_id.as_u32(), 0x12345678);
485 assert_eq!(decoded.counter.value(), 0);
486 assert!(decoded.peripheral.is_none());
487 }
488
489 #[test]
490 fn test_document_encode_decode_with_counter() {
491 let node_id = NodeId::new(0x12345678);
492 let mut doc = HiveDocument::new(node_id);
493 doc.increment_counter();
494 doc.increment_counter();
495
496 let encoded = doc.encode();
497 assert_eq!(encoded.len(), 24);
499
500 let decoded = HiveDocument::decode(&encoded).unwrap();
501 assert_eq!(decoded.counter.value(), 2);
502 }
503
504 #[test]
505 fn test_document_encode_decode_with_peripheral() {
506 let node_id = NodeId::new(0x12345678);
507 let peripheral =
508 Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor).with_callsign("ALPHA-1");
509
510 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
511
512 let encoded = doc.encode();
513 let decoded = HiveDocument::decode(&encoded).unwrap();
514
515 assert!(decoded.peripheral.is_some());
516 let p = decoded.peripheral.unwrap();
517 assert_eq!(p.id, 0xAABBCCDD);
518 assert_eq!(p.callsign_str(), "ALPHA-1");
519 }
520
521 #[test]
522 fn test_document_encode_decode_with_event() {
523 let node_id = NodeId::new(0x12345678);
524 let mut peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor);
525 peripheral.set_event(EventType::Emergency, 1234567890);
526
527 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
528
529 let encoded = doc.encode();
530 let decoded = HiveDocument::decode(&encoded).unwrap();
531
532 assert!(decoded.peripheral.is_some());
533 let p = decoded.peripheral.unwrap();
534 assert!(p.last_event.is_some());
535 let event = p.last_event.unwrap();
536 assert_eq!(event.event_type, EventType::Emergency);
537 assert_eq!(event.timestamp, 1234567890);
538 }
539
540 #[test]
541 fn test_document_merge() {
542 let node1 = NodeId::new(0x11111111);
543 let node2 = NodeId::new(0x22222222);
544
545 let mut doc1 = HiveDocument::new(node1);
546 doc1.increment_counter();
547
548 let mut doc2 = HiveDocument::new(node2);
549 doc2.counter.increment(&node2, 3);
550
551 let changed = doc1.merge(&doc2);
553 assert!(changed);
554 assert_eq!(doc1.counter.value(), 4); }
556
557 #[test]
558 fn test_merge_result_helpers() {
559 let emergency_event = PeripheralEvent::new(EventType::Emergency, 123);
560 let result = MergeResult {
561 source_node: NodeId::new(0x12345678),
562 event: Some(emergency_event),
563 counter_changed: true,
564 emergency_changed: false,
565 total_count: 10,
566 };
567
568 assert!(result.is_emergency());
569 assert!(!result.is_ack());
570
571 let ack_event = PeripheralEvent::new(EventType::Ack, 456);
572 let result = MergeResult {
573 source_node: NodeId::new(0x12345678),
574 event: Some(ack_event),
575 counter_changed: false,
576 emergency_changed: false,
577 total_count: 10,
578 };
579
580 assert!(!result.is_emergency());
581 assert!(result.is_ack());
582 }
583
584 #[test]
585 fn test_document_size_calculation() {
586 use crate::sync::crdt::PeripheralType;
587
588 let node_id = NodeId::new(0x12345678);
589
590 let doc = HiveDocument::new(node_id);
592 assert_eq!(doc.encoded_size(), 12);
593 assert!(!doc.exceeds_target_size());
594
595 let mut doc = HiveDocument::new(node_id);
597 doc.increment_counter();
598 assert_eq!(doc.encoded_size(), 24);
599
600 let peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor);
602 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
603 let encoded = doc.encode();
604 assert_eq!(doc.encoded_size(), encoded.len());
605
606 let mut doc = HiveDocument::new(node_id);
608 for i in 0..10 {
609 doc.counter.increment(&NodeId::new(i), 1);
610 }
611 assert!(doc.encoded_size() < TARGET_DOCUMENT_SIZE);
612 assert!(!doc.exceeds_max_size());
613 }
614}