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 pub const OPENDDS: Self = Self([0x01, 0x03]);
105
106 pub const FASTDDS: Self = Self([0x01, 0x0F]);
108
109 pub const CYCLONE: Self = Self([0x01, 0x10]);
111
112 #[must_use]
114 pub fn to_bytes(self) -> [u8; 2] {
115 self.0
116 }
117
118 #[must_use]
120 pub fn from_bytes(bytes: [u8; 2]) -> Self {
121 Self(bytes)
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
132pub struct GuidPrefix(pub [u8; 12]);
133
134impl GuidPrefix {
135 pub const WIRE_SIZE: usize = 12;
137
138 pub const UNKNOWN: Self = Self([0; 12]);
140
141 #[must_use]
143 pub fn to_bytes(self) -> [u8; 12] {
144 self.0
145 }
146
147 #[must_use]
149 pub fn from_bytes(bytes: [u8; 12]) -> Self {
150 Self(bytes)
151 }
152
153 #[must_use]
163 pub fn host_id(self) -> [u8; 4] {
164 [self.0[0], self.0[1], self.0[2], self.0[3]]
165 }
166
167 #[must_use]
170 pub fn is_same_host(self, other: Self) -> bool {
171 self.host_id() == other.host_id()
172 }
173}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
181#[repr(u8)]
182#[allow(missing_docs)]
183pub enum EntityKind {
184 Unknown = 0x00,
185 UserWriterNoKey = 0x03,
186 UserWriterWithKey = 0x02,
187 UserReaderNoKey = 0x04,
188 UserReaderWithKey = 0x07,
189 BuiltinWriterNoKey = 0xC3,
190 BuiltinWriterWithKey = 0xC2,
191 BuiltinReaderNoKey = 0xC4,
192 BuiltinReaderWithKey = 0xC7,
193 Participant = 0xC1,
194}
195
196impl EntityKind {
197 #[must_use]
200 pub fn from_byte(b: u8) -> Self {
201 match b {
202 0x03 => Self::UserWriterNoKey,
203 0x02 => Self::UserWriterWithKey,
204 0x04 => Self::UserReaderNoKey,
205 0x07 => Self::UserReaderWithKey,
206 0xC3 => Self::BuiltinWriterNoKey,
207 0xC2 => Self::BuiltinWriterWithKey,
208 0xC4 => Self::BuiltinReaderNoKey,
209 0xC7 => Self::BuiltinReaderWithKey,
210 0xC1 => Self::Participant,
211 _ => Self::Unknown,
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
219pub struct EntityId {
220 pub entity_key: [u8; 3],
222 pub entity_kind: EntityKind,
224}
225
226impl EntityId {
227 pub const WIRE_SIZE: usize = 4;
229
230 pub const UNKNOWN: Self = Self {
232 entity_key: [0; 3],
233 entity_kind: EntityKind::Unknown,
234 };
235
236 pub const PARTICIPANT: Self = Self {
238 entity_key: [0, 0, 1],
239 entity_kind: EntityKind::Participant,
240 };
241
242 #[must_use]
244 pub const fn user_writer_with_key(key: [u8; 3]) -> Self {
245 Self {
246 entity_key: key,
247 entity_kind: EntityKind::UserWriterWithKey,
248 }
249 }
250
251 #[must_use]
253 pub const fn user_reader_with_key(key: [u8; 3]) -> Self {
254 Self {
255 entity_key: key,
256 entity_kind: EntityKind::UserReaderWithKey,
257 }
258 }
259
260 #[must_use]
266 pub const fn user_writer_no_key(key: [u8; 3]) -> Self {
267 Self {
268 entity_key: key,
269 entity_kind: EntityKind::UserWriterNoKey,
270 }
271 }
272
273 #[must_use]
276 pub const fn user_reader_no_key(key: [u8; 3]) -> Self {
277 Self {
278 entity_key: key,
279 entity_kind: EntityKind::UserReaderNoKey,
280 }
281 }
282
283 pub const SPDP_BUILTIN_PARTICIPANT_WRITER: Self = Self {
286 entity_key: [0, 0x01, 0x00],
287 entity_kind: EntityKind::BuiltinWriterWithKey,
288 };
289
290 pub const SPDP_BUILTIN_PARTICIPANT_READER: Self = Self {
292 entity_key: [0, 0x01, 0x00],
293 entity_kind: EntityKind::BuiltinReaderWithKey,
294 };
295
296 pub const SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: Self = Self {
298 entity_key: [0, 0x00, 0x04],
299 entity_kind: EntityKind::BuiltinWriterWithKey,
300 };
301
302 pub const SEDP_BUILTIN_SUBSCRIPTIONS_READER: Self = Self {
304 entity_key: [0, 0x00, 0x04],
305 entity_kind: EntityKind::BuiltinReaderWithKey,
306 };
307
308 pub const SEDP_BUILTIN_PUBLICATIONS_WRITER: Self = Self {
310 entity_key: [0, 0x00, 0x03],
311 entity_kind: EntityKind::BuiltinWriterWithKey,
312 };
313
314 pub const SEDP_BUILTIN_PUBLICATIONS_READER: Self = Self {
316 entity_key: [0, 0x00, 0x03],
317 entity_kind: EntityKind::BuiltinReaderWithKey,
318 };
319
320 pub const BUILTIN_PARTICIPANT_MESSAGE_WRITER: Self = Self {
326 entity_key: [0, 0x02, 0x00],
327 entity_kind: EntityKind::BuiltinWriterWithKey,
328 };
329
330 pub const BUILTIN_PARTICIPANT_MESSAGE_READER: Self = Self {
333 entity_key: [0, 0x02, 0x00],
334 entity_kind: EntityKind::BuiltinReaderWithKey,
335 };
336
337 pub const TL_SVC_REQ_WRITER: Self = Self {
341 entity_key: [0, 0x03, 0x00],
342 entity_kind: EntityKind::BuiltinWriterNoKey,
343 };
344 pub const TL_SVC_REQ_READER: Self = Self {
346 entity_key: [0, 0x03, 0x00],
347 entity_kind: EntityKind::BuiltinReaderNoKey,
348 };
349 pub const TL_SVC_REPLY_WRITER: Self = Self {
351 entity_key: [0, 0x03, 0x01],
352 entity_kind: EntityKind::BuiltinWriterNoKey,
353 };
354 pub const TL_SVC_REPLY_READER: Self = Self {
356 entity_key: [0, 0x03, 0x01],
357 entity_kind: EntityKind::BuiltinReaderNoKey,
358 };
359
360 pub const SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: Self = Self {
369 entity_key: [0xff, 0x00, 0x03],
370 entity_kind: EntityKind::BuiltinWriterWithKey,
371 };
372 pub const SEDP_BUILTIN_PUBLICATIONS_SECURE_READER: Self = Self {
374 entity_key: [0xff, 0x00, 0x03],
375 entity_kind: EntityKind::BuiltinReaderWithKey,
376 };
377 pub const SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: Self = Self {
379 entity_key: [0xff, 0x00, 0x04],
380 entity_kind: EntityKind::BuiltinWriterWithKey,
381 };
382 pub const SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER: Self = Self {
384 entity_key: [0xff, 0x00, 0x04],
385 entity_kind: EntityKind::BuiltinReaderWithKey,
386 };
387 pub const BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: Self = Self {
390 entity_key: [0xff, 0x02, 0x00],
391 entity_kind: EntityKind::BuiltinWriterWithKey,
392 };
393 pub const BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER: Self = Self {
395 entity_key: [0xff, 0x02, 0x00],
396 entity_kind: EntityKind::BuiltinReaderWithKey,
397 };
398 pub const BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: Self = Self {
402 entity_key: [0x00, 0x02, 0x01],
403 entity_kind: EntityKind::BuiltinWriterNoKey,
404 };
405 pub const BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER: Self = Self {
407 entity_key: [0x00, 0x02, 0x01],
408 entity_kind: EntityKind::BuiltinReaderNoKey,
409 };
410 pub const BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER: Self = Self {
414 entity_key: [0xff, 0x02, 0x02],
415 entity_kind: EntityKind::BuiltinWriterNoKey,
419 };
420 pub const BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_READER: Self = Self {
422 entity_key: [0xff, 0x02, 0x02],
423 entity_kind: EntityKind::BuiltinReaderNoKey,
425 };
426 pub const SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_WRITER: Self = Self {
429 entity_key: [0xff, 0x01, 0x01],
430 entity_kind: EntityKind::BuiltinWriterWithKey,
431 };
432 pub const SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER: Self = Self {
434 entity_key: [0xff, 0x01, 0x01],
435 entity_kind: EntityKind::BuiltinReaderWithKey,
436 };
437
438 #[must_use]
441 pub const fn is_secure_builtin(self) -> bool {
442 matches!(
443 self,
444 Self::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER
445 | Self::SEDP_BUILTIN_PUBLICATIONS_SECURE_READER
446 | Self::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER
447 | Self::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER
448 | Self::BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER
449 | Self::BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER
450 | Self::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER
451 | Self::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER
452 | Self::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER
453 | Self::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_READER
454 | Self::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_WRITER
455 | Self::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER
456 )
457 }
458
459 #[must_use]
461 pub fn to_bytes(self) -> [u8; 4] {
462 [
463 self.entity_key[0],
464 self.entity_key[1],
465 self.entity_key[2],
466 self.entity_kind as u8,
467 ]
468 }
469
470 #[must_use]
472 pub fn from_bytes(bytes: [u8; 4]) -> Self {
473 Self {
474 entity_key: [bytes[0], bytes[1], bytes[2]],
475 entity_kind: EntityKind::from_byte(bytes[3]),
476 }
477 }
478}
479
480#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
487pub struct Guid {
488 pub prefix: GuidPrefix,
490 pub entity_id: EntityId,
492}
493
494impl Guid {
495 pub const WIRE_SIZE: usize = 16;
497
498 pub const UNKNOWN: Self = Self {
500 prefix: GuidPrefix::UNKNOWN,
501 entity_id: EntityId::UNKNOWN,
502 };
503
504 #[must_use]
506 pub const fn new(prefix: GuidPrefix, entity_id: EntityId) -> Self {
507 Self { prefix, entity_id }
508 }
509
510 #[must_use]
512 pub fn to_bytes(self) -> [u8; 16] {
513 let mut out = [0u8; 16];
514 out[..12].copy_from_slice(&self.prefix.to_bytes());
515 out[12..].copy_from_slice(&self.entity_id.to_bytes());
516 out
517 }
518
519 #[must_use]
521 pub fn from_bytes(bytes: [u8; 16]) -> Self {
522 let mut prefix_bytes = [0u8; 12];
523 prefix_bytes.copy_from_slice(&bytes[..12]);
524 let mut entity_bytes = [0u8; 4];
525 entity_bytes.copy_from_slice(&bytes[12..]);
526 Self {
527 prefix: GuidPrefix::from_bytes(prefix_bytes),
528 entity_id: EntityId::from_bytes(entity_bytes),
529 }
530 }
531}
532
533#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
540pub struct SequenceNumber(pub i64);
541
542impl SequenceNumber {
543 pub const WIRE_SIZE: usize = 8;
545
546 pub const UNKNOWN: Self = Self(-(1_i64 << 32));
548
549 #[must_use]
551 pub fn split(self) -> (i32, u32) {
552 let value = self.0;
553 let high = (value >> 32) as i32;
554 let low = (value & 0xFFFF_FFFF) as u32;
555 (high, low)
556 }
557
558 #[must_use]
560 pub fn from_high_low(high: i32, low: u32) -> Self {
561 let value = (i64::from(high) << 32) | i64::from(low);
562 Self(value)
563 }
564
565 #[must_use]
567 pub fn to_bytes_le(self) -> [u8; 8] {
568 let (high, low) = self.split();
569 let mut out = [0u8; 8];
570 out[..4].copy_from_slice(&high.to_le_bytes());
571 out[4..].copy_from_slice(&low.to_le_bytes());
572 out
573 }
574
575 #[must_use]
577 pub fn to_bytes_be(self) -> [u8; 8] {
578 let (high, low) = self.split();
579 let mut out = [0u8; 8];
580 out[..4].copy_from_slice(&high.to_be_bytes());
581 out[4..].copy_from_slice(&low.to_be_bytes());
582 out
583 }
584
585 #[must_use]
587 pub fn from_bytes_le(bytes: [u8; 8]) -> Self {
588 let mut hi = [0u8; 4];
589 hi.copy_from_slice(&bytes[..4]);
590 let mut lo = [0u8; 4];
591 lo.copy_from_slice(&bytes[4..]);
592 Self::from_high_low(i32::from_le_bytes(hi), u32::from_le_bytes(lo))
593 }
594
595 #[must_use]
597 pub fn from_bytes_be(bytes: [u8; 8]) -> Self {
598 let mut hi = [0u8; 4];
599 hi.copy_from_slice(&bytes[..4]);
600 let mut lo = [0u8; 4];
601 lo.copy_from_slice(&bytes[4..]);
602 Self::from_high_low(i32::from_be_bytes(hi), u32::from_be_bytes(lo))
603 }
604}
605
606#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
615pub struct UExtension4(pub [u8; 4]);
616
617impl UExtension4 {
618 pub const WIRE_SIZE: usize = 4;
620
621 #[must_use]
623 pub fn from_u32_be(v: u32) -> Self {
624 Self(v.to_be_bytes())
625 }
626
627 #[must_use]
629 pub fn to_u32_be(self) -> u32 {
630 u32::from_be_bytes(self.0)
631 }
632
633 #[must_use]
635 pub fn to_bytes(self) -> [u8; 4] {
636 self.0
637 }
638
639 #[must_use]
641 pub fn from_bytes(bytes: [u8; 4]) -> Self {
642 Self(bytes)
643 }
644}
645
646#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
650pub struct WExtension8(pub [u8; 8]);
651
652impl WExtension8 {
653 pub const WIRE_SIZE: usize = 8;
655
656 #[must_use]
658 pub fn from_u64_be(v: u64) -> Self {
659 Self(v.to_be_bytes())
660 }
661
662 #[must_use]
664 pub fn to_u64_be(self) -> u64 {
665 u64::from_be_bytes(self.0)
666 }
667
668 #[must_use]
670 pub fn to_bytes(self) -> [u8; 8] {
671 self.0
672 }
673
674 #[must_use]
676 pub fn from_bytes(bytes: [u8; 8]) -> Self {
677 Self(bytes)
678 }
679}
680
681#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
689pub struct FragmentNumber(pub u32);
690
691impl FragmentNumber {
692 pub const WIRE_SIZE: usize = 4;
694
695 pub const UNKNOWN: Self = Self(0);
697
698 #[must_use]
700 pub fn to_bytes_le(self) -> [u8; 4] {
701 self.0.to_le_bytes()
702 }
703
704 #[must_use]
706 pub fn to_bytes_be(self) -> [u8; 4] {
707 self.0.to_be_bytes()
708 }
709
710 #[must_use]
712 pub fn from_bytes_le(bytes: [u8; 4]) -> Self {
713 Self(u32::from_le_bytes(bytes))
714 }
715
716 #[must_use]
718 pub fn from_bytes_be(bytes: [u8; 4]) -> Self {
719 Self(u32::from_be_bytes(bytes))
720 }
721}
722
723#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
729#[repr(i32)]
730#[allow(missing_docs)]
731pub enum LocatorKind {
732 Invalid = -1,
733 Reserved = 0,
734 UdpV4 = 1,
735 UdpV6 = 2,
736 Tcpv4 = 4,
738 Tcpv6 = 8,
740 Shm = -2_130_706_432, Uds = -2_130_706_431, Tsn = -2_130_706_430, }
759
760impl LocatorKind {
761 #[must_use]
763 pub fn as_i32(self) -> i32 {
764 self as i32
765 }
766
767 pub fn from_i32(v: i32) -> Result<Self, WireError> {
772 match v {
773 -1 => Ok(Self::Invalid),
774 0 => Ok(Self::Reserved),
775 1 => Ok(Self::UdpV4),
776 2 => Ok(Self::UdpV6),
777 4 => Ok(Self::Tcpv4),
778 8 => Ok(Self::Tcpv6),
779 -2_130_706_432 => Ok(Self::Shm),
780 -2_130_706_431 => Ok(Self::Uds),
781 -2_130_706_430 => Ok(Self::Tsn),
782 other => Err(WireError::InvalidLocatorKind { kind: other }),
783 }
784 }
785}
786
787pub const SPDP_DEFAULT_MULTICAST_ADDRESS: [u8; 4] = [239, 255, 0, 1];
789
790pub const SPDP_PORT_BASE: u32 = 7400;
792
793pub const SPDP_DOMAIN_GAIN: u32 = 250;
795
796pub const SPDP_DISCOVERY_MULTICAST_OFFSET: u32 = 0;
798
799#[must_use]
804pub fn spdp_multicast_port(domain_id: u32) -> u32 {
805 SPDP_PORT_BASE + SPDP_DOMAIN_GAIN * domain_id + SPDP_DISCOVERY_MULTICAST_OFFSET
806}
807
808#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
810pub struct Locator {
811 pub kind: LocatorKind,
813 pub port: u32,
815 pub address: [u8; 16],
817}
818
819impl Locator {
820 pub const WIRE_SIZE: usize = 24;
822
823 pub const INVALID: Self = Self {
825 kind: LocatorKind::Invalid,
826 port: 0,
827 address: [0; 16],
828 };
829
830 pub const RESERVED: Self = Self {
833 kind: LocatorKind::Reserved,
834 port: 0,
835 address: [0; 16],
836 };
837
838 pub const UDP_V4_ANY: Self = Self {
840 kind: LocatorKind::UdpV4,
841 port: 0,
842 address: [0; 16],
843 };
844
845 pub const UDP_V6_ANY: Self = Self {
847 kind: LocatorKind::UdpV6,
848 port: 0,
849 address: [0; 16],
850 };
851
852 pub const SHM_ANY: Self = Self {
854 kind: LocatorKind::Shm,
855 port: 0,
856 address: [0; 16],
857 };
858
859 pub const PORT_INVALID: u32 = 0;
861
862 pub const ADDRESS_INVALID: [u8; 16] = [0; 16];
864
865 #[must_use]
867 pub fn udp_v6(addr: [u8; 16], port: u32) -> Self {
868 Self {
869 kind: LocatorKind::UdpV6,
870 port,
871 address: addr,
872 }
873 }
874
875 #[must_use]
877 pub fn udp_v4(addr: [u8; 4], port: u32) -> Self {
878 Self::with_address(LocatorKind::UdpV4, addr, port)
879 }
880
881 #[must_use]
883 pub fn tcp_v4(addr: [u8; 4], port: u32) -> Self {
884 Self::with_address(LocatorKind::Tcpv4, addr, port)
885 }
886
887 #[must_use]
890 pub fn tcp_v6(addr: [u8; 16], port: u32) -> Self {
891 Self {
892 kind: LocatorKind::Tcpv6,
893 port,
894 address: addr,
895 }
896 }
897
898 #[must_use]
901 #[deprecated(note = "use Locator::tcp_v4 instead (naming consistency)")]
902 pub fn new_tcp_v4(addr: [u8; 4], port: u32) -> Self {
903 Self::tcp_v4(addr, port)
904 }
905
906 #[must_use]
910 pub fn uds(id: [u8; 16]) -> Self {
911 Self {
912 kind: LocatorKind::Uds,
913 port: 0,
914 address: id,
915 }
916 }
917
918 #[must_use]
921 pub fn shm(id: [u8; 16]) -> Self {
922 Self {
923 kind: LocatorKind::Shm,
924 port: 0,
925 address: id,
926 }
927 }
928
929 #[must_use]
934 pub fn tsn(mac: [u8; 6], vlan_vid: u16) -> Self {
935 let mut address = [0u8; 16];
936 address[..6].copy_from_slice(&mac);
937 address[6..8].copy_from_slice(&vlan_vid.to_be_bytes());
938 Self {
939 kind: LocatorKind::Tsn,
940 port: 0,
941 address,
942 }
943 }
944
945 #[must_use]
948 fn with_address(kind: LocatorKind, addr: [u8; 4], port: u32) -> Self {
949 let mut address = [0u8; 16];
950 address[12..].copy_from_slice(&addr);
951 Self {
952 kind,
953 port,
954 address,
955 }
956 }
957
958 #[must_use]
960 pub fn ipv4(self) -> [u8; 4] {
961 let mut out = [0u8; 4];
962 out.copy_from_slice(&self.address[12..]);
963 out
964 }
965
966 #[must_use]
968 pub fn to_bytes_le(self) -> [u8; 24] {
969 let mut out = [0u8; 24];
970 out[..4].copy_from_slice(&self.kind.as_i32().to_le_bytes());
971 out[4..8].copy_from_slice(&self.port.to_le_bytes());
972 out[8..].copy_from_slice(&self.address);
973 out
974 }
975
976 #[must_use]
978 pub fn to_bytes_be(self) -> [u8; 24] {
979 let mut out = [0u8; 24];
980 out[..4].copy_from_slice(&self.kind.as_i32().to_be_bytes());
981 out[4..8].copy_from_slice(&self.port.to_be_bytes());
982 out[8..].copy_from_slice(&self.address);
983 out
984 }
985
986 pub fn from_bytes_le(bytes: [u8; 24]) -> Result<Self, WireError> {
991 let mut kind_bytes = [0u8; 4];
992 kind_bytes.copy_from_slice(&bytes[..4]);
993 let kind = LocatorKind::from_i32(i32::from_le_bytes(kind_bytes))?;
994 let mut port_bytes = [0u8; 4];
995 port_bytes.copy_from_slice(&bytes[4..8]);
996 let port = u32::from_le_bytes(port_bytes);
997 let mut address = [0u8; 16];
998 address.copy_from_slice(&bytes[8..]);
999 Ok(Self {
1000 kind,
1001 port,
1002 address,
1003 })
1004 }
1005}
1006
1007#[cfg(test)]
1008mod tests {
1009 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
1010 use super::*;
1011
1012 #[test]
1014 fn protocol_version_default_is_2_5() {
1015 assert_eq!(ProtocolVersion::default(), ProtocolVersion::V2_5);
1016 }
1017
1018 #[test]
1019 fn protocol_version_roundtrip() {
1020 let v = ProtocolVersion::V2_5;
1021 assert_eq!(ProtocolVersion::from_bytes(v.to_bytes()), v);
1022 }
1023
1024 #[test]
1026 fn vendor_id_zerodds_constant() {
1027 assert_eq!(VendorId::ZERODDS.0, [0x01, 0xF0]);
1028 }
1029
1030 #[test]
1031 fn vendor_id_roundtrip() {
1032 let v = VendorId([0xAB, 0xCD]);
1033 assert_eq!(VendorId::from_bytes(v.to_bytes()), v);
1034 }
1035
1036 #[test]
1038 fn guid_prefix_unknown_is_zero() {
1039 assert_eq!(GuidPrefix::UNKNOWN.0, [0u8; 12]);
1040 }
1041
1042 #[test]
1043 fn guid_prefix_roundtrip() {
1044 let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
1045 let p = GuidPrefix::from_bytes(bytes);
1046 assert_eq!(p.to_bytes(), bytes);
1047 }
1048
1049 #[test]
1050 fn guid_prefix_host_id_is_first_four_bytes() {
1051 let p = GuidPrefix::from_bytes([0xAB, 0xCD, 0x12, 0x34, 0, 0, 0, 0, 0, 0, 0, 0]);
1052 assert_eq!(p.host_id(), [0xAB, 0xCD, 0x12, 0x34]);
1053 }
1054
1055 #[test]
1056 fn guid_prefix_same_host_matches_on_first_four_bytes() {
1057 let a = GuidPrefix::from_bytes([1, 2, 3, 4, 9, 9, 9, 9, 9, 9, 9, 9]);
1058 let b = GuidPrefix::from_bytes([1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0]);
1059 let c = GuidPrefix::from_bytes([1, 2, 3, 5, 9, 9, 9, 9, 9, 9, 9, 9]);
1060 assert!(a.is_same_host(b));
1061 assert!(!a.is_same_host(c));
1062 }
1063
1064 #[test]
1066 fn entity_id_user_writer_with_key_layout() {
1067 let id = EntityId::user_writer_with_key([0xAA, 0xBB, 0xCC]);
1068 assert_eq!(id.to_bytes(), [0xAA, 0xBB, 0xCC, 0x02]);
1069 }
1070
1071 #[test]
1072 fn entity_id_user_reader_with_key_layout() {
1073 let id = EntityId::user_reader_with_key([0x11, 0x22, 0x33]);
1074 assert_eq!(id.to_bytes(), [0x11, 0x22, 0x33, 0x07]);
1075 }
1076
1077 #[test]
1078 fn entity_id_participant_constant() {
1079 assert_eq!(EntityId::PARTICIPANT.to_bytes(), [0, 0, 1, 0xC1]);
1080 }
1081
1082 #[test]
1083 fn entity_id_unknown_kind_byte_maps_to_unknown() {
1084 let id = EntityId::from_bytes([1, 2, 3, 0xEE]);
1085 assert_eq!(id.entity_kind, EntityKind::Unknown);
1086 }
1087
1088 #[test]
1089 fn entity_id_roundtrip() {
1090 let id = EntityId::user_writer_with_key([1, 2, 3]);
1091 assert_eq!(EntityId::from_bytes(id.to_bytes()), id);
1092 }
1093
1094 #[test]
1097 fn secure_publications_writer_layout() {
1098 let id = EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER;
1100 assert_eq!(id.to_bytes(), [0xff, 0x00, 0x03, 0xC2]);
1101 }
1102
1103 #[test]
1104 fn stateless_writer_is_no_key_kind() {
1105 let id = EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER;
1107 assert_eq!(id.entity_kind, EntityKind::BuiltinWriterNoKey);
1108 assert_eq!(id.to_bytes(), [0x00, 0x02, 0x01, 0xC3]);
1109 }
1110
1111 #[test]
1112 fn volatile_secure_writer_layout() {
1113 let id = EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER;
1116 assert_eq!(id.to_bytes(), [0xff, 0x02, 0x02, 0xC3]);
1117 }
1118
1119 #[test]
1120 fn spdp_secure_reader_layout() {
1121 let id = EntityId::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER;
1122 assert_eq!(id.to_bytes(), [0xff, 0x01, 0x01, 0xC7]);
1123 }
1124
1125 #[test]
1126 fn all_12_secure_entityids_roundtrip() {
1127 let ids = [
1128 EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER,
1129 EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_READER,
1130 EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER,
1131 EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER,
1132 EntityId::BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER,
1133 EntityId::BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER,
1134 EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER,
1135 EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER,
1136 EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER,
1137 EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_READER,
1138 EntityId::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_WRITER,
1139 EntityId::SPDP_RELIABLE_BUILTIN_PARTICIPANTS_SECURE_READER,
1140 ];
1141 assert_eq!(ids.len(), 12);
1142 for id in ids {
1143 assert!(id.is_secure_builtin(), "{id:?}");
1144 assert_eq!(EntityId::from_bytes(id.to_bytes()), id);
1145 }
1146 }
1147
1148 #[test]
1149 fn standard_builtin_is_not_secure_builtin() {
1150 for id in [
1151 EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER,
1152 EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER,
1153 EntityId::BUILTIN_PARTICIPANT_MESSAGE_WRITER,
1154 EntityId::PARTICIPANT,
1155 EntityId::user_writer_with_key([1, 2, 3]),
1156 ] {
1157 assert!(!id.is_secure_builtin(), "{id:?} should not be secure");
1158 }
1159 }
1160
1161 #[test]
1163 fn guid_layout_is_prefix_then_entity_id() {
1164 let g = Guid::new(
1165 GuidPrefix::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
1166 EntityId::user_writer_with_key([0xAA, 0xBB, 0xCC]),
1167 );
1168 let bytes = g.to_bytes();
1169 assert_eq!(&bytes[..12], &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
1170 assert_eq!(&bytes[12..], &[0xAA, 0xBB, 0xCC, 0x02]);
1171 }
1172
1173 #[test]
1174 fn guid_roundtrip() {
1175 let g = Guid::new(GuidPrefix::from_bytes([42; 12]), EntityId::PARTICIPANT);
1176 assert_eq!(Guid::from_bytes(g.to_bytes()), g);
1177 }
1178
1179 #[test]
1181 fn sequence_number_split_zero() {
1182 let (h, l) = SequenceNumber(0).split();
1183 assert_eq!((h, l), (0, 0));
1184 }
1185
1186 #[test]
1187 fn sequence_number_split_one() {
1188 let (h, l) = SequenceNumber(1).split();
1189 assert_eq!((h, l), (0, 1));
1190 }
1191
1192 #[test]
1193 fn sequence_number_split_high_low() {
1194 let sn = SequenceNumber::from_high_low(2, 5);
1195 assert_eq!(sn.0, (2_i64 << 32) | 5);
1196 }
1197
1198 #[test]
1199 fn sequence_number_roundtrip_le() {
1200 let sn = SequenceNumber(0x0102_0304_0506_0708);
1201 assert_eq!(SequenceNumber::from_bytes_le(sn.to_bytes_le()), sn);
1202 }
1203
1204 #[test]
1205 fn sequence_number_roundtrip_be() {
1206 let sn = SequenceNumber(0x0102_0304_0506_0708);
1207 assert_eq!(SequenceNumber::from_bytes_be(sn.to_bytes_be()), sn);
1208 }
1209
1210 #[test]
1211 fn sequence_number_unknown_high_minus_one_low_zero() {
1212 let (h, l) = SequenceNumber::UNKNOWN.split();
1213 assert_eq!((h, l), (-1, 0));
1214 }
1215
1216 #[test]
1218 fn fragment_number_roundtrip_le_be() {
1219 let fns = [
1220 FragmentNumber(0),
1221 FragmentNumber(1),
1222 FragmentNumber(0x1234_5678),
1223 FragmentNumber(u32::MAX),
1224 ];
1225 for fnum in fns {
1226 assert_eq!(FragmentNumber::from_bytes_le(fnum.to_bytes_le()), fnum);
1227 assert_eq!(FragmentNumber::from_bytes_be(fnum.to_bytes_be()), fnum);
1228 }
1229 }
1230
1231 #[test]
1232 fn fragment_number_unknown_is_zero() {
1233 assert_eq!(FragmentNumber::UNKNOWN.0, 0);
1234 }
1235
1236 #[test]
1237 fn fragment_number_wire_size_is_four() {
1238 assert_eq!(FragmentNumber::WIRE_SIZE, 4);
1239 }
1240
1241 #[test]
1243 fn locator_kind_roundtrip() {
1244 for kind in [
1245 LocatorKind::Invalid,
1246 LocatorKind::Reserved,
1247 LocatorKind::UdpV4,
1248 LocatorKind::UdpV6,
1249 LocatorKind::Tcpv4,
1250 LocatorKind::Tcpv6,
1251 LocatorKind::Shm,
1252 LocatorKind::Uds,
1253 ] {
1254 assert_eq!(LocatorKind::from_i32(kind.as_i32()).unwrap(), kind);
1255 }
1256 }
1257
1258 #[test]
1259 fn locator_uds_layout() {
1260 let id = [
1261 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
1262 0x0F, 0x10,
1263 ];
1264 let l = Locator::uds(id);
1265 assert_eq!(l.kind, LocatorKind::Uds);
1266 assert_eq!(l.port, 0);
1267 assert_eq!(l.address, id);
1268 }
1269
1270 #[test]
1271 fn locator_kind_rejects_unknown() {
1272 let res = LocatorKind::from_i32(99);
1273 assert!(matches!(
1274 res,
1275 Err(WireError::InvalidLocatorKind { kind: 99 })
1276 ));
1277 }
1278
1279 #[test]
1280 fn locator_udp_v4_layout() {
1281 let l = Locator::udp_v4([192, 168, 1, 100], 7400);
1282 assert_eq!(l.kind, LocatorKind::UdpV4);
1283 assert_eq!(l.port, 7400);
1284 assert_eq!(&l.address[..12], &[0u8; 12]);
1285 assert_eq!(&l.address[12..], &[192, 168, 1, 100]);
1286 assert_eq!(l.ipv4(), [192, 168, 1, 100]);
1287 }
1288
1289 #[test]
1290 fn locator_roundtrip_le() {
1291 let l = Locator::udp_v4([10, 0, 0, 1], 7400);
1292 let bytes = l.to_bytes_le();
1293 assert_eq!(Locator::from_bytes_le(bytes).unwrap(), l);
1294 }
1295
1296 #[test]
1297 fn locator_invalid_kind_decoded() {
1298 let mut bytes = [0u8; 24];
1299 bytes[..4].copy_from_slice(&99_i32.to_le_bytes());
1300 let res = Locator::from_bytes_le(bytes);
1301 assert!(matches!(
1302 res,
1303 Err(WireError::InvalidLocatorKind { kind: 99 })
1304 ));
1305 }
1306
1307 #[test]
1310 fn locator_invalid_constant_matches_spec() {
1311 assert_eq!(Locator::INVALID.kind, LocatorKind::Invalid);
1312 assert_eq!(Locator::INVALID.port, Locator::PORT_INVALID);
1313 assert_eq!(Locator::INVALID.address, Locator::ADDRESS_INVALID);
1314 }
1315
1316 #[test]
1317 fn locator_reserved_constant_kind_is_zero() {
1318 assert_eq!(Locator::RESERVED.kind.as_i32(), 0);
1319 }
1320
1321 #[test]
1322 fn locator_udp_v4_any_kind_is_one() {
1323 assert_eq!(Locator::UDP_V4_ANY.kind.as_i32(), 1);
1324 assert_eq!(Locator::UDP_V4_ANY.port, 0);
1325 }
1326
1327 #[test]
1328 fn locator_udp_v6_any_kind_is_two() {
1329 assert_eq!(Locator::UDP_V6_ANY.kind.as_i32(), 2);
1330 }
1331
1332 #[test]
1333 fn locator_shm_any_uses_vendor_kind() {
1334 assert!(Locator::SHM_ANY.kind.as_i32() < 0); }
1336
1337 #[test]
1338 fn locator_tsn_carries_mac_and_vlan() {
1339 let mac = [0x02, 0x00, 0x00, 0x11, 0x22, 0x33];
1340 let loc = Locator::tsn(mac, 42);
1341 assert_eq!(loc.kind, LocatorKind::Tsn);
1342 assert_eq!(&loc.address[..6], &mac);
1343 assert_eq!(u16::from_be_bytes([loc.address[6], loc.address[7]]), 42);
1344 assert!(loc.kind.as_i32() < 0);
1346 assert_eq!(
1347 LocatorKind::from_i32(loc.kind.as_i32()).unwrap(),
1348 LocatorKind::Tsn
1349 );
1350 }
1351
1352 #[test]
1353 fn locator_udp_v6_constructor_keeps_full_address() {
1354 let addr: [u8; 16] = [
1355 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01,
1356 ];
1357 let l = Locator::udp_v6(addr, 1234);
1358 assert_eq!(l.kind, LocatorKind::UdpV6);
1359 assert_eq!(l.address, addr);
1360 assert_eq!(l.port, 1234);
1361 }
1362
1363 #[test]
1364 fn locator_udp_v6_roundtrip_le() {
1365 let l = Locator::udp_v6([1; 16], 9000);
1366 assert_eq!(Locator::from_bytes_le(l.to_bytes_le()).unwrap(), l);
1367 }
1368
1369 #[test]
1372 fn protocol_version_aliases_match_spec() {
1373 assert_eq!(
1374 ProtocolVersion::V1_0,
1375 ProtocolVersion { major: 1, minor: 0 }
1376 );
1377 assert_eq!(
1378 ProtocolVersion::V1_1,
1379 ProtocolVersion { major: 1, minor: 1 }
1380 );
1381 assert_eq!(
1382 ProtocolVersion::V2_0,
1383 ProtocolVersion { major: 2, minor: 0 }
1384 );
1385 assert_eq!(
1386 ProtocolVersion::V2_1,
1387 ProtocolVersion { major: 2, minor: 1 }
1388 );
1389 assert_eq!(
1390 ProtocolVersion::V2_2,
1391 ProtocolVersion { major: 2, minor: 2 }
1392 );
1393 assert_eq!(
1394 ProtocolVersion::V2_3,
1395 ProtocolVersion { major: 2, minor: 3 }
1396 );
1397 assert_eq!(
1398 ProtocolVersion::V2_4,
1399 ProtocolVersion { major: 2, minor: 4 }
1400 );
1401 assert_eq!(
1402 ProtocolVersion::V2_5,
1403 ProtocolVersion { major: 2, minor: 5 }
1404 );
1405 assert_eq!(ProtocolVersion::CURRENT, ProtocolVersion::V2_5);
1406 }
1407
1408 #[test]
1409 fn protocol_version_all_aliases_roundtrip() {
1410 for v in [
1411 ProtocolVersion::V1_0,
1412 ProtocolVersion::V1_1,
1413 ProtocolVersion::V2_0,
1414 ProtocolVersion::V2_1,
1415 ProtocolVersion::V2_2,
1416 ProtocolVersion::V2_3,
1417 ProtocolVersion::V2_4,
1418 ProtocolVersion::V2_5,
1419 ] {
1420 assert_eq!(ProtocolVersion::from_bytes(v.to_bytes()), v);
1421 }
1422 }
1423
1424 #[test]
1427 fn uextension4_roundtrip() {
1428 let u = UExtension4([0xDE, 0xAD, 0xBE, 0xEF]);
1429 assert_eq!(UExtension4::from_bytes(u.to_bytes()), u);
1430 }
1431
1432 #[test]
1433 fn uextension4_u32_be_roundtrip() {
1434 let u = UExtension4::from_u32_be(0x1122_3344);
1435 assert_eq!(u.to_u32_be(), 0x1122_3344);
1436 assert_eq!(u.0, [0x11, 0x22, 0x33, 0x44]);
1437 }
1438
1439 #[test]
1440 fn uextension4_default_is_zero() {
1441 assert_eq!(UExtension4::default().0, [0u8; 4]);
1442 assert_eq!(UExtension4::WIRE_SIZE, 4);
1443 }
1444
1445 #[test]
1448 fn wextension8_roundtrip() {
1449 let w = WExtension8([1, 2, 3, 4, 5, 6, 7, 8]);
1450 assert_eq!(WExtension8::from_bytes(w.to_bytes()), w);
1451 }
1452
1453 #[test]
1454 fn wextension8_u64_be_roundtrip() {
1455 let w = WExtension8::from_u64_be(0x1122_3344_5566_7788);
1456 assert_eq!(w.to_u64_be(), 0x1122_3344_5566_7788);
1457 assert_eq!(w.0, [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]);
1458 }
1459
1460 #[test]
1461 fn wextension8_default_is_zero() {
1462 assert_eq!(WExtension8::default().0, [0u8; 8]);
1463 assert_eq!(WExtension8::WIRE_SIZE, 8);
1464 }
1465
1466 #[test]
1469 fn spdp_builtin_participant_writer_layout() {
1470 let bytes = EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER.to_bytes();
1472 assert_eq!(bytes, [0x00, 0x01, 0x00, 0xC2]);
1473 }
1474
1475 #[test]
1476 fn spdp_builtin_participant_reader_layout() {
1477 let bytes = EntityId::SPDP_BUILTIN_PARTICIPANT_READER.to_bytes();
1479 assert_eq!(bytes, [0x00, 0x01, 0x00, 0xC7]);
1480 }
1481
1482 #[test]
1483 fn sedp_publications_writer_layout() {
1484 let bytes = EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER.to_bytes();
1486 assert_eq!(bytes, [0x00, 0x00, 0x03, 0xC2]);
1487 }
1488
1489 #[test]
1490 fn sedp_subscriptions_reader_layout() {
1491 let bytes = EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_READER.to_bytes();
1493 assert_eq!(bytes, [0x00, 0x00, 0x04, 0xC7]);
1494 }
1495
1496 #[test]
1499 fn spdp_default_multicast_is_239_255_0_1() {
1500 assert_eq!(SPDP_DEFAULT_MULTICAST_ADDRESS, [239, 255, 0, 1]);
1501 }
1502
1503 #[test]
1504 fn spdp_multicast_port_domain_0_is_7400() {
1505 assert_eq!(spdp_multicast_port(0), 7400);
1506 }
1507
1508 #[test]
1509 fn spdp_multicast_port_domain_1_is_7650() {
1510 assert_eq!(spdp_multicast_port(1), 7650);
1511 }
1512
1513 #[test]
1514 fn spdp_multicast_port_domain_5_is_8650() {
1515 assert_eq!(spdp_multicast_port(5), 8650);
1516 }
1517
1518 #[test]
1519 fn volatile_message_secure_entity_ids_match_spec_and_cyclone() {
1520 assert_eq!(
1526 EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_WRITER.to_bytes(),
1527 [0xff, 0x02, 0x02, 0xc3],
1528 "VolatileMessageSecure writer must be 0xff0202c3"
1529 );
1530 assert_eq!(
1531 EntityId::BUILTIN_PARTICIPANT_VOLATILE_MESSAGE_SECURE_READER.to_bytes(),
1532 [0xff, 0x02, 0x02, 0xc4],
1533 "VolatileMessageSecure reader must be 0xff0202c4"
1534 );
1535 }
1536}