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> {
271 let counter_data = self.counter.encode();
272 let peripheral_data = self.peripheral.as_ref().map(|p| p.encode());
273 let emergency_data = self.emergency.as_ref().map(|e| e.encode());
274
275 let mut size = 8 + counter_data.len(); if let Some(ref pdata) = peripheral_data {
278 size += 4 + pdata.len(); }
280 if let Some(ref edata) = emergency_data {
281 size += 4 + edata.len(); }
283
284 let mut buf = Vec::with_capacity(size);
285
286 buf.extend_from_slice(&self.version.to_le_bytes());
288 buf.extend_from_slice(&self.node_id.as_u32().to_le_bytes());
289
290 buf.extend_from_slice(&counter_data);
292
293 if let Some(pdata) = peripheral_data {
295 buf.push(EXTENDED_MARKER);
296 buf.push(0); buf.extend_from_slice(&(pdata.len() as u16).to_le_bytes());
298 buf.extend_from_slice(&pdata);
299 }
300
301 if let Some(edata) = emergency_data {
303 buf.push(EMERGENCY_MARKER);
304 buf.push(0); buf.extend_from_slice(&(edata.len() as u16).to_le_bytes());
306 buf.extend_from_slice(&edata);
307 }
308
309 buf
310 }
311
312 pub fn decode(data: &[u8]) -> Option<Self> {
314 if data.len() < MIN_DOCUMENT_SIZE {
315 return None;
316 }
317
318 let version = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
320 let node_id = NodeId::new(u32::from_le_bytes([data[4], data[5], data[6], data[7]]));
321
322 let counter = GCounter::decode(&data[8..])?;
324
325 let num_entries = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize;
327 let mut offset = 8 + 4 + num_entries * 12;
328
329 let mut peripheral = None;
330 let mut emergency = None;
331
332 while offset < data.len() {
334 let marker = data[offset];
335
336 if marker == EXTENDED_MARKER {
337 if data.len() < offset + 4 {
339 break;
340 }
341 let _reserved = data[offset + 1];
342 let section_len = u16::from_le_bytes([data[offset + 2], data[offset + 3]]) as usize;
343
344 let section_start = offset + 4;
345 if data.len() < section_start + section_len {
346 break;
347 }
348
349 peripheral = Peripheral::decode(&data[section_start..section_start + section_len]);
350 offset = section_start + section_len;
351 } else if marker == EMERGENCY_MARKER {
352 if data.len() < offset + 4 {
354 break;
355 }
356 let _reserved = data[offset + 1];
357 let section_len = u16::from_le_bytes([data[offset + 2], data[offset + 3]]) as usize;
358
359 let section_start = offset + 4;
360 if data.len() < section_start + section_len {
361 break;
362 }
363
364 emergency =
365 EmergencyEvent::decode(&data[section_start..section_start + section_len]);
366 offset = section_start + section_len;
367 } else {
368 break;
370 }
371 }
372
373 Some(Self {
374 version,
375 node_id,
376 counter,
377 peripheral,
378 emergency,
379 })
380 }
381
382 pub fn total_count(&self) -> u64 {
384 self.counter.value()
385 }
386
387 pub fn encoded_size(&self) -> usize {
391 let counter_size = 4 + self.counter.node_count_total() * 12;
392 let peripheral_size = self.peripheral.as_ref().map_or(0, |p| 4 + p.encode().len());
393 let emergency_size = self.emergency.as_ref().map_or(0, |e| 4 + e.encode().len());
394 8 + counter_size + peripheral_size + emergency_size
395 }
396
397 pub fn exceeds_target_size(&self) -> bool {
401 self.encoded_size() > TARGET_DOCUMENT_SIZE
402 }
403
404 pub fn exceeds_max_size(&self) -> bool {
408 self.encoded_size() > MAX_DOCUMENT_SIZE
409 }
410}
411
412#[derive(Debug, Clone)]
414pub struct MergeResult {
415 pub source_node: NodeId,
417
418 pub event: Option<PeripheralEvent>,
420
421 pub counter_changed: bool,
423
424 pub emergency_changed: bool,
426
427 pub total_count: u64,
429}
430
431impl MergeResult {
432 pub fn is_emergency(&self) -> bool {
434 self.event
435 .as_ref()
436 .is_some_and(|e| e.event_type == EventType::Emergency)
437 }
438
439 pub fn is_ack(&self) -> bool {
441 self.event
442 .as_ref()
443 .is_some_and(|e| e.event_type == EventType::Ack)
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use super::*;
450 use crate::sync::crdt::PeripheralType;
451
452 #[test]
453 fn test_document_encode_decode_minimal() {
454 let node_id = NodeId::new(0x12345678);
455 let doc = HiveDocument::new(node_id);
456
457 let encoded = doc.encode();
458 assert_eq!(encoded.len(), 12); let decoded = HiveDocument::decode(&encoded).unwrap();
461 assert_eq!(decoded.version, 1);
462 assert_eq!(decoded.node_id.as_u32(), 0x12345678);
463 assert_eq!(decoded.counter.value(), 0);
464 assert!(decoded.peripheral.is_none());
465 }
466
467 #[test]
468 fn test_document_encode_decode_with_counter() {
469 let node_id = NodeId::new(0x12345678);
470 let mut doc = HiveDocument::new(node_id);
471 doc.increment_counter();
472 doc.increment_counter();
473
474 let encoded = doc.encode();
475 assert_eq!(encoded.len(), 24);
477
478 let decoded = HiveDocument::decode(&encoded).unwrap();
479 assert_eq!(decoded.counter.value(), 2);
480 }
481
482 #[test]
483 fn test_document_encode_decode_with_peripheral() {
484 let node_id = NodeId::new(0x12345678);
485 let peripheral =
486 Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor).with_callsign("ALPHA-1");
487
488 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
489
490 let encoded = doc.encode();
491 let decoded = HiveDocument::decode(&encoded).unwrap();
492
493 assert!(decoded.peripheral.is_some());
494 let p = decoded.peripheral.unwrap();
495 assert_eq!(p.id, 0xAABBCCDD);
496 assert_eq!(p.callsign_str(), "ALPHA-1");
497 }
498
499 #[test]
500 fn test_document_encode_decode_with_event() {
501 let node_id = NodeId::new(0x12345678);
502 let mut peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor);
503 peripheral.set_event(EventType::Emergency, 1234567890);
504
505 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
506
507 let encoded = doc.encode();
508 let decoded = HiveDocument::decode(&encoded).unwrap();
509
510 assert!(decoded.peripheral.is_some());
511 let p = decoded.peripheral.unwrap();
512 assert!(p.last_event.is_some());
513 let event = p.last_event.unwrap();
514 assert_eq!(event.event_type, EventType::Emergency);
515 assert_eq!(event.timestamp, 1234567890);
516 }
517
518 #[test]
519 fn test_document_merge() {
520 let node1 = NodeId::new(0x11111111);
521 let node2 = NodeId::new(0x22222222);
522
523 let mut doc1 = HiveDocument::new(node1);
524 doc1.increment_counter();
525
526 let mut doc2 = HiveDocument::new(node2);
527 doc2.counter.increment(&node2, 3);
528
529 let changed = doc1.merge(&doc2);
531 assert!(changed);
532 assert_eq!(doc1.counter.value(), 4); }
534
535 #[test]
536 fn test_merge_result_helpers() {
537 let emergency_event = PeripheralEvent::new(EventType::Emergency, 123);
538 let result = MergeResult {
539 source_node: NodeId::new(0x12345678),
540 event: Some(emergency_event),
541 counter_changed: true,
542 emergency_changed: false,
543 total_count: 10,
544 };
545
546 assert!(result.is_emergency());
547 assert!(!result.is_ack());
548
549 let ack_event = PeripheralEvent::new(EventType::Ack, 456);
550 let result = MergeResult {
551 source_node: NodeId::new(0x12345678),
552 event: Some(ack_event),
553 counter_changed: false,
554 emergency_changed: false,
555 total_count: 10,
556 };
557
558 assert!(!result.is_emergency());
559 assert!(result.is_ack());
560 }
561
562 #[test]
563 fn test_document_size_calculation() {
564 use crate::sync::crdt::PeripheralType;
565
566 let node_id = NodeId::new(0x12345678);
567
568 let doc = HiveDocument::new(node_id);
570 assert_eq!(doc.encoded_size(), 12);
571 assert!(!doc.exceeds_target_size());
572
573 let mut doc = HiveDocument::new(node_id);
575 doc.increment_counter();
576 assert_eq!(doc.encoded_size(), 24);
577
578 let peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor);
580 let doc = HiveDocument::new(node_id).with_peripheral(peripheral);
581 let encoded = doc.encode();
582 assert_eq!(doc.encoded_size(), encoded.len());
583
584 let mut doc = HiveDocument::new(node_id);
586 for i in 0..10 {
587 doc.counter.increment(&NodeId::new(i), 1);
588 }
589 assert!(doc.encoded_size() < TARGET_DOCUMENT_SIZE);
590 assert!(!doc.exceeds_max_size());
591 }
592}