1extern crate alloc;
45use alloc::vec::Vec;
46
47use crate::error::WireError;
48use crate::wire_types::GuidPrefix;
49
50pub const ENCAPSULATION_CDR_BE: [u8; 2] = [0x00, 0x00];
52pub const ENCAPSULATION_CDR_LE: [u8; 2] = [0x00, 0x01];
54pub const ENCAPSULATION_CDR2_BE: [u8; 2] = [0x00, 0x06];
56pub const ENCAPSULATION_CDR2_LE: [u8; 2] = [0x00, 0x07];
58
59pub const MAX_DATA_LEN: usize = 4096;
63
64pub const PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE: u32 = 0x0000_0000;
67
68pub const PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_BY_PARTICIPANT_LIVELINESS_UPDATE: u32 = 0x0000_0001;
72
73pub const PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE: u32 = 0x8000_0000;
78
79pub const PARTICIPANT_MESSAGE_DATA_KIND_ZERODDS_MANUAL_BY_TOPIC: u32 = 0x8000_0001;
86
87#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct ParticipantMessageData {
91 pub participant_guid: [u8; 16],
95 pub kind: u32,
97 pub data: Vec<u8>,
99}
100
101impl ParticipantMessageData {
102 #[must_use]
104 pub fn automatic(prefix: GuidPrefix) -> Self {
105 Self {
106 participant_guid: full_guid_bytes(prefix),
107 kind: PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE,
108 data: Vec::new(),
109 }
110 }
111
112 #[must_use]
114 pub fn manual_by_participant(prefix: GuidPrefix) -> Self {
115 Self {
116 participant_guid: full_guid_bytes(prefix),
117 kind: PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_BY_PARTICIPANT_LIVELINESS_UPDATE,
118 data: Vec::new(),
119 }
120 }
121
122 #[must_use]
124 pub fn manual_by_topic(prefix: GuidPrefix, topic_token: Vec<u8>) -> Self {
125 Self {
126 participant_guid: full_guid_bytes(prefix),
127 kind: PARTICIPANT_MESSAGE_DATA_KIND_ZERODDS_MANUAL_BY_TOPIC,
128 data: topic_token,
129 }
130 }
131
132 pub fn to_cdr(&self, little_endian: bool) -> Result<Vec<u8>, WireError> {
138 if self.data.len() > MAX_DATA_LEN {
139 return Err(WireError::ValueOutOfRange {
140 message: "ParticipantMessageData.data exceeds MAX_DATA_LEN",
141 });
142 }
143 let data_len_u32 =
144 u32::try_from(self.data.len()).map_err(|_| WireError::ValueOutOfRange {
145 message: "ParticipantMessageData.data length exceeds u32",
146 })?;
147 let mut out = Vec::with_capacity(4 + 16 + 4 + 4 + self.data.len());
148 if little_endian {
150 out.extend_from_slice(&ENCAPSULATION_CDR_LE);
151 } else {
152 out.extend_from_slice(&ENCAPSULATION_CDR_BE);
153 }
154 out.extend_from_slice(&[0, 0]); out.extend_from_slice(&self.participant_guid);
158 let kind_bytes = if little_endian {
160 self.kind.to_le_bytes()
161 } else {
162 self.kind.to_be_bytes()
163 };
164 out.extend_from_slice(&kind_bytes);
165 let len_bytes = if little_endian {
167 data_len_u32.to_le_bytes()
168 } else {
169 data_len_u32.to_be_bytes()
170 };
171 out.extend_from_slice(&len_bytes);
172 out.extend_from_slice(&self.data);
173 Ok(out)
174 }
175
176 pub fn from_cdr(bytes: &[u8]) -> Result<Self, WireError> {
189 if bytes.len() < 4 {
190 return Err(WireError::UnexpectedEof {
191 needed: 4,
192 offset: 0,
193 });
194 }
195 let little_endian = match (bytes[0], bytes[1]) {
196 (0x00, 0x00) | (0x00, 0x06) => false,
197 (0x00, 0x01) | (0x00, 0x07) => true,
198 (a, b) => {
199 return Err(WireError::UnsupportedEncapsulation { kind: [a, b] });
200 }
201 };
202 let body = &bytes[4..];
204 let (guid_bytes, after_guid_offset) = parse_guid(body)?;
211 if body.len() < after_guid_offset + 4 {
212 return Err(WireError::UnexpectedEof {
213 needed: after_guid_offset + 4,
214 offset: 4,
215 });
216 }
217 let kind_slice = &body[after_guid_offset..after_guid_offset + 4];
218 let mut kind_arr = [0u8; 4];
219 kind_arr.copy_from_slice(kind_slice);
220 let kind = if little_endian {
221 u32::from_le_bytes(kind_arr)
222 } else {
223 u32::from_be_bytes(kind_arr)
224 };
225 let len_offset = after_guid_offset + 4;
226 if body.len() < len_offset + 4 {
227 return Err(WireError::UnexpectedEof {
228 needed: len_offset + 4,
229 offset: 4,
230 });
231 }
232 let mut len_arr = [0u8; 4];
233 len_arr.copy_from_slice(&body[len_offset..len_offset + 4]);
234 let data_len = if little_endian {
235 u32::from_le_bytes(len_arr)
236 } else {
237 u32::from_be_bytes(len_arr)
238 } as usize;
239 if data_len > MAX_DATA_LEN {
240 return Err(WireError::ValueOutOfRange {
241 message: "ParticipantMessageData.data exceeds MAX_DATA_LEN",
242 });
243 }
244 let data_offset = len_offset + 4;
245 if body.len() < data_offset + data_len {
246 return Err(WireError::UnexpectedEof {
247 needed: data_offset + data_len,
248 offset: 4,
249 });
250 }
251 let data = body[data_offset..data_offset + data_len].to_vec();
252 Ok(Self {
253 participant_guid: guid_bytes,
254 kind,
255 data,
256 })
257 }
258
259 #[must_use]
261 pub fn prefix(&self) -> GuidPrefix {
262 let mut p = [0u8; 12];
263 p.copy_from_slice(&self.participant_guid[..12]);
264 GuidPrefix::from_bytes(p)
265 }
266
267 #[must_use]
269 pub fn is_vendor_kind(&self) -> bool {
270 self.kind >= PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE
271 }
272}
273
274fn full_guid_bytes(prefix: GuidPrefix) -> [u8; 16] {
275 let mut g = [0u8; 16];
276 g[..12].copy_from_slice(&prefix.to_bytes());
277 g[12] = 0;
279 g[13] = 0;
280 g[14] = 1;
281 g[15] = 0xC1;
282 g
283}
284
285fn parse_guid(body: &[u8]) -> Result<([u8; 16], usize), WireError> {
288 if body.len() >= 24 {
290 let mut g = [0u8; 16];
291 g.copy_from_slice(&body[..16]);
292 return Ok((g, 16));
293 }
294 if body.len() >= 20 {
296 let mut g = [0u8; 16];
297 g[..12].copy_from_slice(&body[..12]);
298 g[14] = 1;
300 g[15] = 0xC1;
301 return Ok((g, 12));
302 }
303 Err(WireError::UnexpectedEof {
304 needed: 24,
305 offset: 4,
306 })
307}
308
309#[cfg(test)]
310mod tests {
311 #![allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
312 use super::*;
313 use alloc::vec;
314
315 fn sample_prefix() -> GuidPrefix {
316 GuidPrefix::from_bytes([0xA, 0xB, 0xC, 0xD, 1, 2, 3, 4, 5, 6, 7, 8])
317 }
318
319 #[test]
320 fn participant_message_data_automatic_default_data_empty() {
321 let m = ParticipantMessageData::automatic(sample_prefix());
322 assert_eq!(
323 m.kind,
324 PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE
325 );
326 assert!(m.data.is_empty());
327 assert_eq!(m.prefix(), sample_prefix());
328 }
329
330 #[test]
331 fn participant_message_data_kind_constants_match_spec() {
332 assert_eq!(
335 PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE,
336 0x0000_0000
337 );
338 assert_eq!(
339 PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_BY_PARTICIPANT_LIVELINESS_UPDATE,
340 0x0000_0001
341 );
342 assert_eq!(PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE, 0x8000_0000);
343 assert_eq!(
348 PARTICIPANT_MESSAGE_DATA_KIND_ZERODDS_MANUAL_BY_TOPIC
349 & PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE,
350 PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE
351 );
352 }
353
354 #[test]
355 fn participant_message_data_roundtrip_le() {
356 let m = ParticipantMessageData::manual_by_participant(sample_prefix());
357 let bytes = m.to_cdr(true).unwrap();
358 assert_eq!(&bytes[..4], &[0x00, 0x01, 0x00, 0x00]);
360 let decoded = ParticipantMessageData::from_cdr(&bytes).unwrap();
361 assert_eq!(decoded, m);
362 }
363
364 #[test]
365 fn participant_message_data_roundtrip_be() {
366 let m = ParticipantMessageData::automatic(sample_prefix());
367 let bytes = m.to_cdr(false).unwrap();
368 assert_eq!(&bytes[..4], &[0x00, 0x00, 0x00, 0x00]);
369 let decoded = ParticipantMessageData::from_cdr(&bytes).unwrap();
370 assert_eq!(decoded, m);
371 }
372
373 #[test]
374 fn participant_message_data_roundtrip_with_topic_token() {
375 let m =
376 ParticipantMessageData::manual_by_topic(sample_prefix(), vec![0xDE, 0xAD, 0xBE, 0xEF]);
377 assert!(m.is_vendor_kind());
378 let bytes = m.to_cdr(true).unwrap();
379 let decoded = ParticipantMessageData::from_cdr(&bytes).unwrap();
380 assert_eq!(decoded.data, vec![0xDE, 0xAD, 0xBE, 0xEF]);
381 assert_eq!(
382 decoded.kind,
383 PARTICIPANT_MESSAGE_DATA_KIND_ZERODDS_MANUAL_BY_TOPIC
384 );
385 }
386
387 #[test]
388 fn participant_message_data_accepts_xcdr2_le_encapsulation() {
389 let m = ParticipantMessageData::automatic(sample_prefix());
393 let mut bytes = m.to_cdr(true).unwrap();
394 bytes[0] = 0x00;
395 bytes[1] = 0x07; let decoded = ParticipantMessageData::from_cdr(&bytes).unwrap();
397 assert_eq!(decoded, m);
398 }
399
400 #[test]
401 fn participant_message_data_accepts_xcdr2_be_encapsulation() {
402 let m = ParticipantMessageData::automatic(sample_prefix());
403 let mut bytes = m.to_cdr(false).unwrap();
404 bytes[0] = 0x00;
405 bytes[1] = 0x06; let decoded = ParticipantMessageData::from_cdr(&bytes).unwrap();
407 assert_eq!(decoded, m);
408 }
409
410 #[test]
411 fn participant_message_data_rejects_unknown_encapsulation() {
412 let mut bytes = vec![0x99, 0x99, 0, 0];
413 bytes.extend_from_slice(&[0u8; 24]);
414 let res = ParticipantMessageData::from_cdr(&bytes);
415 assert!(matches!(
416 res,
417 Err(WireError::UnsupportedEncapsulation { kind: [0x99, 0x99] })
418 ));
419 }
420
421 #[test]
422 fn participant_message_data_rejects_overlong_data() {
423 let mut bytes = vec![0x00, 0x01, 0x00, 0x00];
426 bytes.extend_from_slice(&[0u8; 16]);
427 bytes.extend_from_slice(&0u32.to_le_bytes()); let too_big = (MAX_DATA_LEN as u32) + 1;
429 bytes.extend_from_slice(&too_big.to_le_bytes());
430 let res = ParticipantMessageData::from_cdr(&bytes);
432 assert!(matches!(res, Err(WireError::ValueOutOfRange { .. })));
433 }
434
435 #[test]
436 fn participant_message_data_encoder_caps_data_length() {
437 let mut m = ParticipantMessageData::automatic(sample_prefix());
438 m.data = vec![0u8; MAX_DATA_LEN + 1];
439 let res = m.to_cdr(true);
440 assert!(matches!(res, Err(WireError::ValueOutOfRange { .. })));
441 }
442
443 #[test]
444 fn participant_message_data_too_short_encapsulation() {
445 let bytes = [0x00];
446 let res = ParticipantMessageData::from_cdr(&bytes);
447 assert!(matches!(res, Err(WireError::UnexpectedEof { .. })));
448 }
449
450 #[test]
451 fn participant_message_data_too_short_body() {
452 let bytes = vec![0x00, 0x01, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0];
454 let res = ParticipantMessageData::from_cdr(&bytes);
455 assert!(matches!(res, Err(WireError::UnexpectedEof { .. })));
456 }
457
458 #[test]
459 fn participant_message_data_truncated_data_section() {
460 let mut bytes = vec![0x00, 0x01, 0x00, 0x00];
462 bytes.extend_from_slice(&[0u8; 16]);
463 bytes.extend_from_slice(&0u32.to_le_bytes());
464 bytes.extend_from_slice(&8u32.to_le_bytes());
465 bytes.extend_from_slice(&[1, 2, 3, 4]);
466 let res = ParticipantMessageData::from_cdr(&bytes);
467 assert!(matches!(res, Err(WireError::UnexpectedEof { .. })));
468 }
469
470 #[test]
471 fn participant_message_data_le_be_bytes_differ_for_kind() {
472 let mut m = ParticipantMessageData::automatic(sample_prefix());
474 m.kind = 0x0102_0304;
475 let le = m.to_cdr(true).unwrap();
476 let be = m.to_cdr(false).unwrap();
477 assert_ne!(le, be);
478 assert_eq!(ParticipantMessageData::from_cdr(&le).unwrap(), m);
480 assert_eq!(ParticipantMessageData::from_cdr(&be).unwrap(), m);
481 }
482
483 #[test]
484 fn participant_message_data_accepts_12_byte_prefix_only_encoding() {
485 let mut bytes = vec![0x00, 0x01, 0x00, 0x00];
489 let prefix = sample_prefix().to_bytes();
490 bytes.extend_from_slice(&prefix); bytes.extend_from_slice(&0u32.to_le_bytes()); bytes.extend_from_slice(&0u32.to_le_bytes()); let decoded = ParticipantMessageData::from_cdr(&bytes).unwrap();
494 assert_eq!(decoded.prefix(), sample_prefix());
495 assert_eq!(&decoded.participant_guid[12..], &[0, 0, 1, 0xC1]);
497 }
498}