1use crate::error::WireError;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
29pub struct ProtocolVersion {
30 pub major: u8,
32 pub minor: u8,
34}
35
36impl ProtocolVersion {
37 pub const WIRE_SIZE: usize = 2;
39
40 pub const V1_0: Self = Self { major: 1, minor: 0 };
42 pub const V1_1: Self = Self { major: 1, minor: 1 };
44 pub const V2_0: Self = Self { major: 2, minor: 0 };
46 pub const V2_1: Self = Self { major: 2, minor: 1 };
48 pub const V2_2: Self = Self { major: 2, minor: 2 };
50 pub const V2_3: Self = Self { major: 2, minor: 3 };
52 pub const V2_4: Self = Self { major: 2, minor: 4 };
54 pub const V2_5: Self = Self { major: 2, minor: 5 };
56
57 pub const CURRENT: Self = Self::V2_5;
60
61 #[must_use]
63 pub fn to_bytes(self) -> [u8; 2] {
64 [self.major, self.minor]
65 }
66
67 #[must_use]
69 pub fn from_bytes(bytes: [u8; 2]) -> Self {
70 Self {
71 major: bytes[0],
72 minor: bytes[1],
73 }
74 }
75}
76
77impl Default for ProtocolVersion {
78 fn default() -> Self {
79 Self::V2_5
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub struct VendorId(pub [u8; 2]);
92
93impl VendorId {
94 pub const WIRE_SIZE: usize = 2;
96
97 pub const UNKNOWN: Self = Self([0, 0]);
99
100 pub const ZERODDS: Self = Self([0x01, 0xF0]);
102
103 #[must_use]
105 pub fn to_bytes(self) -> [u8; 2] {
106 self.0
107 }
108
109 #[must_use]
111 pub fn from_bytes(bytes: [u8; 2]) -> Self {
112 Self(bytes)
113 }
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
123pub struct GuidPrefix(pub [u8; 12]);
124
125impl GuidPrefix {
126 pub const WIRE_SIZE: usize = 12;
128
129 pub const UNKNOWN: Self = Self([0; 12]);
131
132 #[must_use]
134 pub fn to_bytes(self) -> [u8; 12] {
135 self.0
136 }
137
138 #[must_use]
140 pub fn from_bytes(bytes: [u8; 12]) -> Self {
141 Self(bytes)
142 }
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
151#[repr(u8)]
152#[allow(missing_docs)]
153pub enum EntityKind {
154 Unknown = 0x00,
155 UserWriterNoKey = 0x03,
156 UserWriterWithKey = 0x02,
157 UserReaderNoKey = 0x04,
158 UserReaderWithKey = 0x07,
159 BuiltinWriterNoKey = 0xC3,
160 BuiltinWriterWithKey = 0xC2,
161 BuiltinReaderNoKey = 0xC4,
162 BuiltinReaderWithKey = 0xC7,
163 Participant = 0xC1,
164}
165
166impl EntityKind {
167 #[must_use]
170 pub fn from_byte(b: u8) -> Self {
171 match b {
172 0x03 => Self::UserWriterNoKey,
173 0x02 => Self::UserWriterWithKey,
174 0x04 => Self::UserReaderNoKey,
175 0x07 => Self::UserReaderWithKey,
176 0xC3 => Self::BuiltinWriterNoKey,
177 0xC2 => Self::BuiltinWriterWithKey,
178 0xC4 => Self::BuiltinReaderNoKey,
179 0xC7 => Self::BuiltinReaderWithKey,
180 0xC1 => Self::Participant,
181 _ => Self::Unknown,
182 }
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
189pub struct EntityId {
190 pub entity_key: [u8; 3],
192 pub entity_kind: EntityKind,
194}
195
196impl EntityId {
197 pub const WIRE_SIZE: usize = 4;
199
200 pub const UNKNOWN: Self = Self {
202 entity_key: [0; 3],
203 entity_kind: EntityKind::Unknown,
204 };
205
206 pub const PARTICIPANT: Self = Self {
208 entity_key: [0, 0, 1],
209 entity_kind: EntityKind::Participant,
210 };
211
212 #[must_use]
214 pub const fn user_writer_with_key(key: [u8; 3]) -> Self {
215 Self {
216 entity_key: key,
217 entity_kind: EntityKind::UserWriterWithKey,
218 }
219 }
220
221 #[must_use]
223 pub const fn user_reader_with_key(key: [u8; 3]) -> Self {
224 Self {
225 entity_key: key,
226 entity_kind: EntityKind::UserReaderWithKey,
227 }
228 }
229
230 pub const SPDP_BUILTIN_PARTICIPANT_WRITER: Self = Self {
233 entity_key: [0, 0x01, 0x00],
234 entity_kind: EntityKind::BuiltinWriterWithKey,
235 };
236
237 pub const SPDP_BUILTIN_PARTICIPANT_READER: Self = Self {
239 entity_key: [0, 0x01, 0x00],
240 entity_kind: EntityKind::BuiltinReaderWithKey,
241 };
242
243 pub const SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: Self = Self {
245 entity_key: [0, 0x00, 0x04],
246 entity_kind: EntityKind::BuiltinWriterWithKey,
247 };
248
249 pub const SEDP_BUILTIN_SUBSCRIPTIONS_READER: Self = Self {
251 entity_key: [0, 0x00, 0x04],
252 entity_kind: EntityKind::BuiltinReaderWithKey,
253 };
254
255 pub const SEDP_BUILTIN_PUBLICATIONS_WRITER: Self = Self {
257 entity_key: [0, 0x00, 0x03],
258 entity_kind: EntityKind::BuiltinWriterWithKey,
259 };
260
261 pub const SEDP_BUILTIN_PUBLICATIONS_READER: Self = Self {
263 entity_key: [0, 0x00, 0x03],
264 entity_kind: EntityKind::BuiltinReaderWithKey,
265 };
266
267 pub const BUILTIN_PARTICIPANT_MESSAGE_WRITER: Self = Self {
273 entity_key: [0, 0x02, 0x00],
274 entity_kind: EntityKind::BuiltinWriterWithKey,
275 };
276
277 pub const BUILTIN_PARTICIPANT_MESSAGE_READER: Self = Self {
280 entity_key: [0, 0x02, 0x00],
281 entity_kind: EntityKind::BuiltinReaderWithKey,
282 };
283
284 pub const TL_SVC_REQ_WRITER: Self = Self {
288 entity_key: [0, 0x03, 0x00],
289 entity_kind: EntityKind::BuiltinWriterNoKey,
290 };
291 pub const TL_SVC_REQ_READER: Self = Self {
293 entity_key: [0, 0x03, 0x00],
294 entity_kind: EntityKind::BuiltinReaderNoKey,
295 };
296 pub const TL_SVC_REPLY_WRITER: Self = Self {
298 entity_key: [0, 0x03, 0x01],
299 entity_kind: EntityKind::BuiltinWriterNoKey,
300 };
301 pub const TL_SVC_REPLY_READER: Self = Self {
303 entity_key: [0, 0x03, 0x01],
304 entity_kind: EntityKind::BuiltinReaderNoKey,
305 };
306
307 pub const SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: Self = Self {
316 entity_key: [0xff, 0x00, 0x03],
317 entity_kind: EntityKind::BuiltinWriterWithKey,
318 };
319 pub const SEDP_BUILTIN_PUBLICATIONS_SECURE_READER: Self = Self {
321 entity_key: [0xff, 0x00, 0x03],
322 entity_kind: EntityKind::BuiltinReaderWithKey,
323 };
324 pub const SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: Self = Self {
326 entity_key: [0xff, 0x00, 0x04],
327 entity_kind: EntityKind::BuiltinWriterWithKey,
328 };
329 pub const SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER: Self = Self {
331 entity_key: [0xff, 0x00, 0x04],
332 entity_kind: EntityKind::BuiltinReaderWithKey,
333 };
334 pub const BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: Self = Self {
337 entity_key: [0xff, 0x02, 0x00],
338 entity_kind: EntityKind::BuiltinWriterWithKey,
339 };
340 pub const BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER: Self = Self {
342 entity_key: [0xff, 0x02, 0x00],
343 entity_kind: EntityKind::BuiltinReaderWithKey,
344 };
345 pub const BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: Self = Self {
349 entity_key: [0x00, 0x02, 0x01],
350 entity_kind: EntityKind::BuiltinWriterNoKey,
351 };
352 pub const BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER: Self = Self {
354 entity_key: [0x00, 0x02, 0x01],
355 entity_kind: EntityKind::BuiltinReaderNoKey,
356 };
357 pub const BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER: Self = Self {
361 entity_key: [0xff, 0x02, 0x02],
362 entity_kind: EntityKind::BuiltinWriterWithKey,
363 };
364 pub const BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_READER: Self = Self {
366 entity_key: [0xff, 0x02, 0x02],
367 entity_kind: EntityKind::BuiltinReaderWithKey,
368 };
369 pub const SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_WRITER: Self = Self {
372 entity_key: [0xff, 0x01, 0x01],
373 entity_kind: EntityKind::BuiltinWriterWithKey,
374 };
375 pub const SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER: Self = Self {
377 entity_key: [0xff, 0x01, 0x01],
378 entity_kind: EntityKind::BuiltinReaderWithKey,
379 };
380
381 #[must_use]
384 pub const fn is_secure_builtin(self) -> bool {
385 matches!(
386 self,
387 Self::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER
388 | Self::SEDP_BUILTIN_PUBLICATIONS_SECURE_READER
389 | Self::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER
390 | Self::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER
391 | Self::BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER
392 | Self::BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER
393 | Self::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER
394 | Self::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER
395 | Self::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER
396 | Self::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_READER
397 | Self::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_WRITER
398 | Self::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER
399 )
400 }
401
402 #[must_use]
404 pub fn to_bytes(self) -> [u8; 4] {
405 [
406 self.entity_key[0],
407 self.entity_key[1],
408 self.entity_key[2],
409 self.entity_kind as u8,
410 ]
411 }
412
413 #[must_use]
415 pub fn from_bytes(bytes: [u8; 4]) -> Self {
416 Self {
417 entity_key: [bytes[0], bytes[1], bytes[2]],
418 entity_kind: EntityKind::from_byte(bytes[3]),
419 }
420 }
421}
422
423#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
430pub struct Guid {
431 pub prefix: GuidPrefix,
433 pub entity_id: EntityId,
435}
436
437impl Guid {
438 pub const WIRE_SIZE: usize = 16;
440
441 pub const UNKNOWN: Self = Self {
443 prefix: GuidPrefix::UNKNOWN,
444 entity_id: EntityId::UNKNOWN,
445 };
446
447 #[must_use]
449 pub const fn new(prefix: GuidPrefix, entity_id: EntityId) -> Self {
450 Self { prefix, entity_id }
451 }
452
453 #[must_use]
455 pub fn to_bytes(self) -> [u8; 16] {
456 let mut out = [0u8; 16];
457 out[..12].copy_from_slice(&self.prefix.to_bytes());
458 out[12..].copy_from_slice(&self.entity_id.to_bytes());
459 out
460 }
461
462 #[must_use]
464 pub fn from_bytes(bytes: [u8; 16]) -> Self {
465 let mut prefix_bytes = [0u8; 12];
466 prefix_bytes.copy_from_slice(&bytes[..12]);
467 let mut entity_bytes = [0u8; 4];
468 entity_bytes.copy_from_slice(&bytes[12..]);
469 Self {
470 prefix: GuidPrefix::from_bytes(prefix_bytes),
471 entity_id: EntityId::from_bytes(entity_bytes),
472 }
473 }
474}
475
476#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
483pub struct SequenceNumber(pub i64);
484
485impl SequenceNumber {
486 pub const WIRE_SIZE: usize = 8;
488
489 pub const UNKNOWN: Self = Self(-(1_i64 << 32));
491
492 #[must_use]
494 pub fn split(self) -> (i32, u32) {
495 let value = self.0;
496 let high = (value >> 32) as i32;
497 let low = (value & 0xFFFF_FFFF) as u32;
498 (high, low)
499 }
500
501 #[must_use]
503 pub fn from_high_low(high: i32, low: u32) -> Self {
504 let value = (i64::from(high) << 32) | i64::from(low);
505 Self(value)
506 }
507
508 #[must_use]
510 pub fn to_bytes_le(self) -> [u8; 8] {
511 let (high, low) = self.split();
512 let mut out = [0u8; 8];
513 out[..4].copy_from_slice(&high.to_le_bytes());
514 out[4..].copy_from_slice(&low.to_le_bytes());
515 out
516 }
517
518 #[must_use]
520 pub fn to_bytes_be(self) -> [u8; 8] {
521 let (high, low) = self.split();
522 let mut out = [0u8; 8];
523 out[..4].copy_from_slice(&high.to_be_bytes());
524 out[4..].copy_from_slice(&low.to_be_bytes());
525 out
526 }
527
528 #[must_use]
530 pub fn from_bytes_le(bytes: [u8; 8]) -> Self {
531 let mut hi = [0u8; 4];
532 hi.copy_from_slice(&bytes[..4]);
533 let mut lo = [0u8; 4];
534 lo.copy_from_slice(&bytes[4..]);
535 Self::from_high_low(i32::from_le_bytes(hi), u32::from_le_bytes(lo))
536 }
537
538 #[must_use]
540 pub fn from_bytes_be(bytes: [u8; 8]) -> Self {
541 let mut hi = [0u8; 4];
542 hi.copy_from_slice(&bytes[..4]);
543 let mut lo = [0u8; 4];
544 lo.copy_from_slice(&bytes[4..]);
545 Self::from_high_low(i32::from_be_bytes(hi), u32::from_be_bytes(lo))
546 }
547}
548
549#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
558pub struct UExtension4(pub [u8; 4]);
559
560impl UExtension4 {
561 pub const WIRE_SIZE: usize = 4;
563
564 #[must_use]
566 pub fn from_u32_be(v: u32) -> Self {
567 Self(v.to_be_bytes())
568 }
569
570 #[must_use]
572 pub fn to_u32_be(self) -> u32 {
573 u32::from_be_bytes(self.0)
574 }
575
576 #[must_use]
578 pub fn to_bytes(self) -> [u8; 4] {
579 self.0
580 }
581
582 #[must_use]
584 pub fn from_bytes(bytes: [u8; 4]) -> Self {
585 Self(bytes)
586 }
587}
588
589#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
593pub struct WExtension8(pub [u8; 8]);
594
595impl WExtension8 {
596 pub const WIRE_SIZE: usize = 8;
598
599 #[must_use]
601 pub fn from_u64_be(v: u64) -> Self {
602 Self(v.to_be_bytes())
603 }
604
605 #[must_use]
607 pub fn to_u64_be(self) -> u64 {
608 u64::from_be_bytes(self.0)
609 }
610
611 #[must_use]
613 pub fn to_bytes(self) -> [u8; 8] {
614 self.0
615 }
616
617 #[must_use]
619 pub fn from_bytes(bytes: [u8; 8]) -> Self {
620 Self(bytes)
621 }
622}
623
624#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
632pub struct FragmentNumber(pub u32);
633
634impl FragmentNumber {
635 pub const WIRE_SIZE: usize = 4;
637
638 pub const UNKNOWN: Self = Self(0);
640
641 #[must_use]
643 pub fn to_bytes_le(self) -> [u8; 4] {
644 self.0.to_le_bytes()
645 }
646
647 #[must_use]
649 pub fn to_bytes_be(self) -> [u8; 4] {
650 self.0.to_be_bytes()
651 }
652
653 #[must_use]
655 pub fn from_bytes_le(bytes: [u8; 4]) -> Self {
656 Self(u32::from_le_bytes(bytes))
657 }
658
659 #[must_use]
661 pub fn from_bytes_be(bytes: [u8; 4]) -> Self {
662 Self(u32::from_be_bytes(bytes))
663 }
664}
665
666#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
672#[repr(i32)]
673#[allow(missing_docs)]
674pub enum LocatorKind {
675 Invalid = -1,
676 Reserved = 0,
677 UdpV4 = 1,
678 UdpV6 = 2,
679 Tcpv4 = 4,
681 Tcpv6 = 8,
683 Shm = -2_130_706_432, Uds = -2_130_706_431, }
696
697impl LocatorKind {
698 #[must_use]
700 pub fn as_i32(self) -> i32 {
701 self as i32
702 }
703
704 pub fn from_i32(v: i32) -> Result<Self, WireError> {
709 match v {
710 -1 => Ok(Self::Invalid),
711 0 => Ok(Self::Reserved),
712 1 => Ok(Self::UdpV4),
713 2 => Ok(Self::UdpV6),
714 4 => Ok(Self::Tcpv4),
715 8 => Ok(Self::Tcpv6),
716 -2_130_706_432 => Ok(Self::Shm),
717 -2_130_706_431 => Ok(Self::Uds),
718 other => Err(WireError::InvalidLocatorKind { kind: other }),
719 }
720 }
721}
722
723pub const SPDP_DEFAULT_MULTICAST_ADDRESS: [u8; 4] = [239, 255, 0, 1];
725
726pub const SPDP_PORT_BASE: u32 = 7400;
728
729pub const SPDP_DOMAIN_GAIN: u32 = 250;
731
732pub const SPDP_DISCOVERY_MULTICAST_OFFSET: u32 = 0;
734
735#[must_use]
740pub fn spdp_multicast_port(domain_id: u32) -> u32 {
741 SPDP_PORT_BASE + SPDP_DOMAIN_GAIN * domain_id + SPDP_DISCOVERY_MULTICAST_OFFSET
742}
743
744#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
746pub struct Locator {
747 pub kind: LocatorKind,
749 pub port: u32,
751 pub address: [u8; 16],
753}
754
755impl Locator {
756 pub const WIRE_SIZE: usize = 24;
758
759 pub const INVALID: Self = Self {
761 kind: LocatorKind::Invalid,
762 port: 0,
763 address: [0; 16],
764 };
765
766 pub const RESERVED: Self = Self {
769 kind: LocatorKind::Reserved,
770 port: 0,
771 address: [0; 16],
772 };
773
774 pub const UDP_V4_ANY: Self = Self {
776 kind: LocatorKind::UdpV4,
777 port: 0,
778 address: [0; 16],
779 };
780
781 pub const UDP_V6_ANY: Self = Self {
783 kind: LocatorKind::UdpV6,
784 port: 0,
785 address: [0; 16],
786 };
787
788 pub const SHM_ANY: Self = Self {
790 kind: LocatorKind::Shm,
791 port: 0,
792 address: [0; 16],
793 };
794
795 pub const PORT_INVALID: u32 = 0;
797
798 pub const ADDRESS_INVALID: [u8; 16] = [0; 16];
800
801 #[must_use]
803 pub fn udp_v6(addr: [u8; 16], port: u32) -> Self {
804 Self {
805 kind: LocatorKind::UdpV6,
806 port,
807 address: addr,
808 }
809 }
810
811 #[must_use]
813 pub fn udp_v4(addr: [u8; 4], port: u32) -> Self {
814 Self::with_address(LocatorKind::UdpV4, addr, port)
815 }
816
817 #[must_use]
819 pub fn tcp_v4(addr: [u8; 4], port: u32) -> Self {
820 Self::with_address(LocatorKind::Tcpv4, addr, port)
821 }
822
823 #[must_use]
826 #[deprecated(note = "use Locator::tcp_v4 instead (naming consistency)")]
827 pub fn new_tcp_v4(addr: [u8; 4], port: u32) -> Self {
828 Self::tcp_v4(addr, port)
829 }
830
831 #[must_use]
835 pub fn uds(id: [u8; 16]) -> Self {
836 Self {
837 kind: LocatorKind::Uds,
838 port: 0,
839 address: id,
840 }
841 }
842
843 #[must_use]
846 pub fn shm(id: [u8; 16]) -> Self {
847 Self {
848 kind: LocatorKind::Shm,
849 port: 0,
850 address: id,
851 }
852 }
853
854 #[must_use]
857 fn with_address(kind: LocatorKind, addr: [u8; 4], port: u32) -> Self {
858 let mut address = [0u8; 16];
859 address[12..].copy_from_slice(&addr);
860 Self {
861 kind,
862 port,
863 address,
864 }
865 }
866
867 #[must_use]
869 pub fn ipv4(self) -> [u8; 4] {
870 let mut out = [0u8; 4];
871 out.copy_from_slice(&self.address[12..]);
872 out
873 }
874
875 #[must_use]
877 pub fn to_bytes_le(self) -> [u8; 24] {
878 let mut out = [0u8; 24];
879 out[..4].copy_from_slice(&self.kind.as_i32().to_le_bytes());
880 out[4..8].copy_from_slice(&self.port.to_le_bytes());
881 out[8..].copy_from_slice(&self.address);
882 out
883 }
884
885 pub fn from_bytes_le(bytes: [u8; 24]) -> Result<Self, WireError> {
890 let mut kind_bytes = [0u8; 4];
891 kind_bytes.copy_from_slice(&bytes[..4]);
892 let kind = LocatorKind::from_i32(i32::from_le_bytes(kind_bytes))?;
893 let mut port_bytes = [0u8; 4];
894 port_bytes.copy_from_slice(&bytes[4..8]);
895 let port = u32::from_le_bytes(port_bytes);
896 let mut address = [0u8; 16];
897 address.copy_from_slice(&bytes[8..]);
898 Ok(Self {
899 kind,
900 port,
901 address,
902 })
903 }
904}
905
906#[cfg(test)]
907mod tests {
908 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
909 use super::*;
910
911 #[test]
913 fn protocol_version_default_is_2_5() {
914 assert_eq!(ProtocolVersion::default(), ProtocolVersion::V2_5);
915 }
916
917 #[test]
918 fn protocol_version_roundtrip() {
919 let v = ProtocolVersion::V2_5;
920 assert_eq!(ProtocolVersion::from_bytes(v.to_bytes()), v);
921 }
922
923 #[test]
925 fn vendor_id_zerodds_constant() {
926 assert_eq!(VendorId::ZERODDS.0, [0x01, 0xF0]);
927 }
928
929 #[test]
930 fn vendor_id_roundtrip() {
931 let v = VendorId([0xAB, 0xCD]);
932 assert_eq!(VendorId::from_bytes(v.to_bytes()), v);
933 }
934
935 #[test]
937 fn guid_prefix_unknown_is_zero() {
938 assert_eq!(GuidPrefix::UNKNOWN.0, [0u8; 12]);
939 }
940
941 #[test]
942 fn guid_prefix_roundtrip() {
943 let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
944 let p = GuidPrefix::from_bytes(bytes);
945 assert_eq!(p.to_bytes(), bytes);
946 }
947
948 #[test]
950 fn entity_id_user_writer_with_key_layout() {
951 let id = EntityId::user_writer_with_key([0xAA, 0xBB, 0xCC]);
952 assert_eq!(id.to_bytes(), [0xAA, 0xBB, 0xCC, 0x02]);
953 }
954
955 #[test]
956 fn entity_id_user_reader_with_key_layout() {
957 let id = EntityId::user_reader_with_key([0x11, 0x22, 0x33]);
958 assert_eq!(id.to_bytes(), [0x11, 0x22, 0x33, 0x07]);
959 }
960
961 #[test]
962 fn entity_id_participant_constant() {
963 assert_eq!(EntityId::PARTICIPANT.to_bytes(), [0, 0, 1, 0xC1]);
964 }
965
966 #[test]
967 fn entity_id_unknown_kind_byte_maps_to_unknown() {
968 let id = EntityId::from_bytes([1, 2, 3, 0xEE]);
969 assert_eq!(id.entity_kind, EntityKind::Unknown);
970 }
971
972 #[test]
973 fn entity_id_roundtrip() {
974 let id = EntityId::user_writer_with_key([1, 2, 3]);
975 assert_eq!(EntityId::from_bytes(id.to_bytes()), id);
976 }
977
978 #[test]
981 fn secure_publications_writer_layout() {
982 let id = EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER;
984 assert_eq!(id.to_bytes(), [0xff, 0x00, 0x03, 0xC2]);
985 }
986
987 #[test]
988 fn stateless_writer_is_no_key_kind() {
989 let id = EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER;
991 assert_eq!(id.entity_kind, EntityKind::BuiltinWriterNoKey);
992 assert_eq!(id.to_bytes(), [0x00, 0x02, 0x01, 0xC3]);
993 }
994
995 #[test]
996 fn volatile_secure_writer_layout() {
997 let id = EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER;
998 assert_eq!(id.to_bytes(), [0xff, 0x02, 0x02, 0xC2]);
999 }
1000
1001 #[test]
1002 fn spdp_secure_reader_layout() {
1003 let id = EntityId::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER;
1004 assert_eq!(id.to_bytes(), [0xff, 0x01, 0x01, 0xC7]);
1005 }
1006
1007 #[test]
1008 fn all_12_secure_entityids_roundtrip() {
1009 let ids = [
1010 EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER,
1011 EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_READER,
1012 EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER,
1013 EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER,
1014 EntityId::BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER,
1015 EntityId::BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER,
1016 EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER,
1017 EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER,
1018 EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER,
1019 EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_READER,
1020 EntityId::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_WRITER,
1021 EntityId::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER,
1022 ];
1023 assert_eq!(ids.len(), 12);
1024 for id in ids {
1025 assert!(id.is_secure_builtin(), "{id:?}");
1026 assert_eq!(EntityId::from_bytes(id.to_bytes()), id);
1027 }
1028 }
1029
1030 #[test]
1031 fn standard_builtin_is_not_secure_builtin() {
1032 for id in [
1033 EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER,
1034 EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER,
1035 EntityId::BUILTIN_PARTICIPANT_MESSAGE_WRITER,
1036 EntityId::PARTICIPANT,
1037 EntityId::user_writer_with_key([1, 2, 3]),
1038 ] {
1039 assert!(!id.is_secure_builtin(), "{id:?} should not be secure");
1040 }
1041 }
1042
1043 #[test]
1045 fn guid_layout_is_prefix_then_entity_id() {
1046 let g = Guid::new(
1047 GuidPrefix::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
1048 EntityId::user_writer_with_key([0xAA, 0xBB, 0xCC]),
1049 );
1050 let bytes = g.to_bytes();
1051 assert_eq!(&bytes[..12], &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
1052 assert_eq!(&bytes[12..], &[0xAA, 0xBB, 0xCC, 0x02]);
1053 }
1054
1055 #[test]
1056 fn guid_roundtrip() {
1057 let g = Guid::new(GuidPrefix::from_bytes([42; 12]), EntityId::PARTICIPANT);
1058 assert_eq!(Guid::from_bytes(g.to_bytes()), g);
1059 }
1060
1061 #[test]
1063 fn sequence_number_split_zero() {
1064 let (h, l) = SequenceNumber(0).split();
1065 assert_eq!((h, l), (0, 0));
1066 }
1067
1068 #[test]
1069 fn sequence_number_split_one() {
1070 let (h, l) = SequenceNumber(1).split();
1071 assert_eq!((h, l), (0, 1));
1072 }
1073
1074 #[test]
1075 fn sequence_number_split_high_low() {
1076 let sn = SequenceNumber::from_high_low(2, 5);
1077 assert_eq!(sn.0, (2_i64 << 32) | 5);
1078 }
1079
1080 #[test]
1081 fn sequence_number_roundtrip_le() {
1082 let sn = SequenceNumber(0x0102_0304_0506_0708);
1083 assert_eq!(SequenceNumber::from_bytes_le(sn.to_bytes_le()), sn);
1084 }
1085
1086 #[test]
1087 fn sequence_number_roundtrip_be() {
1088 let sn = SequenceNumber(0x0102_0304_0506_0708);
1089 assert_eq!(SequenceNumber::from_bytes_be(sn.to_bytes_be()), sn);
1090 }
1091
1092 #[test]
1093 fn sequence_number_unknown_high_minus_one_low_zero() {
1094 let (h, l) = SequenceNumber::UNKNOWN.split();
1095 assert_eq!((h, l), (-1, 0));
1096 }
1097
1098 #[test]
1100 fn fragment_number_roundtrip_le_be() {
1101 let fns = [
1102 FragmentNumber(0),
1103 FragmentNumber(1),
1104 FragmentNumber(0x1234_5678),
1105 FragmentNumber(u32::MAX),
1106 ];
1107 for fnum in fns {
1108 assert_eq!(FragmentNumber::from_bytes_le(fnum.to_bytes_le()), fnum);
1109 assert_eq!(FragmentNumber::from_bytes_be(fnum.to_bytes_be()), fnum);
1110 }
1111 }
1112
1113 #[test]
1114 fn fragment_number_unknown_is_zero() {
1115 assert_eq!(FragmentNumber::UNKNOWN.0, 0);
1116 }
1117
1118 #[test]
1119 fn fragment_number_wire_size_is_four() {
1120 assert_eq!(FragmentNumber::WIRE_SIZE, 4);
1121 }
1122
1123 #[test]
1125 fn locator_kind_roundtrip() {
1126 for kind in [
1127 LocatorKind::Invalid,
1128 LocatorKind::Reserved,
1129 LocatorKind::UdpV4,
1130 LocatorKind::UdpV6,
1131 LocatorKind::Tcpv4,
1132 LocatorKind::Tcpv6,
1133 LocatorKind::Shm,
1134 LocatorKind::Uds,
1135 ] {
1136 assert_eq!(LocatorKind::from_i32(kind.as_i32()).unwrap(), kind);
1137 }
1138 }
1139
1140 #[test]
1141 fn locator_uds_layout() {
1142 let id = [
1143 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
1144 0x0F, 0x10,
1145 ];
1146 let l = Locator::uds(id);
1147 assert_eq!(l.kind, LocatorKind::Uds);
1148 assert_eq!(l.port, 0);
1149 assert_eq!(l.address, id);
1150 }
1151
1152 #[test]
1153 fn locator_kind_rejects_unknown() {
1154 let res = LocatorKind::from_i32(99);
1155 assert!(matches!(
1156 res,
1157 Err(WireError::InvalidLocatorKind { kind: 99 })
1158 ));
1159 }
1160
1161 #[test]
1162 fn locator_udp_v4_layout() {
1163 let l = Locator::udp_v4([192, 168, 1, 100], 7400);
1164 assert_eq!(l.kind, LocatorKind::UdpV4);
1165 assert_eq!(l.port, 7400);
1166 assert_eq!(&l.address[..12], &[0u8; 12]);
1167 assert_eq!(&l.address[12..], &[192, 168, 1, 100]);
1168 assert_eq!(l.ipv4(), [192, 168, 1, 100]);
1169 }
1170
1171 #[test]
1172 fn locator_roundtrip_le() {
1173 let l = Locator::udp_v4([10, 0, 0, 1], 7400);
1174 let bytes = l.to_bytes_le();
1175 assert_eq!(Locator::from_bytes_le(bytes).unwrap(), l);
1176 }
1177
1178 #[test]
1179 fn locator_invalid_kind_decoded() {
1180 let mut bytes = [0u8; 24];
1181 bytes[..4].copy_from_slice(&99_i32.to_le_bytes());
1182 let res = Locator::from_bytes_le(bytes);
1183 assert!(matches!(
1184 res,
1185 Err(WireError::InvalidLocatorKind { kind: 99 })
1186 ));
1187 }
1188
1189 #[test]
1192 fn locator_invalid_constant_matches_spec() {
1193 assert_eq!(Locator::INVALID.kind, LocatorKind::Invalid);
1194 assert_eq!(Locator::INVALID.port, Locator::PORT_INVALID);
1195 assert_eq!(Locator::INVALID.address, Locator::ADDRESS_INVALID);
1196 }
1197
1198 #[test]
1199 fn locator_reserved_constant_kind_is_zero() {
1200 assert_eq!(Locator::RESERVED.kind.as_i32(), 0);
1201 }
1202
1203 #[test]
1204 fn locator_udp_v4_any_kind_is_one() {
1205 assert_eq!(Locator::UDP_V4_ANY.kind.as_i32(), 1);
1206 assert_eq!(Locator::UDP_V4_ANY.port, 0);
1207 }
1208
1209 #[test]
1210 fn locator_udp_v6_any_kind_is_two() {
1211 assert_eq!(Locator::UDP_V6_ANY.kind.as_i32(), 2);
1212 }
1213
1214 #[test]
1215 fn locator_shm_any_uses_vendor_kind() {
1216 assert!(Locator::SHM_ANY.kind.as_i32() < 0); }
1218
1219 #[test]
1220 fn locator_udp_v6_constructor_keeps_full_address() {
1221 let addr: [u8; 16] = [
1222 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01,
1223 ];
1224 let l = Locator::udp_v6(addr, 1234);
1225 assert_eq!(l.kind, LocatorKind::UdpV6);
1226 assert_eq!(l.address, addr);
1227 assert_eq!(l.port, 1234);
1228 }
1229
1230 #[test]
1231 fn locator_udp_v6_roundtrip_le() {
1232 let l = Locator::udp_v6([1; 16], 9000);
1233 assert_eq!(Locator::from_bytes_le(l.to_bytes_le()).unwrap(), l);
1234 }
1235
1236 #[test]
1239 fn protocol_version_aliases_match_spec() {
1240 assert_eq!(
1241 ProtocolVersion::V1_0,
1242 ProtocolVersion { major: 1, minor: 0 }
1243 );
1244 assert_eq!(
1245 ProtocolVersion::V1_1,
1246 ProtocolVersion { major: 1, minor: 1 }
1247 );
1248 assert_eq!(
1249 ProtocolVersion::V2_0,
1250 ProtocolVersion { major: 2, minor: 0 }
1251 );
1252 assert_eq!(
1253 ProtocolVersion::V2_1,
1254 ProtocolVersion { major: 2, minor: 1 }
1255 );
1256 assert_eq!(
1257 ProtocolVersion::V2_2,
1258 ProtocolVersion { major: 2, minor: 2 }
1259 );
1260 assert_eq!(
1261 ProtocolVersion::V2_3,
1262 ProtocolVersion { major: 2, minor: 3 }
1263 );
1264 assert_eq!(
1265 ProtocolVersion::V2_4,
1266 ProtocolVersion { major: 2, minor: 4 }
1267 );
1268 assert_eq!(
1269 ProtocolVersion::V2_5,
1270 ProtocolVersion { major: 2, minor: 5 }
1271 );
1272 assert_eq!(ProtocolVersion::CURRENT, ProtocolVersion::V2_5);
1273 }
1274
1275 #[test]
1276 fn protocol_version_all_aliases_roundtrip() {
1277 for v in [
1278 ProtocolVersion::V1_0,
1279 ProtocolVersion::V1_1,
1280 ProtocolVersion::V2_0,
1281 ProtocolVersion::V2_1,
1282 ProtocolVersion::V2_2,
1283 ProtocolVersion::V2_3,
1284 ProtocolVersion::V2_4,
1285 ProtocolVersion::V2_5,
1286 ] {
1287 assert_eq!(ProtocolVersion::from_bytes(v.to_bytes()), v);
1288 }
1289 }
1290
1291 #[test]
1294 fn uextension4_roundtrip() {
1295 let u = UExtension4([0xDE, 0xAD, 0xBE, 0xEF]);
1296 assert_eq!(UExtension4::from_bytes(u.to_bytes()), u);
1297 }
1298
1299 #[test]
1300 fn uextension4_u32_be_roundtrip() {
1301 let u = UExtension4::from_u32_be(0x1122_3344);
1302 assert_eq!(u.to_u32_be(), 0x1122_3344);
1303 assert_eq!(u.0, [0x11, 0x22, 0x33, 0x44]);
1304 }
1305
1306 #[test]
1307 fn uextension4_default_is_zero() {
1308 assert_eq!(UExtension4::default().0, [0u8; 4]);
1309 assert_eq!(UExtension4::WIRE_SIZE, 4);
1310 }
1311
1312 #[test]
1315 fn wextension8_roundtrip() {
1316 let w = WExtension8([1, 2, 3, 4, 5, 6, 7, 8]);
1317 assert_eq!(WExtension8::from_bytes(w.to_bytes()), w);
1318 }
1319
1320 #[test]
1321 fn wextension8_u64_be_roundtrip() {
1322 let w = WExtension8::from_u64_be(0x1122_3344_5566_7788);
1323 assert_eq!(w.to_u64_be(), 0x1122_3344_5566_7788);
1324 assert_eq!(w.0, [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]);
1325 }
1326
1327 #[test]
1328 fn wextension8_default_is_zero() {
1329 assert_eq!(WExtension8::default().0, [0u8; 8]);
1330 assert_eq!(WExtension8::WIRE_SIZE, 8);
1331 }
1332
1333 #[test]
1336 fn spdp_builtin_participant_writer_layout() {
1337 let bytes = EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER.to_bytes();
1339 assert_eq!(bytes, [0x00, 0x01, 0x00, 0xC2]);
1340 }
1341
1342 #[test]
1343 fn spdp_builtin_participant_reader_layout() {
1344 let bytes = EntityId::SPDP_BUILTIN_PARTICIPANT_READER.to_bytes();
1346 assert_eq!(bytes, [0x00, 0x01, 0x00, 0xC7]);
1347 }
1348
1349 #[test]
1350 fn sedp_publications_writer_layout() {
1351 let bytes = EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER.to_bytes();
1353 assert_eq!(bytes, [0x00, 0x00, 0x03, 0xC2]);
1354 }
1355
1356 #[test]
1357 fn sedp_subscriptions_reader_layout() {
1358 let bytes = EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_READER.to_bytes();
1360 assert_eq!(bytes, [0x00, 0x00, 0x04, 0xC7]);
1361 }
1362
1363 #[test]
1366 fn spdp_default_multicast_is_239_255_0_1() {
1367 assert_eq!(SPDP_DEFAULT_MULTICAST_ADDRESS, [239, 255, 0, 1]);
1368 }
1369
1370 #[test]
1371 fn spdp_multicast_port_domain_0_is_7400() {
1372 assert_eq!(spdp_multicast_port(0), 7400);
1373 }
1374
1375 #[test]
1376 fn spdp_multicast_port_domain_1_is_7650() {
1377 assert_eq!(spdp_multicast_port(1), 7650);
1378 }
1379
1380 #[test]
1381 fn spdp_multicast_port_domain_5_is_8650() {
1382 assert_eq!(spdp_multicast_port(5), 8650);
1383 }
1384}