1#[cfg(not(feature = "std"))]
43use alloc::vec::Vec;
44
45use crate::sync::crdt::{EmergencyEvent, EventType, GCounter, Peripheral, PeripheralEvent};
46use crate::NodeId;
47
48pub const EXTENDED_MARKER: u8 = 0xAB;
50
51pub const EMERGENCY_MARKER: u8 = 0xAC;
53
54pub const ENCRYPTED_MARKER: u8 = 0xAE;
68
69pub const PEER_E2EE_MARKER: u8 = 0xAF;
84
85pub const KEY_EXCHANGE_MARKER: u8 = 0xB0;
96
97pub const MIN_DOCUMENT_SIZE: usize = 8;
99
100pub const MAX_MESH_SIZE: usize = 20;
106
107pub const TARGET_DOCUMENT_SIZE: usize = 244;
111
112pub const MAX_DOCUMENT_SIZE: usize = 512;
116
117#[derive(Debug, Clone)]
122pub struct HiveDocument {
123 pub version: u32,
125
126 pub node_id: NodeId,
128
129 pub counter: GCounter,
131
132 pub peripheral: Option<Peripheral>,
134
135 pub emergency: Option<EmergencyEvent>,
137}
138
139impl Default for HiveDocument {
140 fn default() -> Self {
141 Self {
142 version: 1,
143 node_id: NodeId::default(),
144 counter: GCounter::new(),
145 peripheral: None,
146 emergency: None,
147 }
148 }
149}
150
151impl HiveDocument {
152 pub fn new(node_id: NodeId) -> Self {
154 Self {
155 version: 1,
156 node_id,
157 counter: GCounter::new(),
158 peripheral: None,
159 emergency: None,
160 }
161 }
162
163 pub fn with_peripheral(mut self, peripheral: Peripheral) -> Self {
165 self.peripheral = Some(peripheral);
166 self
167 }
168
169 pub fn with_emergency(mut self, emergency: EmergencyEvent) -> Self {
171 self.emergency = Some(emergency);
172 self
173 }
174
175 pub fn increment_version(&mut self) {
177 self.version = self.version.wrapping_add(1);
178 }
179
180 pub fn increment_counter(&mut self) {
182 self.counter.increment(&self.node_id, 1);
183 self.increment_version();
184 }
185
186 pub fn set_event(&mut self, event_type: EventType, timestamp: u64) {
188 if let Some(ref mut peripheral) = self.peripheral {
189 peripheral.set_event(event_type, timestamp);
190 self.increment_counter();
191 }
192 }
193
194 pub fn clear_event(&mut self) {
196 if let Some(ref mut peripheral) = self.peripheral {
197 peripheral.clear_event();
198 self.increment_version();
199 }
200 }
201
202 pub fn set_emergency(&mut self, source_node: u32, timestamp: u64, known_peers: &[u32]) {
207 self.emergency = Some(EmergencyEvent::new(source_node, timestamp, known_peers));
208 self.increment_counter();
209 }
210
211 pub fn ack_emergency(&mut self, node_id: u32) -> bool {
215 if let Some(ref mut emergency) = self.emergency {
216 if emergency.ack(node_id) {
217 self.increment_version();
218 return true;
219 }
220 }
221 false
222 }
223
224 pub fn clear_emergency(&mut self) {
226 if self.emergency.is_some() {
227 self.emergency = None;
228 self.increment_version();
229 }
230 }
231
232 pub fn get_emergency(&self) -> Option<&EmergencyEvent> {
234 self.emergency.as_ref()
235 }
236
237 pub fn has_emergency(&self) -> bool {
239 self.emergency.is_some()
240 }
241
242 pub fn merge(&mut self, other: &HiveDocument) -> bool {
246 let mut changed = false;
247
248 let old_value = self.counter.value();
250 self.counter.merge(&other.counter);
251 if self.counter.value() != old_value {
252 changed = true;
253 }
254
255 if let Some(ref other_emergency) = other.emergency {
257 match &mut self.emergency {
258 Some(ref mut our_emergency) => {
259 if our_emergency.merge(other_emergency) {
260 changed = true;
261 }
262 }
263 None => {
264 self.emergency = Some(other_emergency.clone());
265 changed = true;
266 }
267 }
268 }
269
270 if changed {
271 self.increment_version();
272 }
273 changed
274 }
275
276 pub fn current_event(&self) -> Option<EventType> {
278 self.peripheral
279 .as_ref()
280 .and_then(|p| p.last_event.as_ref())
281 .map(|e| e.event_type)
282 }
283
284 pub fn encode(&self) -> Vec<u8> {
288 let counter_data = self.counter.encode();
289 let peripheral_data = self.peripheral.as_ref().map(|p| p.encode());
290 let emergency_data = self.emergency.as_ref().map(|e| e.encode());
291
292 let mut size = 8 + counter_data.len(); if let Some(ref pdata) = peripheral_data {
295 size += 4 + pdata.len(); }
297 if let Some(ref edata) = emergency_data {
298 size += 4 + edata.len(); }
300
301 let mut buf = Vec::with_capacity(size);
302
303 buf.extend_from_slice(&self.version.to_le_bytes());
305 buf.extend_from_slice(&self.node_id.as_u32().to_le_bytes());
306
307 buf.extend_from_slice(&counter_data);
309
310 if let Some(pdata) = peripheral_data {
312 buf.push(EXTENDED_MARKER);
313 buf.push(0); buf.extend_from_slice(&(pdata.len() as u16).to_le_bytes());
315 buf.extend_from_slice(&pdata);
316 }
317
318 if let Some(edata) = emergency_data {
320 buf.push(EMERGENCY_MARKER);
321 buf.push(0); buf.extend_from_slice(&(edata.len() as u16).to_le_bytes());
323 buf.extend_from_slice(&edata);
324 }
325
326 buf
327 }
328
329 #[inline]
334 pub fn to_bytes(&self) -> Vec<u8> {
335 self.encode()
336 }
337
338 pub fn decode(data: &[u8]) -> Option<Self> {
342 if data.len() < MIN_DOCUMENT_SIZE {
343 return None;
344 }
345
346 let version = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
348 let node_id = NodeId::new(u32::from_le_bytes([data[4], data[5], data[6], data[7]]));
349
350 let counter = GCounter::decode(&data[8..])?;
352
353 let num_entries = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize;
355 let mut offset = 8 + 4 + num_entries * 12;
356
357 let mut peripheral = None;
358 let mut emergency = None;
359
360 while offset < data.len() {
362 let marker = data[offset];
363
364 if marker == EXTENDED_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 peripheral = Peripheral::decode(&data[section_start..section_start + section_len]);
378 offset = section_start + section_len;
379 } else if marker == EMERGENCY_MARKER {
380 if data.len() < offset + 4 {
382 break;
383 }
384 let _reserved = data[offset + 1];
385 let section_len = u16::from_le_bytes([data[offset + 2], data[offset + 3]]) as usize;
386
387 let section_start = offset + 4;
388 if data.len() < section_start + section_len {
389 break;
390 }
391
392 emergency =
393 EmergencyEvent::decode(&data[section_start..section_start + section_len]);
394 offset = section_start + section_len;
395 } else {
396 break;
398 }
399 }
400
401 Some(Self {
402 version,
403 node_id,
404 counter,
405 peripheral,
406 emergency,
407 })
408 }
409
410 #[inline]
415 pub fn from_bytes(data: &[u8]) -> Option<Self> {
416 Self::decode(data)
417 }
418
419 pub fn total_count(&self) -> u64 {
421 self.counter.value()
422 }
423
424 pub fn encoded_size(&self) -> usize {
428 let counter_size = 4 + self.counter.node_count_total() * 12;
429 let peripheral_size = self.peripheral.as_ref().map_or(0, |p| 4 + p.encode().len());
430 let emergency_size = self.emergency.as_ref().map_or(0, |e| 4 + e.encode().len());
431 8 + counter_size + peripheral_size + emergency_size
432 }
433
434 pub fn exceeds_target_size(&self) -> bool {
438 self.encoded_size() > TARGET_DOCUMENT_SIZE
439 }
440
441 pub fn exceeds_max_size(&self) -> bool {
445 self.encoded_size() > MAX_DOCUMENT_SIZE
446 }
447}
448
449#[derive(Debug, Clone)]
451pub struct MergeResult {
452 pub source_node: NodeId,
454
455 pub event: Option<PeripheralEvent>,
457
458 pub counter_changed: bool,
460
461 pub emergency_changed: bool,
463
464 pub total_count: u64,
466}
467
468impl MergeResult {
469 pub fn is_emergency(&self) -> bool {
471 self.event
472 .as_ref()
473 .is_some_and(|e| e.event_type == EventType::Emergency)
474 }
475
476 pub fn is_ack(&self) -> bool {
478 self.event
479 .as_ref()
480 .is_some_and(|e| e.event_type == EventType::Ack)
481 }
482}
483
484#[cfg(test)]
485mod tests {
486 use super::*;
487 use crate::sync::crdt::PeripheralType;
488
489 #[test]
490 fn test_document_encode_decode_minimal() {
491 let node_id = NodeId::new(0x12345678);
492 let doc = HiveDocument::new(node_id);
493
494 let encoded = doc.encode();
495 assert_eq!(encoded.len(), 12); let decoded = HiveDocument::decode(&encoded).unwrap();
498 assert_eq!(decoded.version, 1);
499 assert_eq!(decoded.node_id.as_u32(), 0x12345678);
500 assert_eq!(decoded.counter.value(), 0);
501 assert!(decoded.peripheral.is_none());
502 }
503
504 #[test]
505 fn test_document_encode_decode_with_counter() {
506 let node_id = NodeId::new(0x12345678);
507 let mut doc = HiveDocument::new(node_id);
508 doc.increment_counter();
509 doc.increment_counter();
510
511 let encoded = doc.encode();
512 assert_eq!(encoded.len(), 24);
514
515 let decoded = HiveDocument::decode(&encoded).unwrap();
516 assert_eq!(decoded.counter.value(), 2);
517 }
518
519 #[test]
520 fn test_document_encode_decode_with_peripheral() {
521 let node_id = NodeId::new(0x12345678);
522 let peripheral =
523 Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor).with_callsign("ALPHA-1");
524
525 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
526
527 let encoded = doc.encode();
528 let decoded = HiveDocument::decode(&encoded).unwrap();
529
530 assert!(decoded.peripheral.is_some());
531 let p = decoded.peripheral.unwrap();
532 assert_eq!(p.id, 0xAABBCCDD);
533 assert_eq!(p.callsign_str(), "ALPHA-1");
534 }
535
536 #[test]
537 fn test_document_encode_decode_with_event() {
538 let node_id = NodeId::new(0x12345678);
539 let mut peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor);
540 peripheral.set_event(EventType::Emergency, 1234567890);
541
542 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
543
544 let encoded = doc.encode();
545 let decoded = HiveDocument::decode(&encoded).unwrap();
546
547 assert!(decoded.peripheral.is_some());
548 let p = decoded.peripheral.unwrap();
549 assert!(p.last_event.is_some());
550 let event = p.last_event.unwrap();
551 assert_eq!(event.event_type, EventType::Emergency);
552 assert_eq!(event.timestamp, 1234567890);
553 }
554
555 #[test]
556 fn test_document_merge() {
557 let node1 = NodeId::new(0x11111111);
558 let node2 = NodeId::new(0x22222222);
559
560 let mut doc1 = HiveDocument::new(node1);
561 doc1.increment_counter();
562
563 let mut doc2 = HiveDocument::new(node2);
564 doc2.counter.increment(&node2, 3);
565
566 let changed = doc1.merge(&doc2);
568 assert!(changed);
569 assert_eq!(doc1.counter.value(), 4); }
571
572 #[test]
573 fn test_merge_result_helpers() {
574 let emergency_event = PeripheralEvent::new(EventType::Emergency, 123);
575 let result = MergeResult {
576 source_node: NodeId::new(0x12345678),
577 event: Some(emergency_event),
578 counter_changed: true,
579 emergency_changed: false,
580 total_count: 10,
581 };
582
583 assert!(result.is_emergency());
584 assert!(!result.is_ack());
585
586 let ack_event = PeripheralEvent::new(EventType::Ack, 456);
587 let result = MergeResult {
588 source_node: NodeId::new(0x12345678),
589 event: Some(ack_event),
590 counter_changed: false,
591 emergency_changed: false,
592 total_count: 10,
593 };
594
595 assert!(!result.is_emergency());
596 assert!(result.is_ack());
597 }
598
599 #[test]
600 fn test_document_size_calculation() {
601 use crate::sync::crdt::PeripheralType;
602
603 let node_id = NodeId::new(0x12345678);
604
605 let doc = HiveDocument::new(node_id);
607 assert_eq!(doc.encoded_size(), 12);
608 assert!(!doc.exceeds_target_size());
609
610 let mut doc = HiveDocument::new(node_id);
612 doc.increment_counter();
613 assert_eq!(doc.encoded_size(), 24);
614
615 let peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor);
617 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
618 let encoded = doc.encode();
619 assert_eq!(doc.encoded_size(), encoded.len());
620
621 let mut doc = HiveDocument::new(node_id);
623 for i in 0..10 {
624 doc.counter.increment(&NodeId::new(i), 1);
625 }
626 assert!(doc.encoded_size() < TARGET_DOCUMENT_SIZE);
627 assert!(!doc.exceeds_max_size());
628 }
629}