1#[cfg(not(feature = "std"))]
26use alloc::{collections::BTreeMap, string::String, string::ToString, vec, vec::Vec};
27#[cfg(feature = "std")]
28use std::collections::BTreeMap;
29
30use crate::NodeId;
31
32pub const MIN_VALID_TIMESTAMP: u64 = 1577836800000;
41
42pub const MAX_BATTERY_PERCENT: u8 = 100;
44
45pub const MIN_HEART_RATE: u8 = 20;
47
48pub const MAX_HEART_RATE: u8 = 250;
50
51pub const MAX_EMERGENCY_ACKS: usize = 256;
53
54pub const MAX_COUNTER_ENTRIES: usize = 256;
56
57pub type Timestamp = u64;
59
60#[derive(Debug, Clone, PartialEq)]
65pub struct LwwRegister<T: Clone> {
66 value: T,
68 timestamp: Timestamp,
70 node_id: NodeId,
72}
73
74impl<T: Clone + Default> Default for LwwRegister<T> {
75 fn default() -> Self {
76 Self {
77 value: T::default(),
78 timestamp: 0,
79 node_id: NodeId::default(),
80 }
81 }
82}
83
84impl<T: Clone> LwwRegister<T> {
85 pub fn new(value: T, timestamp: Timestamp, node_id: NodeId) -> Self {
87 Self {
88 value,
89 timestamp,
90 node_id,
91 }
92 }
93
94 pub fn get(&self) -> &T {
96 &self.value
97 }
98
99 pub fn timestamp(&self) -> Timestamp {
101 self.timestamp
102 }
103
104 pub fn node_id(&self) -> &NodeId {
106 &self.node_id
107 }
108
109 pub fn set(&mut self, value: T, timestamp: Timestamp, node_id: NodeId) -> bool {
113 if self.should_update(timestamp, &node_id) {
114 self.value = value;
115 self.timestamp = timestamp;
116 self.node_id = node_id;
117 true
118 } else {
119 false
120 }
121 }
122
123 pub fn merge(&mut self, other: &LwwRegister<T>) -> bool {
127 if self.should_update(other.timestamp, &other.node_id) {
128 self.value = other.value.clone();
129 self.timestamp = other.timestamp;
130 self.node_id = other.node_id;
131 true
132 } else {
133 false
134 }
135 }
136
137 fn should_update(&self, timestamp: Timestamp, node_id: &NodeId) -> bool {
139 timestamp > self.timestamp
140 || (timestamp == self.timestamp && node_id.as_u32() > self.node_id.as_u32())
141 }
142}
143
144#[derive(Debug, Clone, Default)]
149pub struct GCounter {
150 counts: BTreeMap<u32, u64>,
152}
153
154impl GCounter {
155 pub fn new() -> Self {
157 Self {
158 counts: BTreeMap::new(),
159 }
160 }
161
162 pub fn value(&self) -> u64 {
164 self.counts.values().sum()
165 }
166
167 pub fn increment(&mut self, node_id: &NodeId, amount: u64) {
169 let count = self.counts.entry(node_id.as_u32()).or_insert(0);
170 *count = count.saturating_add(amount);
171 }
172
173 pub fn node_count(&self, node_id: &NodeId) -> u64 {
175 self.counts.get(&node_id.as_u32()).copied().unwrap_or(0)
176 }
177
178 pub fn merge(&mut self, other: &GCounter) {
182 for (&node_id, &count) in &other.counts {
183 let our_count = self.counts.entry(node_id).or_insert(0);
184 *our_count = (*our_count).max(count);
185 }
186 }
187
188 pub fn node_count_total(&self) -> usize {
190 self.counts.len()
191 }
192
193 pub fn entries(&self) -> impl Iterator<Item = (u32, u64)> + '_ {
198 self.counts.iter().map(|(&k, &v)| (k, v))
199 }
200
201 pub fn encode(&self) -> Vec<u8> {
203 let mut buf = Vec::with_capacity(4 + self.counts.len() * 12);
204 buf.extend_from_slice(&(self.counts.len() as u32).to_le_bytes());
206 for (&node_id, &count) in &self.counts {
208 buf.extend_from_slice(&node_id.to_le_bytes());
209 buf.extend_from_slice(&count.to_le_bytes());
210 }
211 buf
212 }
213
214 pub fn decode(data: &[u8]) -> Option<Self> {
220 if data.len() < 4 {
221 return None;
222 }
223 let num_entries = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
224
225 if num_entries > MAX_COUNTER_ENTRIES {
227 return None;
228 }
229
230 if data.len() < 4 + num_entries * 12 {
231 return None;
232 }
233
234 let mut counts = BTreeMap::new();
235 let mut offset = 4;
236 for _ in 0..num_entries {
237 let node_id = u32::from_le_bytes([
238 data[offset],
239 data[offset + 1],
240 data[offset + 2],
241 data[offset + 3],
242 ]);
243 let count = u64::from_le_bytes([
244 data[offset + 4],
245 data[offset + 5],
246 data[offset + 6],
247 data[offset + 7],
248 data[offset + 8],
249 data[offset + 9],
250 data[offset + 10],
251 data[offset + 11],
252 ]);
253 if node_id != 0 {
255 counts.insert(node_id, count);
256 }
257 offset += 12;
258 }
259
260 Some(Self { counts })
261 }
262}
263
264#[derive(Debug, Clone, Default, PartialEq)]
266pub struct Position {
267 pub latitude: f32,
269 pub longitude: f32,
271 pub altitude: Option<f32>,
273 pub accuracy: Option<f32>,
275}
276
277impl Position {
278 pub fn new(latitude: f32, longitude: f32) -> Self {
280 Self {
281 latitude,
282 longitude,
283 altitude: None,
284 accuracy: None,
285 }
286 }
287
288 pub fn with_altitude(mut self, altitude: f32) -> Self {
290 self.altitude = Some(altitude);
291 self
292 }
293
294 pub fn with_accuracy(mut self, accuracy: f32) -> Self {
296 self.accuracy = Some(accuracy);
297 self
298 }
299
300 pub fn encode(&self) -> Vec<u8> {
302 let mut buf = Vec::with_capacity(20);
303 buf.extend_from_slice(&self.latitude.to_le_bytes());
304 buf.extend_from_slice(&self.longitude.to_le_bytes());
305
306 let mut flags = 0u8;
308 if self.altitude.is_some() {
309 flags |= 0x01;
310 }
311 if self.accuracy.is_some() {
312 flags |= 0x02;
313 }
314 buf.push(flags);
315
316 if let Some(alt) = self.altitude {
317 buf.extend_from_slice(&alt.to_le_bytes());
318 }
319 if let Some(acc) = self.accuracy {
320 buf.extend_from_slice(&acc.to_le_bytes());
321 }
322 buf
323 }
324
325 pub fn decode(data: &[u8]) -> Option<Self> {
331 if data.len() < 9 {
332 return None;
333 }
334
335 let latitude = f32::from_le_bytes([data[0], data[1], data[2], data[3]]);
336 let longitude = f32::from_le_bytes([data[4], data[5], data[6], data[7]]);
337 let flags = data[8];
338
339 if !latitude.is_finite() || !longitude.is_finite() {
341 return None;
342 }
343 if !(-90.0..=90.0).contains(&latitude) {
344 return None;
345 }
346 if !(-180.0..=180.0).contains(&longitude) {
347 return None;
348 }
349
350 let mut pos = Self::new(latitude, longitude);
351 let mut offset = 9;
352
353 if flags & 0x01 != 0 {
354 if data.len() < offset + 4 {
355 return None;
356 }
357 let alt = f32::from_le_bytes([
358 data[offset],
359 data[offset + 1],
360 data[offset + 2],
361 data[offset + 3],
362 ]);
363 if !alt.is_finite() || !(-1000.0..=100000.0).contains(&alt) {
365 return None;
366 }
367 pos.altitude = Some(alt);
368 offset += 4;
369 }
370
371 if flags & 0x02 != 0 {
372 if data.len() < offset + 4 {
373 return None;
374 }
375 let acc = f32::from_le_bytes([
376 data[offset],
377 data[offset + 1],
378 data[offset + 2],
379 data[offset + 3],
380 ]);
381 if !acc.is_finite() || acc < 0.0 {
383 return None;
384 }
385 pos.accuracy = Some(acc);
386 }
387
388 Some(pos)
389 }
390}
391
392#[derive(Debug, Clone, Default, PartialEq)]
394pub struct HealthStatus {
395 pub battery_percent: u8,
397 pub heart_rate: Option<u8>,
399 pub activity: u8,
401 pub alerts: u8,
403}
404
405impl HealthStatus {
406 pub const ALERT_MAN_DOWN: u8 = 0x01;
408 pub const ALERT_LOW_BATTERY: u8 = 0x02;
410 pub const ALERT_OUT_OF_RANGE: u8 = 0x04;
412 pub const ALERT_CUSTOM_1: u8 = 0x08;
414
415 pub fn new(battery_percent: u8) -> Self {
417 Self {
418 battery_percent,
419 heart_rate: None,
420 activity: 0,
421 alerts: 0,
422 }
423 }
424
425 pub fn with_heart_rate(mut self, hr: u8) -> Self {
427 self.heart_rate = Some(hr);
428 self
429 }
430
431 pub fn with_activity(mut self, activity: u8) -> Self {
433 self.activity = activity;
434 self
435 }
436
437 pub fn set_alert(&mut self, flag: u8) {
439 self.alerts |= flag;
440 }
441
442 pub fn clear_alert(&mut self, flag: u8) {
444 self.alerts &= !flag;
445 }
446
447 pub fn has_alert(&self, flag: u8) -> bool {
449 self.alerts & flag != 0
450 }
451
452 pub fn encode(&self) -> Vec<u8> {
454 vec![
455 self.battery_percent,
456 self.activity,
457 self.alerts,
458 self.heart_rate.unwrap_or(0),
460 ]
461 }
462
463 pub fn decode(data: &[u8]) -> Option<Self> {
469 if data.len() < 4 {
470 return None;
471 }
472
473 let battery_percent = data[0];
474 let activity = data[1];
475 let alerts = data[2];
476 let heart_rate_raw = data[3];
477
478 if battery_percent > MAX_BATTERY_PERCENT {
480 return None;
481 }
482
483 if activity > 3 {
485 return None;
486 }
487
488 let mut status = Self::new(battery_percent);
489 status.activity = activity;
490 status.alerts = alerts;
491
492 if heart_rate_raw > 0 {
494 if !(MIN_HEART_RATE..=MAX_HEART_RATE).contains(&heart_rate_raw) {
495 return None;
496 }
497 status.heart_rate = Some(heart_rate_raw);
498 }
499
500 Some(status)
501 }
502}
503
504#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
510#[repr(u8)]
511pub enum PeripheralType {
512 #[default]
514 Unknown = 0,
515 SoldierSensor = 1,
517 FixedSensor = 2,
519 Relay = 3,
521}
522
523impl PeripheralType {
524 pub fn from_u8(v: u8) -> Self {
526 match v {
527 1 => Self::SoldierSensor,
528 2 => Self::FixedSensor,
529 3 => Self::Relay,
530 _ => Self::Unknown,
531 }
532 }
533}
534
535#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
537#[repr(u8)]
538pub enum EventType {
539 #[default]
541 None = 0,
542 Ping = 1,
544 NeedAssist = 2,
546 Emergency = 3,
548 Moving = 4,
550 InPosition = 5,
552 Ack = 6,
554}
555
556impl EventType {
557 pub fn from_u8(v: u8) -> Self {
559 match v {
560 1 => Self::Ping,
561 2 => Self::NeedAssist,
562 3 => Self::Emergency,
563 4 => Self::Moving,
564 5 => Self::InPosition,
565 6 => Self::Ack,
566 _ => Self::None,
567 }
568 }
569
570 pub fn label(&self) -> &'static str {
572 match self {
573 Self::None => "",
574 Self::Ping => "PING",
575 Self::NeedAssist => "NEED ASSIST",
576 Self::Emergency => "EMERGENCY",
577 Self::Moving => "MOVING",
578 Self::InPosition => "IN POSITION",
579 Self::Ack => "ACK",
580 }
581 }
582}
583
584#[derive(Debug, Clone, Default, PartialEq)]
586pub struct PeripheralEvent {
587 pub event_type: EventType,
589 pub timestamp: u64,
591}
592
593impl PeripheralEvent {
594 pub fn new(event_type: EventType, timestamp: u64) -> Self {
596 Self {
597 event_type,
598 timestamp,
599 }
600 }
601
602 pub fn encode(&self) -> Vec<u8> {
604 let mut buf = Vec::with_capacity(9);
605 buf.push(self.event_type as u8);
606 buf.extend_from_slice(&self.timestamp.to_le_bytes());
607 buf
608 }
609
610 pub fn decode(data: &[u8]) -> Option<Self> {
616 if data.len() < 9 {
617 return None;
618 }
619
620 let event_type = EventType::from_u8(data[0]);
621 let timestamp = u64::from_le_bytes([
622 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
623 ]);
624
625 if timestamp != 0 && timestamp < MIN_VALID_TIMESTAMP {
628 return None;
629 }
630
631 Some(Self {
632 event_type,
633 timestamp,
634 })
635 }
636}
637
638#[derive(Debug, Clone, PartialEq, Default)]
662pub struct EmergencyEvent {
663 source_node: u32,
665 timestamp: u64,
667 acks: BTreeMap<u32, bool>,
669}
670
671impl EmergencyEvent {
672 pub fn new(source_node: u32, timestamp: u64, known_peers: &[u32]) -> Self {
681 let mut acks = BTreeMap::new();
682
683 acks.insert(source_node, true);
685
686 for &peer_id in known_peers {
688 if peer_id != source_node {
689 acks.entry(peer_id).or_insert(false);
690 }
691 }
692
693 Self {
694 source_node,
695 timestamp,
696 acks,
697 }
698 }
699
700 pub fn source_node(&self) -> u32 {
702 self.source_node
703 }
704
705 pub fn timestamp(&self) -> u64 {
707 self.timestamp
708 }
709
710 pub fn has_acked(&self, node_id: u32) -> bool {
712 self.acks.get(&node_id).copied().unwrap_or(false)
713 }
714
715 pub fn ack(&mut self, node_id: u32) -> bool {
719 let entry = self.acks.entry(node_id).or_insert(false);
720 if !*entry {
721 *entry = true;
722 true
723 } else {
724 false
725 }
726 }
727
728 pub fn add_peer(&mut self, node_id: u32) {
733 self.acks.entry(node_id).or_insert(false);
734 }
735
736 pub fn acked_nodes(&self) -> Vec<u32> {
738 self.acks
739 .iter()
740 .filter(|(_, &acked)| acked)
741 .map(|(&node_id, _)| node_id)
742 .collect()
743 }
744
745 pub fn pending_nodes(&self) -> Vec<u32> {
747 self.acks
748 .iter()
749 .filter(|(_, &acked)| !acked)
750 .map(|(&node_id, _)| node_id)
751 .collect()
752 }
753
754 pub fn all_nodes(&self) -> Vec<u32> {
756 self.acks.keys().copied().collect()
757 }
758
759 pub fn all_acked(&self) -> bool {
761 !self.acks.is_empty() && self.acks.values().all(|&acked| acked)
762 }
763
764 pub fn peer_count(&self) -> usize {
766 self.acks.len()
767 }
768
769 pub fn ack_count(&self) -> usize {
771 self.acks.values().filter(|&&acked| acked).count()
772 }
773
774 pub fn merge(&mut self, other: &EmergencyEvent) -> bool {
783 if self.source_node != other.source_node || self.timestamp != other.timestamp {
785 if other.timestamp > self.timestamp {
786 *self = other.clone();
787 return true;
788 }
789 return false;
790 }
791
792 let mut changed = false;
794 for (&node_id, &other_acked) in &other.acks {
795 let entry = self.acks.entry(node_id).or_insert(false);
796 if other_acked && !*entry {
797 *entry = true;
798 changed = true;
799 }
800 }
801 changed
802 }
803
804 pub fn encode(&self) -> Vec<u8> {
808 let mut buf = Vec::with_capacity(16 + self.acks.len() * 5);
809
810 buf.extend_from_slice(&self.source_node.to_le_bytes());
811 buf.extend_from_slice(&self.timestamp.to_le_bytes());
812 buf.extend_from_slice(&(self.acks.len() as u32).to_le_bytes());
813
814 for (&node_id, &acked) in &self.acks {
815 buf.extend_from_slice(&node_id.to_le_bytes());
816 buf.push(if acked { 1 } else { 0 });
817 }
818
819 buf
820 }
821
822 pub fn decode(data: &[u8]) -> Option<Self> {
828 if data.len() < 16 {
829 return None;
830 }
831
832 let source_node = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
833 let timestamp = u64::from_le_bytes([
834 data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11],
835 ]);
836 let num_acks = u32::from_le_bytes([data[12], data[13], data[14], data[15]]) as usize;
837
838 if source_node == 0 {
840 return None;
841 }
842
843 if timestamp < MIN_VALID_TIMESTAMP {
845 return None;
846 }
847
848 if num_acks > MAX_EMERGENCY_ACKS {
850 return None;
851 }
852
853 if data.len() < 16 + num_acks * 5 {
854 return None;
855 }
856
857 let mut acks = BTreeMap::new();
858 let mut offset = 16;
859 for _ in 0..num_acks {
860 let node_id = u32::from_le_bytes([
861 data[offset],
862 data[offset + 1],
863 data[offset + 2],
864 data[offset + 3],
865 ]);
866 if node_id != 0 {
868 let acked = data[offset + 4] != 0;
869 acks.insert(node_id, acked);
870 }
871 offset += 5;
872 }
873
874 Some(Self {
875 source_node,
876 timestamp,
877 acks,
878 })
879 }
880}
881
882#[derive(Debug, Clone, Default)]
887pub struct Peripheral {
888 pub id: u32,
890 pub parent_node: u32,
892 pub peripheral_type: PeripheralType,
894 pub callsign: [u8; 12],
896 pub health: HealthStatus,
898 pub last_event: Option<PeripheralEvent>,
900 pub location: Option<Position>,
902 pub timestamp: u64,
904}
905
906impl Peripheral {
907 pub fn new(id: u32, peripheral_type: PeripheralType) -> Self {
909 Self {
910 id,
911 parent_node: 0,
912 peripheral_type,
913 callsign: [0u8; 12],
914 health: HealthStatus::default(),
915 last_event: None,
916 location: None,
917 timestamp: 0,
918 }
919 }
920
921 pub fn with_callsign(mut self, callsign: &str) -> Self {
923 let bytes = callsign.as_bytes();
924 let len = bytes.len().min(12);
925 self.callsign[..len].copy_from_slice(&bytes[..len]);
926 self
927 }
928
929 pub fn set_callsign(&mut self, callsign: &str) {
931 self.callsign = [0u8; 12];
932 let bytes = callsign.as_bytes();
933 let len = bytes.len().min(12);
934 self.callsign[..len].copy_from_slice(&bytes[..len]);
935 }
936
937 pub fn callsign_str(&self) -> &str {
939 let len = self.callsign.iter().position(|&b| b == 0).unwrap_or(12);
940 core::str::from_utf8(&self.callsign[..len]).unwrap_or("")
941 }
942
943 pub fn with_parent(mut self, parent_node: u32) -> Self {
945 self.parent_node = parent_node;
946 self
947 }
948
949 pub fn with_location(mut self, location: Position) -> Self {
951 self.location = Some(location);
952 self
953 }
954
955 pub fn set_location(&mut self, latitude: f32, longitude: f32, altitude: Option<f32>) {
957 let mut pos = Position::new(latitude, longitude);
958 if let Some(alt) = altitude {
959 pos = pos.with_altitude(alt);
960 }
961 self.location = Some(pos);
962 }
963
964 pub fn clear_location(&mut self) {
966 self.location = None;
967 }
968
969 pub fn set_event(&mut self, event_type: EventType, timestamp: u64) {
971 self.last_event = Some(PeripheralEvent::new(event_type, timestamp));
972 self.timestamp = timestamp;
973 }
974
975 pub fn clear_event(&mut self) {
977 self.last_event = None;
978 }
979
980 pub fn encode(&self) -> Vec<u8> {
984 let mut buf = Vec::with_capacity(64);
985 buf.extend_from_slice(&self.id.to_le_bytes());
986 buf.extend_from_slice(&self.parent_node.to_le_bytes());
987 buf.push(self.peripheral_type as u8);
988 buf.extend_from_slice(&self.callsign);
989 buf.extend_from_slice(&self.health.encode());
990
991 if let Some(ref event) = self.last_event {
992 buf.push(1); buf.extend_from_slice(&event.encode());
994 } else {
995 buf.push(0); }
997
998 buf.extend_from_slice(&self.timestamp.to_le_bytes());
999
1000 if let Some(ref location) = self.location {
1002 buf.push(1); buf.extend_from_slice(&location.encode());
1004 } else {
1005 buf.push(0); }
1007
1008 buf
1009 }
1010
1011 pub fn decode(data: &[u8]) -> Option<Self> {
1017 if data.len() < 34 {
1018 return None;
1019 }
1020
1021 let id = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
1022 let parent_node = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
1023 let peripheral_type = PeripheralType::from_u8(data[8]);
1024
1025 if id == 0 {
1027 return None;
1028 }
1029
1030 let mut callsign = [0u8; 12];
1031 callsign.copy_from_slice(&data[9..21]);
1032
1033 let callsign_len = callsign.iter().position(|&b| b == 0).unwrap_or(12);
1036 if callsign_len > 0 && core::str::from_utf8(&callsign[..callsign_len]).is_err() {
1037 return None;
1038 }
1039
1040 let health = HealthStatus::decode(&data[21..25])?;
1042
1043 let has_event = data[25] != 0;
1044 let (last_event, timestamp_offset) = if has_event {
1045 if data.len() < 43 {
1046 return None;
1047 }
1048 (PeripheralEvent::decode(&data[26..35]), 35)
1050 } else {
1051 (None, 26)
1052 };
1053
1054 if data.len() < timestamp_offset + 8 {
1055 return None;
1056 }
1057
1058 let timestamp = u64::from_le_bytes([
1059 data[timestamp_offset],
1060 data[timestamp_offset + 1],
1061 data[timestamp_offset + 2],
1062 data[timestamp_offset + 3],
1063 data[timestamp_offset + 4],
1064 data[timestamp_offset + 5],
1065 data[timestamp_offset + 6],
1066 data[timestamp_offset + 7],
1067 ]);
1068
1069 if timestamp != 0 && timestamp < MIN_VALID_TIMESTAMP {
1071 return None;
1072 }
1073
1074 let location_offset = timestamp_offset + 8;
1077 let location = if data.len() > location_offset {
1078 let has_location = data[location_offset] != 0;
1079 if has_location && data.len() > location_offset + 1 {
1080 Position::decode(&data[location_offset + 1..])
1081 } else {
1082 None
1083 }
1084 } else {
1085 None
1086 };
1087
1088 Some(Self {
1089 id,
1090 parent_node,
1091 peripheral_type,
1092 callsign,
1093 health,
1094 last_event,
1095 location,
1096 timestamp,
1097 })
1098 }
1099}
1100
1101pub const CHAT_MAX_TEXT_LEN: usize = 128;
1107
1108pub const CHAT_MAX_SENDER_LEN: usize = 12;
1110
1111pub const CHAT_MAX_MESSAGES: usize = 32;
1115
1116pub const CHAT_SYNC_LIMIT: usize = 8;
1122
1123#[derive(Debug, Clone, PartialEq)]
1128pub struct ChatMessage {
1129 pub origin_node: u32,
1131 pub timestamp: u64,
1133 sender: [u8; CHAT_MAX_SENDER_LEN],
1135 sender_len: u8,
1136 text: [u8; CHAT_MAX_TEXT_LEN],
1138 text_len: u8,
1139 pub is_broadcast: bool,
1141 pub requires_ack: bool,
1143 pub reply_to_node: u32,
1145 pub reply_to_timestamp: u64,
1147}
1148
1149impl Default for ChatMessage {
1150 fn default() -> Self {
1151 Self {
1152 origin_node: 0,
1153 timestamp: 0,
1154 sender: [0u8; CHAT_MAX_SENDER_LEN],
1155 sender_len: 0,
1156 text: [0u8; CHAT_MAX_TEXT_LEN],
1157 text_len: 0,
1158 is_broadcast: true,
1159 requires_ack: false,
1160 reply_to_node: 0,
1161 reply_to_timestamp: 0,
1162 }
1163 }
1164}
1165
1166impl ChatMessage {
1167 pub fn new(origin_node: u32, timestamp: u64, sender: &str, text: &str) -> Self {
1169 let mut msg = Self {
1170 origin_node,
1171 timestamp,
1172 ..Default::default()
1173 };
1174 msg.set_sender(sender);
1175 msg.set_text(text);
1176 msg
1177 }
1178
1179 pub fn set_sender(&mut self, sender: &str) {
1181 let bytes = sender.as_bytes();
1182 let len = bytes.len().min(CHAT_MAX_SENDER_LEN);
1183 self.sender[..len].copy_from_slice(&bytes[..len]);
1184 self.sender_len = len as u8;
1185 }
1186
1187 pub fn sender(&self) -> &str {
1189 core::str::from_utf8(&self.sender[..self.sender_len as usize]).unwrap_or("")
1190 }
1191
1192 pub fn set_text(&mut self, text: &str) {
1194 let bytes = text.as_bytes();
1195 let len = bytes.len().min(CHAT_MAX_TEXT_LEN);
1196 self.text[..len].copy_from_slice(&bytes[..len]);
1197 self.text_len = len as u8;
1198 }
1199
1200 pub fn text(&self) -> &str {
1202 core::str::from_utf8(&self.text[..self.text_len as usize]).unwrap_or("")
1203 }
1204
1205 pub fn set_reply_to(&mut self, node: u32, timestamp: u64) {
1207 self.reply_to_node = node;
1208 self.reply_to_timestamp = timestamp;
1209 }
1210
1211 pub fn is_reply(&self) -> bool {
1213 self.reply_to_node != 0 || self.reply_to_timestamp != 0
1214 }
1215
1216 pub fn message_id(&self) -> u64 {
1221 ((self.origin_node as u64) << 32) | (self.timestamp & 0xFFFFFFFF)
1222 }
1223
1224 pub fn encode(&self) -> Vec<u8> {
1239 let size = 4 + 8 + 1 + self.sender_len as usize + 1 + self.text_len as usize + 1 + 4 + 8;
1240 let mut buf = Vec::with_capacity(size);
1241
1242 buf.extend_from_slice(&self.origin_node.to_le_bytes());
1243 buf.extend_from_slice(&self.timestamp.to_le_bytes());
1244 buf.push(self.sender_len);
1245 buf.extend_from_slice(&self.sender[..self.sender_len as usize]);
1246 buf.push(self.text_len);
1247 buf.extend_from_slice(&self.text[..self.text_len as usize]);
1248
1249 let mut flags = 0u8;
1250 if self.is_broadcast {
1251 flags |= 0x01;
1252 }
1253 if self.requires_ack {
1254 flags |= 0x02;
1255 }
1256 buf.push(flags);
1257
1258 buf.extend_from_slice(&self.reply_to_node.to_le_bytes());
1259 buf.extend_from_slice(&self.reply_to_timestamp.to_le_bytes());
1260
1261 buf
1262 }
1263
1264 pub fn decode(data: &[u8]) -> Option<(Self, usize)> {
1277 if data.len() < 14 {
1278 return None;
1280 }
1281
1282 let origin_node = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
1283 let timestamp = u64::from_le_bytes([
1284 data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11],
1285 ]);
1286
1287 if origin_node == 0 {
1289 return None;
1290 }
1291
1292 if timestamp < MIN_VALID_TIMESTAMP {
1294 return None;
1295 }
1296
1297 let sender_len = data[12] as usize;
1298 if sender_len > CHAT_MAX_SENDER_LEN || data.len() < 13 + sender_len + 1 {
1299 return None;
1300 }
1301
1302 if sender_len == 0 {
1304 return None;
1305 }
1306
1307 let mut sender = [0u8; CHAT_MAX_SENDER_LEN];
1308 sender[..sender_len].copy_from_slice(&data[13..13 + sender_len]);
1309
1310 if core::str::from_utf8(&sender[..sender_len]).is_err() {
1312 return None;
1313 }
1314
1315 let text_offset = 13 + sender_len;
1316 let text_len = data[text_offset] as usize;
1317 if text_len > CHAT_MAX_TEXT_LEN || data.len() < text_offset + 1 + text_len + 1 {
1318 return None;
1319 }
1320
1321 let mut text = [0u8; CHAT_MAX_TEXT_LEN];
1322 text[..text_len].copy_from_slice(&data[text_offset + 1..text_offset + 1 + text_len]);
1323
1324 if text_len > 0 && core::str::from_utf8(&text[..text_len]).is_err() {
1327 return None;
1328 }
1329
1330 let flags_offset = text_offset + 1 + text_len;
1331 let flags = data[flags_offset];
1332 let is_broadcast = flags & 0x01 != 0;
1333 let requires_ack = flags & 0x02 != 0;
1334
1335 let mut reply_to_node = 0u32;
1337 let mut reply_to_timestamp = 0u64;
1338 let mut total_len = flags_offset + 1;
1339
1340 if data.len() >= flags_offset + 1 + 12 {
1341 reply_to_node = u32::from_le_bytes([
1342 data[flags_offset + 1],
1343 data[flags_offset + 2],
1344 data[flags_offset + 3],
1345 data[flags_offset + 4],
1346 ]);
1347 reply_to_timestamp = u64::from_le_bytes([
1348 data[flags_offset + 5],
1349 data[flags_offset + 6],
1350 data[flags_offset + 7],
1351 data[flags_offset + 8],
1352 data[flags_offset + 9],
1353 data[flags_offset + 10],
1354 data[flags_offset + 11],
1355 data[flags_offset + 12],
1356 ]);
1357 total_len = flags_offset + 13;
1358 }
1359
1360 Some((
1361 Self {
1362 origin_node,
1363 timestamp,
1364 sender,
1365 sender_len: sender_len as u8,
1366 text,
1367 text_len: text_len as u8,
1368 is_broadcast,
1369 requires_ack,
1370 reply_to_node,
1371 reply_to_timestamp,
1372 },
1373 total_len,
1374 ))
1375 }
1376}
1377
1378#[derive(Debug, Clone, Default)]
1398pub struct ChatCRDT {
1399 messages: BTreeMap<u64, ChatMessage>,
1401}
1402
1403impl ChatCRDT {
1404 pub fn new() -> Self {
1406 Self {
1407 messages: BTreeMap::new(),
1408 }
1409 }
1410
1411 pub fn add_message(&mut self, message: ChatMessage) -> bool {
1415 let id = message.message_id();
1416 if self.messages.contains_key(&id) {
1417 return false;
1418 }
1419
1420 self.messages.insert(id, message);
1421 self.prune_if_needed();
1422 true
1423 }
1424
1425 pub fn send_message(
1427 &mut self,
1428 origin_node: u32,
1429 timestamp: u64,
1430 sender: &str,
1431 text: &str,
1432 ) -> bool {
1433 let msg = ChatMessage::new(origin_node, timestamp, sender, text);
1434 self.add_message(msg)
1435 }
1436
1437 pub fn get_message(&self, origin_node: u32, timestamp: u64) -> Option<&ChatMessage> {
1439 let id = ((origin_node as u64) << 32) | (timestamp & 0xFFFFFFFF);
1440 self.messages.get(&id)
1441 }
1442
1443 pub fn messages(&self) -> impl Iterator<Item = &ChatMessage> {
1445 self.messages.values()
1446 }
1447
1448 pub fn messages_since(&self, since_timestamp: u64) -> impl Iterator<Item = &ChatMessage> {
1450 self.messages
1451 .values()
1452 .filter(move |m| m.timestamp > since_timestamp)
1453 }
1454
1455 pub fn len(&self) -> usize {
1457 self.messages.len()
1458 }
1459
1460 pub fn is_empty(&self) -> bool {
1462 self.messages.is_empty()
1463 }
1464
1465 pub fn newest_timestamp(&self) -> Option<u64> {
1467 self.messages.values().map(|m| m.timestamp).max()
1468 }
1469
1470 pub fn merge(&mut self, other: &ChatCRDT) -> bool {
1474 let mut changed = false;
1475 for (id, msg) in &other.messages {
1476 if !self.messages.contains_key(id) {
1477 self.messages.insert(*id, msg.clone());
1478 changed = true;
1479 }
1480 }
1481 if changed {
1482 self.prune_if_needed();
1483 }
1484 changed
1485 }
1486
1487 fn prune_if_needed(&mut self) {
1489 while self.messages.len() > CHAT_MAX_MESSAGES {
1490 if let Some(&oldest_id) = self.messages.keys().next() {
1492 self.messages.remove(&oldest_id);
1493 }
1494 }
1495 }
1496
1497 pub fn encode(&self) -> Vec<u8> {
1499 let mut buf = Vec::new();
1500
1501 buf.extend_from_slice(&(self.messages.len() as u16).to_le_bytes());
1503
1504 for msg in self.messages.values() {
1506 buf.extend_from_slice(&msg.encode());
1507 }
1508
1509 buf
1510 }
1511
1512 pub fn decode(data: &[u8]) -> Option<Self> {
1514 if data.len() < 2 {
1515 return None;
1516 }
1517
1518 let num_messages = u16::from_le_bytes([data[0], data[1]]) as usize;
1519 let mut messages = BTreeMap::new();
1520 let mut offset = 2;
1521
1522 for _ in 0..num_messages {
1523 if offset >= data.len() {
1524 break;
1525 }
1526 if let Some((msg, len)) = ChatMessage::decode(&data[offset..]) {
1527 let id = msg.message_id();
1528 messages.insert(id, msg);
1529 offset += len;
1530 } else {
1531 break;
1532 }
1533 }
1534
1535 Some(Self { messages })
1536 }
1537
1538 pub fn encoded_size(&self) -> usize {
1540 2 + self
1541 .messages
1542 .values()
1543 .map(|m| m.encode().len())
1544 .sum::<usize>()
1545 }
1546
1547 pub fn for_sync(&self) -> Self {
1555 if self.messages.len() <= CHAT_SYNC_LIMIT {
1556 return self.clone();
1557 }
1558
1559 let messages: BTreeMap<u64, ChatMessage> = self
1562 .messages
1563 .iter()
1564 .rev()
1565 .take(CHAT_SYNC_LIMIT)
1566 .map(|(&k, v)| (k, v.clone()))
1567 .collect();
1568
1569 Self { messages }
1570 }
1571}
1572
1573#[derive(Debug, Clone)]
1575pub enum CrdtOperation {
1576 UpdatePosition {
1578 node_id: NodeId,
1580 position: Position,
1582 timestamp: Timestamp,
1584 },
1585 UpdateHealth {
1587 node_id: NodeId,
1589 status: HealthStatus,
1591 timestamp: Timestamp,
1593 },
1594 IncrementCounter {
1596 counter_id: u8,
1598 node_id: NodeId,
1600 amount: u64,
1602 },
1603 UpdateRegister {
1605 key: String,
1607 value: Vec<u8>,
1609 timestamp: Timestamp,
1611 node_id: NodeId,
1613 },
1614}
1615
1616impl CrdtOperation {
1617 pub fn size(&self) -> usize {
1619 match self {
1620 CrdtOperation::UpdatePosition { position, .. } => 4 + 8 + position.encode().len(),
1621 CrdtOperation::UpdateHealth { status, .. } => 4 + 8 + status.encode().len(),
1622 CrdtOperation::IncrementCounter { .. } => 1 + 4 + 8,
1623 CrdtOperation::UpdateRegister { key, value, .. } => 4 + 8 + key.len() + value.len(),
1624 }
1625 }
1626
1627 pub fn encode(&self) -> Vec<u8> {
1629 let mut buf = Vec::new();
1630 match self {
1631 CrdtOperation::UpdatePosition {
1632 node_id,
1633 position,
1634 timestamp,
1635 } => {
1636 buf.push(0x01); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1638 buf.extend_from_slice(×tamp.to_le_bytes());
1639 buf.extend_from_slice(&position.encode());
1640 }
1641 CrdtOperation::UpdateHealth {
1642 node_id,
1643 status,
1644 timestamp,
1645 } => {
1646 buf.push(0x02); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1648 buf.extend_from_slice(×tamp.to_le_bytes());
1649 buf.extend_from_slice(&status.encode());
1650 }
1651 CrdtOperation::IncrementCounter {
1652 counter_id,
1653 node_id,
1654 amount,
1655 } => {
1656 buf.push(0x03); buf.push(*counter_id);
1658 buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1659 buf.extend_from_slice(&amount.to_le_bytes());
1660 }
1661 CrdtOperation::UpdateRegister {
1662 key,
1663 value,
1664 timestamp,
1665 node_id,
1666 } => {
1667 buf.push(0x04); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1669 buf.extend_from_slice(×tamp.to_le_bytes());
1670 buf.push(key.len() as u8);
1671 buf.extend_from_slice(key.as_bytes());
1672 buf.extend_from_slice(&(value.len() as u16).to_le_bytes());
1673 buf.extend_from_slice(value);
1674 }
1675 }
1676 buf
1677 }
1678
1679 pub fn decode(data: &[u8]) -> Option<Self> {
1681 if data.is_empty() {
1682 return None;
1683 }
1684
1685 match data[0] {
1686 0x01 => {
1687 if data.len() < 13 {
1689 return None;
1690 }
1691 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1692 let timestamp = u64::from_le_bytes([
1693 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1694 ]);
1695 let position = Position::decode(&data[13..])?;
1696 Some(CrdtOperation::UpdatePosition {
1697 node_id,
1698 position,
1699 timestamp,
1700 })
1701 }
1702 0x02 => {
1703 if data.len() < 13 {
1705 return None;
1706 }
1707 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1708 let timestamp = u64::from_le_bytes([
1709 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1710 ]);
1711 let status = HealthStatus::decode(&data[13..])?;
1712 Some(CrdtOperation::UpdateHealth {
1713 node_id,
1714 status,
1715 timestamp,
1716 })
1717 }
1718 0x03 => {
1719 if data.len() < 14 {
1721 return None;
1722 }
1723 let counter_id = data[1];
1724 let node_id = NodeId::new(u32::from_le_bytes([data[2], data[3], data[4], data[5]]));
1725 let amount = u64::from_le_bytes([
1726 data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13],
1727 ]);
1728 Some(CrdtOperation::IncrementCounter {
1729 counter_id,
1730 node_id,
1731 amount,
1732 })
1733 }
1734 0x04 => {
1735 if data.len() < 14 {
1737 return None;
1738 }
1739 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1740 let timestamp = u64::from_le_bytes([
1741 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1742 ]);
1743 let key_len = data[13] as usize;
1744 if data.len() < 14 + key_len + 2 {
1745 return None;
1746 }
1747 let key = core::str::from_utf8(&data[14..14 + key_len])
1748 .ok()?
1749 .to_string();
1750 let value_len =
1751 u16::from_le_bytes([data[14 + key_len], data[15 + key_len]]) as usize;
1752 if data.len() < 16 + key_len + value_len {
1753 return None;
1754 }
1755 let value = data[16 + key_len..16 + key_len + value_len].to_vec();
1756 Some(CrdtOperation::UpdateRegister {
1757 key,
1758 value,
1759 timestamp,
1760 node_id,
1761 })
1762 }
1763 _ => None,
1764 }
1765 }
1766}
1767
1768#[cfg(test)]
1769mod tests {
1770 use super::*;
1771
1772 const TEST_TIMESTAMP: u64 = 1705276800000;
1775
1776 #[test]
1777 fn test_lww_register_basic() {
1778 let mut reg = LwwRegister::new(42u32, 100, NodeId::new(1));
1779 assert_eq!(*reg.get(), 42);
1780 assert_eq!(reg.timestamp(), 100);
1781
1782 assert!(reg.set(99, 200, NodeId::new(2)));
1784 assert_eq!(*reg.get(), 99);
1785
1786 assert!(!reg.set(50, 150, NodeId::new(3)));
1788 assert_eq!(*reg.get(), 99);
1789 }
1790
1791 #[test]
1792 fn test_lww_register_tiebreak() {
1793 let mut reg = LwwRegister::new(1u32, 100, NodeId::new(1));
1794
1795 assert!(reg.set(2, 100, NodeId::new(2)));
1797 assert_eq!(*reg.get(), 2);
1798
1799 assert!(!reg.set(3, 100, NodeId::new(1)));
1801 assert_eq!(*reg.get(), 2);
1802 }
1803
1804 #[test]
1805 fn test_lww_register_merge() {
1806 let mut reg1 = LwwRegister::new(1u32, 100, NodeId::new(1));
1807 let reg2 = LwwRegister::new(2u32, 200, NodeId::new(2));
1808
1809 assert!(reg1.merge(®2));
1810 assert_eq!(*reg1.get(), 2);
1811 }
1812
1813 #[test]
1814 fn test_gcounter_basic() {
1815 let mut counter = GCounter::new();
1816 let node1 = NodeId::new(1);
1817 let node2 = NodeId::new(2);
1818
1819 counter.increment(&node1, 5);
1820 counter.increment(&node2, 3);
1821 counter.increment(&node1, 2);
1822
1823 assert_eq!(counter.value(), 10);
1824 assert_eq!(counter.node_count(&node1), 7);
1825 assert_eq!(counter.node_count(&node2), 3);
1826 }
1827
1828 #[test]
1829 fn test_gcounter_merge() {
1830 let mut counter1 = GCounter::new();
1831 let mut counter2 = GCounter::new();
1832 let node1 = NodeId::new(1);
1833 let node2 = NodeId::new(2);
1834
1835 counter1.increment(&node1, 5);
1836 counter2.increment(&node1, 3);
1837 counter2.increment(&node2, 4);
1838
1839 counter1.merge(&counter2);
1840
1841 assert_eq!(counter1.value(), 9); assert_eq!(counter1.node_count(&node1), 5);
1843 assert_eq!(counter1.node_count(&node2), 4);
1844 }
1845
1846 #[test]
1847 fn test_gcounter_encode_decode() {
1848 let mut counter = GCounter::new();
1849 counter.increment(&NodeId::new(1), 5);
1850 counter.increment(&NodeId::new(2), 10);
1851
1852 let encoded = counter.encode();
1853 let decoded = GCounter::decode(&encoded).unwrap();
1854
1855 assert_eq!(decoded.value(), counter.value());
1856 assert_eq!(decoded.node_count(&NodeId::new(1)), 5);
1857 assert_eq!(decoded.node_count(&NodeId::new(2)), 10);
1858 }
1859
1860 #[test]
1861 fn test_position_encode_decode() {
1862 let pos = Position::new(37.7749, -122.4194)
1863 .with_altitude(100.0)
1864 .with_accuracy(5.0);
1865
1866 let encoded = pos.encode();
1867 let decoded = Position::decode(&encoded).unwrap();
1868
1869 assert_eq!(decoded.latitude, pos.latitude);
1870 assert_eq!(decoded.longitude, pos.longitude);
1871 assert_eq!(decoded.altitude, pos.altitude);
1872 assert_eq!(decoded.accuracy, pos.accuracy);
1873 }
1874
1875 #[test]
1876 fn test_position_minimal_encode() {
1877 let pos = Position::new(0.0, 0.0);
1878 let encoded = pos.encode();
1879 assert_eq!(encoded.len(), 9); let pos_with_alt = Position::new(0.0, 0.0).with_altitude(0.0);
1882 let encoded_alt = pos_with_alt.encode();
1883 assert_eq!(encoded_alt.len(), 13);
1884 }
1885
1886 #[test]
1887 fn test_health_status() {
1888 let mut status = HealthStatus::new(85).with_heart_rate(72).with_activity(1);
1889
1890 assert_eq!(status.battery_percent, 85);
1891 assert_eq!(status.heart_rate, Some(72));
1892 assert!(!status.has_alert(HealthStatus::ALERT_MAN_DOWN));
1893
1894 status.set_alert(HealthStatus::ALERT_MAN_DOWN);
1895 assert!(status.has_alert(HealthStatus::ALERT_MAN_DOWN));
1896
1897 let encoded = status.encode();
1898 let decoded = HealthStatus::decode(&encoded).unwrap();
1899 assert_eq!(decoded.battery_percent, 85);
1900 assert_eq!(decoded.heart_rate, Some(72));
1901 assert!(decoded.has_alert(HealthStatus::ALERT_MAN_DOWN));
1902 }
1903
1904 #[test]
1905 fn test_crdt_operation_position() {
1906 let op = CrdtOperation::UpdatePosition {
1907 node_id: NodeId::new(0x1234),
1908 position: Position::new(37.0, -122.0),
1909 timestamp: 1000,
1910 };
1911
1912 let encoded = op.encode();
1913 let decoded = CrdtOperation::decode(&encoded).unwrap();
1914
1915 if let CrdtOperation::UpdatePosition {
1916 node_id,
1917 position,
1918 timestamp,
1919 } = decoded
1920 {
1921 assert_eq!(node_id.as_u32(), 0x1234);
1922 assert_eq!(timestamp, 1000);
1923 assert_eq!(position.latitude, 37.0);
1924 } else {
1925 panic!("Wrong operation type");
1926 }
1927 }
1928
1929 #[test]
1930 fn test_crdt_operation_counter() {
1931 let op = CrdtOperation::IncrementCounter {
1932 counter_id: 1,
1933 node_id: NodeId::new(0x5678),
1934 amount: 42,
1935 };
1936
1937 let encoded = op.encode();
1938 let decoded = CrdtOperation::decode(&encoded).unwrap();
1939
1940 if let CrdtOperation::IncrementCounter {
1941 counter_id,
1942 node_id,
1943 amount,
1944 } = decoded
1945 {
1946 assert_eq!(counter_id, 1);
1947 assert_eq!(node_id.as_u32(), 0x5678);
1948 assert_eq!(amount, 42);
1949 } else {
1950 panic!("Wrong operation type");
1951 }
1952 }
1953
1954 #[test]
1955 fn test_crdt_operation_size() {
1956 let pos_op = CrdtOperation::UpdatePosition {
1957 node_id: NodeId::new(1),
1958 position: Position::new(0.0, 0.0),
1959 timestamp: 0,
1960 };
1961 assert!(pos_op.size() > 0);
1962
1963 let counter_op = CrdtOperation::IncrementCounter {
1964 counter_id: 0,
1965 node_id: NodeId::new(1),
1966 amount: 1,
1967 };
1968 assert_eq!(counter_op.size(), 13);
1969 }
1970
1971 #[test]
1976 fn test_peripheral_type_from_u8() {
1977 assert_eq!(PeripheralType::from_u8(0), PeripheralType::Unknown);
1978 assert_eq!(PeripheralType::from_u8(1), PeripheralType::SoldierSensor);
1979 assert_eq!(PeripheralType::from_u8(2), PeripheralType::FixedSensor);
1980 assert_eq!(PeripheralType::from_u8(3), PeripheralType::Relay);
1981 assert_eq!(PeripheralType::from_u8(99), PeripheralType::Unknown);
1982 }
1983
1984 #[test]
1985 fn test_event_type_from_u8() {
1986 assert_eq!(EventType::from_u8(0), EventType::None);
1987 assert_eq!(EventType::from_u8(1), EventType::Ping);
1988 assert_eq!(EventType::from_u8(2), EventType::NeedAssist);
1989 assert_eq!(EventType::from_u8(3), EventType::Emergency);
1990 assert_eq!(EventType::from_u8(4), EventType::Moving);
1991 assert_eq!(EventType::from_u8(5), EventType::InPosition);
1992 assert_eq!(EventType::from_u8(6), EventType::Ack);
1993 assert_eq!(EventType::from_u8(99), EventType::None);
1994 }
1995
1996 #[test]
1997 fn test_event_type_labels() {
1998 assert_eq!(EventType::None.label(), "");
1999 assert_eq!(EventType::Emergency.label(), "EMERGENCY");
2000 assert_eq!(EventType::Ping.label(), "PING");
2001 }
2002
2003 #[test]
2004 fn test_peripheral_event_encode_decode() {
2005 let event = PeripheralEvent::new(EventType::Emergency, TEST_TIMESTAMP);
2006 let encoded = event.encode();
2007 assert_eq!(encoded.len(), 9);
2008
2009 let decoded = PeripheralEvent::decode(&encoded).unwrap();
2010 assert_eq!(decoded.event_type, EventType::Emergency);
2011 assert_eq!(decoded.timestamp, TEST_TIMESTAMP);
2012 }
2013
2014 #[test]
2015 fn test_peripheral_new() {
2016 let peripheral = Peripheral::new(0x12345678, PeripheralType::SoldierSensor);
2017 assert_eq!(peripheral.id, 0x12345678);
2018 assert_eq!(peripheral.peripheral_type, PeripheralType::SoldierSensor);
2019 assert_eq!(peripheral.parent_node, 0);
2020 assert!(peripheral.last_event.is_none());
2021 }
2022
2023 #[test]
2024 fn test_peripheral_with_callsign() {
2025 let peripheral = Peripheral::new(1, PeripheralType::SoldierSensor).with_callsign("ALPHA-1");
2026 assert_eq!(peripheral.callsign_str(), "ALPHA-1");
2027
2028 let peripheral2 = Peripheral::new(2, PeripheralType::SoldierSensor)
2030 .with_callsign("THIS_IS_A_VERY_LONG_CALLSIGN");
2031 assert_eq!(peripheral2.callsign_str(), "THIS_IS_A_VE");
2032 }
2033
2034 #[test]
2035 fn test_peripheral_set_event() {
2036 let mut peripheral = Peripheral::new(1, PeripheralType::SoldierSensor);
2037 peripheral.set_event(EventType::Emergency, TEST_TIMESTAMP);
2038
2039 assert!(peripheral.last_event.is_some());
2040 let event = peripheral.last_event.as_ref().unwrap();
2041 assert_eq!(event.event_type, EventType::Emergency);
2042 assert_eq!(event.timestamp, TEST_TIMESTAMP);
2043 assert_eq!(peripheral.timestamp, TEST_TIMESTAMP);
2044
2045 peripheral.clear_event();
2046 assert!(peripheral.last_event.is_none());
2047 }
2048
2049 #[test]
2050 fn test_peripheral_encode_decode_without_event() {
2051 let peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor)
2052 .with_callsign("BRAVO-2")
2053 .with_parent(0x11223344);
2054
2055 let encoded = peripheral.encode();
2056 assert_eq!(encoded.len(), 35); let decoded = Peripheral::decode(&encoded).unwrap();
2059 assert_eq!(decoded.id, 0xAABBCCDD);
2060 assert_eq!(decoded.parent_node, 0x11223344);
2061 assert_eq!(decoded.peripheral_type, PeripheralType::SoldierSensor);
2062 assert_eq!(decoded.callsign_str(), "BRAVO-2");
2063 assert!(decoded.last_event.is_none());
2064 assert!(decoded.location.is_none());
2065 }
2066
2067 #[test]
2068 fn test_peripheral_encode_decode_with_event() {
2069 let mut peripheral = Peripheral::new(0x12345678, PeripheralType::SoldierSensor)
2070 .with_callsign("CHARLIE")
2071 .with_parent(0x87654321);
2072 peripheral.health = HealthStatus::new(85);
2073 peripheral.set_event(EventType::NeedAssist, TEST_TIMESTAMP);
2074
2075 let encoded = peripheral.encode();
2076 assert_eq!(encoded.len(), 44); let decoded = Peripheral::decode(&encoded).unwrap();
2079 assert_eq!(decoded.id, 0x12345678);
2080 assert_eq!(decoded.parent_node, 0x87654321);
2081 assert_eq!(decoded.callsign_str(), "CHARLIE");
2082 assert_eq!(decoded.health.battery_percent, 85);
2083 assert!(decoded.last_event.is_some());
2084 let event = decoded.last_event.as_ref().unwrap();
2085 assert_eq!(event.event_type, EventType::NeedAssist);
2086 assert_eq!(event.timestamp, TEST_TIMESTAMP);
2087 assert!(decoded.location.is_none());
2088 }
2089
2090 #[test]
2091 fn test_peripheral_encode_decode_with_location() {
2092 let location = Position::new(37.7749, -122.4194).with_altitude(10.0);
2093 let peripheral = Peripheral::new(0x12345678, PeripheralType::SoldierSensor)
2094 .with_callsign("DELTA")
2095 .with_location(location);
2096
2097 let encoded = peripheral.encode();
2098 assert_eq!(encoded.len(), 48);
2100
2101 let decoded = Peripheral::decode(&encoded).unwrap();
2102 assert_eq!(decoded.id, 0x12345678);
2103 assert_eq!(decoded.callsign_str(), "DELTA");
2104 assert!(decoded.location.is_some());
2105
2106 let loc = decoded.location.unwrap();
2107 assert!((loc.latitude - 37.7749).abs() < 0.0001);
2108 assert!((loc.longitude - (-122.4194)).abs() < 0.0001);
2109 assert!(loc.altitude.is_some());
2110 assert!((loc.altitude.unwrap() - 10.0).abs() < 1.0);
2111 }
2112
2113 #[test]
2114 fn test_peripheral_decode_invalid_data() {
2115 assert!(Peripheral::decode(&[0u8; 10]).is_none());
2117
2118 let mut data = vec![0u8; 34];
2120 data[25] = 0; assert!(Peripheral::decode(&data).is_none()); data[0..4].copy_from_slice(&1u32.to_le_bytes()); assert!(Peripheral::decode(&data).is_some());
2126
2127 data[25] = 1; assert!(Peripheral::decode(&data).is_none());
2130 }
2131
2132 #[test]
2137 fn test_emergency_event_new() {
2138 let peers = vec![0x22222222, 0x33333333];
2139 let event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2140
2141 assert_eq!(event.source_node(), 0x11111111);
2142 assert_eq!(event.timestamp(), TEST_TIMESTAMP);
2143 assert_eq!(event.peer_count(), 3); assert!(event.has_acked(0x11111111));
2147 assert!(!event.has_acked(0x22222222));
2149 assert!(!event.has_acked(0x33333333));
2150 }
2151
2152 #[test]
2153 fn test_emergency_event_ack() {
2154 let peers = vec![0x22222222, 0x33333333];
2155 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2156
2157 assert_eq!(event.ack_count(), 1); assert!(!event.all_acked());
2159
2160 assert!(event.ack(0x22222222)); assert_eq!(event.ack_count(), 2);
2163 assert!(!event.all_acked());
2164
2165 assert!(!event.ack(0x22222222)); assert!(event.ack(0x33333333));
2170 assert_eq!(event.ack_count(), 3);
2171 assert!(event.all_acked());
2172 }
2173
2174 #[test]
2175 fn test_emergency_event_pending_nodes() {
2176 let peers = vec![0x22222222, 0x33333333];
2177 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2178
2179 let pending = event.pending_nodes();
2180 assert_eq!(pending.len(), 2);
2181 assert!(pending.contains(&0x22222222));
2182 assert!(pending.contains(&0x33333333));
2183
2184 event.ack(0x22222222);
2185 let pending = event.pending_nodes();
2186 assert_eq!(pending.len(), 1);
2187 assert!(pending.contains(&0x33333333));
2188 }
2189
2190 #[test]
2191 fn test_emergency_event_encode_decode() {
2192 let peers = vec![0x22222222, 0x33333333];
2193 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2194 event.ack(0x22222222);
2195
2196 let encoded = event.encode();
2197 let decoded = EmergencyEvent::decode(&encoded).unwrap();
2198
2199 assert_eq!(decoded.source_node(), 0x11111111);
2200 assert_eq!(decoded.timestamp(), TEST_TIMESTAMP);
2201 assert!(decoded.has_acked(0x11111111));
2202 assert!(decoded.has_acked(0x22222222));
2203 assert!(!decoded.has_acked(0x33333333));
2204 }
2205
2206 #[test]
2207 fn test_emergency_event_merge_same_event() {
2208 let peers = vec![0x22222222, 0x33333333];
2210 let mut event1 = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2211 let mut event2 = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2212
2213 event1.ack(0x22222222);
2214 event2.ack(0x33333333);
2215
2216 let changed = event1.merge(&event2);
2218 assert!(changed);
2219 assert!(event1.has_acked(0x22222222));
2220 assert!(event1.has_acked(0x33333333));
2221 assert!(event1.all_acked());
2222 }
2223
2224 #[test]
2225 fn test_emergency_event_merge_different_events() {
2226 let mut old_event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &[0x22222222]);
2228 old_event.ack(0x22222222);
2229
2230 let new_event =
2232 EmergencyEvent::new(0x33333333, TEST_TIMESTAMP + 1000, &[0x11111111, 0x22222222]);
2233
2234 let changed = old_event.merge(&new_event);
2236 assert!(changed);
2237 assert_eq!(old_event.source_node(), 0x33333333);
2238 assert_eq!(old_event.timestamp(), TEST_TIMESTAMP + 1000);
2239 assert!(!old_event.has_acked(0x22222222));
2241 }
2242
2243 #[test]
2244 fn test_emergency_event_merge_older_event_ignored() {
2245 let mut current = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP + 1000, &[0x22222222]);
2247
2248 let older = EmergencyEvent::new(0x33333333, TEST_TIMESTAMP, &[0x11111111]);
2250
2251 let changed = current.merge(&older);
2253 assert!(!changed);
2254 assert_eq!(current.source_node(), 0x11111111);
2255 assert_eq!(current.timestamp(), TEST_TIMESTAMP + 1000);
2256 }
2257
2258 #[test]
2259 fn test_emergency_event_add_peer() {
2260 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &[]);
2261
2262 event.add_peer(0x22222222);
2264 assert!(!event.has_acked(0x22222222));
2265 assert_eq!(event.peer_count(), 2);
2266
2267 event.ack(0x22222222);
2269 event.add_peer(0x22222222);
2270 assert!(event.has_acked(0x22222222)); }
2272
2273 #[test]
2274 fn test_emergency_event_decode_invalid() {
2275 assert!(EmergencyEvent::decode(&[0u8; 10]).is_none());
2277
2278 let mut data = vec![0u8; 16];
2280 data[12] = 5; assert!(EmergencyEvent::decode(&data).is_none());
2282 }
2283
2284 #[test]
2289 fn test_chat_message_new() {
2290 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "ALPHA-1", "Hello mesh!");
2291 assert_eq!(msg.origin_node, 0x12345678);
2292 assert_eq!(msg.timestamp, TEST_TIMESTAMP);
2293 assert_eq!(msg.sender(), "ALPHA-1");
2294 assert_eq!(msg.text(), "Hello mesh!");
2295 assert!(msg.is_broadcast);
2296 assert!(!msg.requires_ack);
2297 assert!(!msg.is_reply());
2298 }
2299
2300 #[test]
2301 fn test_chat_message_reply_to() {
2302 let mut msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP + 1000, "BRAVO", "Roger that");
2303 msg.set_reply_to(0xAABBCCDD, TEST_TIMESTAMP);
2304
2305 assert!(msg.is_reply());
2306 assert_eq!(msg.reply_to_node, 0xAABBCCDD);
2307 assert_eq!(msg.reply_to_timestamp, TEST_TIMESTAMP);
2308 }
2309
2310 #[test]
2311 fn test_chat_message_truncation() {
2312 let msg = ChatMessage::new(0x1, TEST_TIMESTAMP, "VERY_LONG_CALLSIGN", "Hi");
2314 assert_eq!(msg.sender(), "VERY_LONG_CA"); let long_text = "A".repeat(200);
2318 let msg = ChatMessage::new(0x1, TEST_TIMESTAMP, "X", &long_text);
2319 assert_eq!(msg.text().len(), 128);
2320 }
2321
2322 #[test]
2323 fn test_chat_message_id() {
2324 let msg = ChatMessage::new(0x12345678, 0x18D4A51_ABCDEF01, "X", "Y");
2325 let id = msg.message_id();
2326 assert_eq!(id, (0x12345678u64 << 32) | 0xABCDEF01);
2328 }
2329
2330 #[test]
2331 fn test_chat_message_encode_decode() {
2332 let mut msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "CHARLIE", "Test message");
2333 msg.is_broadcast = true;
2334 msg.requires_ack = true;
2335 msg.set_reply_to(0xAABBCCDD, TEST_TIMESTAMP - 1000);
2336
2337 let encoded = msg.encode();
2338 let (decoded, len) = ChatMessage::decode(&encoded).unwrap();
2339
2340 assert_eq!(len, encoded.len());
2341 assert_eq!(decoded.origin_node, 0x12345678);
2342 assert_eq!(decoded.timestamp, TEST_TIMESTAMP);
2343 assert_eq!(decoded.sender(), "CHARLIE");
2344 assert_eq!(decoded.text(), "Test message");
2345 assert!(decoded.is_broadcast);
2346 assert!(decoded.requires_ack);
2347 assert_eq!(decoded.reply_to_node, 0xAABBCCDD);
2348 assert_eq!(decoded.reply_to_timestamp, TEST_TIMESTAMP - 1000);
2349 }
2350
2351 #[test]
2352 fn test_chat_message_decode_empty_text() {
2353 let msg = ChatMessage::new(0x1, TEST_TIMESTAMP, "ACK-NODE", "");
2355 let encoded = msg.encode();
2356 let (decoded, _) = ChatMessage::decode(&encoded).unwrap();
2357 assert_eq!(decoded.sender(), "ACK-NODE");
2358 assert_eq!(decoded.text(), "");
2359 }
2360
2361 #[test]
2366 fn test_chat_message_decode_rejects_zero_origin() {
2367 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "TEST", "msg");
2369 let mut encoded = msg.encode();
2370 encoded[0] = 0;
2372 encoded[1] = 0;
2373 encoded[2] = 0;
2374 encoded[3] = 0;
2375
2376 assert!(ChatMessage::decode(&encoded).is_none());
2377 }
2378
2379 #[test]
2380 fn test_chat_message_decode_rejects_old_timestamp() {
2381 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "TEST", "msg");
2383 let mut encoded = msg.encode();
2384 let old_ts: u64 = 1000;
2386 encoded[4..12].copy_from_slice(&old_ts.to_le_bytes());
2387
2388 assert!(ChatMessage::decode(&encoded).is_none());
2389 }
2390
2391 #[test]
2392 fn test_chat_message_decode_rejects_empty_sender() {
2393 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "X", "msg");
2395 let mut encoded = msg.encode();
2396 encoded[12] = 0;
2398 let mut raw = Vec::new();
2402 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(0); raw.push(3); raw.extend_from_slice(b"msg"); raw.push(0x01); assert!(ChatMessage::decode(&raw).is_none());
2410 }
2411
2412 #[test]
2413 fn test_chat_message_decode_rejects_invalid_utf8_sender() {
2414 let mut raw = Vec::new();
2416 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(4); raw.extend_from_slice(&[0x66, 0x59, 0xFF, 0xFE]); raw.push(3); raw.extend_from_slice(b"msg"); raw.push(0x01); raw.extend_from_slice(&0u32.to_le_bytes()); raw.extend_from_slice(&0u64.to_le_bytes()); assert!(ChatMessage::decode(&raw).is_none());
2427 }
2428
2429 #[test]
2430 fn test_chat_message_decode_rejects_invalid_utf8_text() {
2431 let mut raw = Vec::new();
2433 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(4); raw.extend_from_slice(b"TEST"); raw.push(4); raw.extend_from_slice(&[0x80, 0x81, 0x82, 0x83]); raw.push(0x01); raw.extend_from_slice(&0u32.to_le_bytes()); raw.extend_from_slice(&0u64.to_le_bytes()); assert!(ChatMessage::decode(&raw).is_none());
2444 }
2445
2446 #[test]
2447 fn test_chat_message_decode_accepts_valid_utf8() {
2448 let mut raw = Vec::new();
2450 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(6); raw.extend_from_slice("TËST".as_bytes()); let sender_bytes = "TËST1".as_bytes(); raw[12] = sender_bytes.len() as u8;
2457 raw.truncate(13);
2458 raw.extend_from_slice(sender_bytes);
2459 raw.push(4); raw.extend_from_slice(b"test"); raw.push(0x01); raw.extend_from_slice(&0u32.to_le_bytes()); raw.extend_from_slice(&0u64.to_le_bytes()); let result = ChatMessage::decode(&raw);
2466 assert!(result.is_some());
2467 let (msg, _) = result.unwrap();
2468 assert_eq!(msg.sender(), "TËST1");
2469 }
2470
2471 #[test]
2476 fn test_chat_crdt_new() {
2477 let chat = ChatCRDT::new();
2478 assert!(chat.is_empty());
2479 assert_eq!(chat.len(), 0);
2480 }
2481
2482 #[test]
2483 fn test_chat_crdt_add_message() {
2484 let mut chat = ChatCRDT::new();
2485
2486 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "ALPHA", "Hello");
2487 assert!(chat.add_message(msg.clone()));
2488 assert_eq!(chat.len(), 1);
2489
2490 assert!(!chat.add_message(msg));
2492 assert_eq!(chat.len(), 1);
2493 }
2494
2495 #[test]
2496 fn test_chat_crdt_send_message() {
2497 let mut chat = ChatCRDT::new();
2498
2499 assert!(chat.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "First"));
2500 assert!(chat.send_message(0x2, TEST_TIMESTAMP + 1, "BRAVO", "Second"));
2501 assert_eq!(chat.len(), 2);
2502
2503 assert!(!chat.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "Duplicate"));
2505 assert_eq!(chat.len(), 2);
2506 }
2507
2508 #[test]
2509 fn test_chat_crdt_get_message() {
2510 let mut chat = ChatCRDT::new();
2511 chat.send_message(0x12345678, TEST_TIMESTAMP, "ALPHA", "Test");
2512
2513 let msg = chat.get_message(0x12345678, TEST_TIMESTAMP);
2514 assert!(msg.is_some());
2515 assert_eq!(msg.unwrap().text(), "Test");
2516
2517 assert!(chat.get_message(0x99999999, TEST_TIMESTAMP).is_none());
2519 }
2520
2521 #[test]
2522 fn test_chat_crdt_merge() {
2523 let mut chat1 = ChatCRDT::new();
2524 let mut chat2 = ChatCRDT::new();
2525
2526 chat1.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "From 1");
2527 chat2.send_message(0x2, TEST_TIMESTAMP + 1, "BRAVO", "From 2");
2528
2529 let changed = chat1.merge(&chat2);
2531 assert!(changed);
2532 assert_eq!(chat1.len(), 2);
2533
2534 let changed = chat1.merge(&chat2);
2536 assert!(!changed);
2537 assert_eq!(chat1.len(), 2);
2538 }
2539
2540 #[test]
2541 fn test_chat_crdt_merge_duplicates() {
2542 let mut chat1 = ChatCRDT::new();
2543 let mut chat2 = ChatCRDT::new();
2544
2545 chat1.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "Same message");
2547 chat2.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "Same message");
2548
2549 chat1.merge(&chat2);
2551 assert_eq!(chat1.len(), 1);
2552 }
2553
2554 #[test]
2555 fn test_chat_crdt_pruning() {
2556 let mut chat = ChatCRDT::new();
2557
2558 for i in 0..(CHAT_MAX_MESSAGES + 10) {
2560 chat.send_message(i as u32 + 1, TEST_TIMESTAMP + i as u64, "X", "Y");
2561 }
2562
2563 assert_eq!(chat.len(), CHAT_MAX_MESSAGES);
2565
2566 assert!(chat.get_message(1, TEST_TIMESTAMP).is_none());
2570 assert!(chat.get_message(10, TEST_TIMESTAMP + 9).is_none());
2571 assert!(chat.get_message(11, TEST_TIMESTAMP + 10).is_some());
2573 }
2574
2575 #[test]
2576 fn test_chat_crdt_encode_decode() {
2577 let mut chat = ChatCRDT::new();
2578 chat.send_message(0x12345678, TEST_TIMESTAMP, "ALPHA", "First message");
2579 chat.send_message(0xAABBCCDD, TEST_TIMESTAMP + 1000, "BRAVO", "Second message");
2580
2581 let encoded = chat.encode();
2582 let decoded = ChatCRDT::decode(&encoded).unwrap();
2583
2584 assert_eq!(decoded.len(), 2);
2585 assert!(decoded.get_message(0x12345678, TEST_TIMESTAMP).is_some());
2586 assert!(decoded
2587 .get_message(0xAABBCCDD, TEST_TIMESTAMP + 1000)
2588 .is_some());
2589 }
2590
2591 #[test]
2592 fn test_chat_crdt_messages_since() {
2593 let mut chat = ChatCRDT::new();
2594 chat.send_message(0x1, TEST_TIMESTAMP, "A", "Old");
2595 chat.send_message(0x2, TEST_TIMESTAMP + 1000, "B", "Mid");
2596 chat.send_message(0x3, TEST_TIMESTAMP + 2000, "C", "New");
2597
2598 let recent: Vec<_> = chat.messages_since(TEST_TIMESTAMP + 500).collect();
2599 assert_eq!(recent.len(), 2);
2600 }
2601
2602 #[test]
2603 fn test_chat_crdt_newest_timestamp() {
2604 let mut chat = ChatCRDT::new();
2605 assert!(chat.newest_timestamp().is_none());
2606
2607 chat.send_message(0x1, TEST_TIMESTAMP, "A", "1");
2608 assert_eq!(chat.newest_timestamp(), Some(TEST_TIMESTAMP));
2609
2610 chat.send_message(0x2, TEST_TIMESTAMP + 2000, "B", "2");
2611 assert_eq!(chat.newest_timestamp(), Some(TEST_TIMESTAMP + 2000));
2612
2613 chat.send_message(0x3, TEST_TIMESTAMP + 1000, "C", "3"); assert_eq!(chat.newest_timestamp(), Some(TEST_TIMESTAMP + 2000));
2615 }
2616
2617 #[test]
2622 fn test_chat_crdt_decode_skips_invalid_messages() {
2623 let mut valid_chat = ChatCRDT::new();
2625 valid_chat.send_message(0x12345678, TEST_TIMESTAMP, "VALID", "Good message");
2626
2627 let encoded = valid_chat.encode();
2628
2629 let decoded = ChatCRDT::decode(&encoded).unwrap();
2631 assert_eq!(decoded.len(), 1);
2632 assert!(decoded.get_message(0x12345678, TEST_TIMESTAMP).is_some());
2633 }
2634
2635 #[test]
2636 fn test_chat_crdt_decode_handles_truncated_data() {
2637 let mut chat = ChatCRDT::new();
2638 chat.send_message(0x12345678, TEST_TIMESTAMP, "TEST", "Message");
2639
2640 let encoded = chat.encode();
2641
2642 let truncated = &encoded[..2];
2644 let decoded = ChatCRDT::decode(truncated);
2645 assert!(decoded.is_some());
2646 assert_eq!(decoded.unwrap().len(), 0); }
2648}