1extern crate alloc;
46use alloc::vec::Vec;
47
48use crate::error::WireError;
49use crate::wire_types::GuidPrefix;
50
51pub const ENCAPSULATION_CDR_BE: [u8; 2] = [0x00, 0x00];
53pub const ENCAPSULATION_CDR_LE: [u8; 2] = [0x00, 0x01];
55pub const ENCAPSULATION_CDR2_BE: [u8; 2] = [0x00, 0x06];
57pub const ENCAPSULATION_CDR2_LE: [u8; 2] = [0x00, 0x07];
59
60pub const MAX_DATA_LEN: usize = 4096;
64
65pub const PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE: u32 = 0x0000_0000;
68
69pub const PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_BY_PARTICIPANT_LIVELINESS_UPDATE: u32 = 0x0000_0001;
73
74pub const PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE: u32 = 0x8000_0000;
79
80pub const PARTICIPANT_MESSAGE_DATA_KIND_ZERODDS_MANUAL_BY_TOPIC: u32 = 0x8000_0001;
87
88#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct ParticipantMessageData {
92 pub participant_guid: [u8; 16],
96 pub kind: u32,
98 pub data: Vec<u8>,
100}
101
102impl ParticipantMessageData {
103 #[must_use]
105 pub fn automatic(prefix: GuidPrefix) -> Self {
106 Self {
107 participant_guid: full_guid_bytes(prefix),
108 kind: PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE,
109 data: Vec::new(),
110 }
111 }
112
113 #[must_use]
115 pub fn manual_by_participant(prefix: GuidPrefix) -> Self {
116 Self {
117 participant_guid: full_guid_bytes(prefix),
118 kind: PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_BY_PARTICIPANT_LIVELINESS_UPDATE,
119 data: Vec::new(),
120 }
121 }
122
123 #[must_use]
125 pub fn manual_by_topic(prefix: GuidPrefix, topic_token: Vec<u8>) -> Self {
126 Self {
127 participant_guid: full_guid_bytes(prefix),
128 kind: PARTICIPANT_MESSAGE_DATA_KIND_ZERODDS_MANUAL_BY_TOPIC,
129 data: topic_token,
130 }
131 }
132
133 pub fn to_cdr(&self, little_endian: bool) -> Result<Vec<u8>, WireError> {
139 if self.data.len() > MAX_DATA_LEN {
140 return Err(WireError::ValueOutOfRange {
141 message: "ParticipantMessageData.data exceeds MAX_DATA_LEN",
142 });
143 }
144 let data_len_u32 =
145 u32::try_from(self.data.len()).map_err(|_| WireError::ValueOutOfRange {
146 message: "ParticipantMessageData.data length exceeds u32",
147 })?;
148 let mut out = Vec::with_capacity(4 + 16 + 4 + 4 + self.data.len());
149 if little_endian {
151 out.extend_from_slice(&ENCAPSULATION_CDR_LE);
152 } else {
153 out.extend_from_slice(&ENCAPSULATION_CDR_BE);
154 }
155 out.extend_from_slice(&[0, 0]); out.extend_from_slice(&self.participant_guid);
159 let kind_bytes = if little_endian {
161 self.kind.to_le_bytes()
162 } else {
163 self.kind.to_be_bytes()
164 };
165 out.extend_from_slice(&kind_bytes);
166 let len_bytes = if little_endian {
168 data_len_u32.to_le_bytes()
169 } else {
170 data_len_u32.to_be_bytes()
171 };
172 out.extend_from_slice(&len_bytes);
173 out.extend_from_slice(&self.data);
174 Ok(out)
175 }
176
177 pub fn from_cdr(bytes: &[u8]) -> Result<Self, WireError> {
190 if bytes.len() < 4 {
191 return Err(WireError::UnexpectedEof {
192 needed: 4,
193 offset: 0,
194 });
195 }
196 let little_endian = match (bytes[0], bytes[1]) {
197 (0x00, 0x00) | (0x00, 0x06) => false,
198 (0x00, 0x01) | (0x00, 0x07) => true,
199 (a, b) => {
200 return Err(WireError::UnsupportedEncapsulation { kind: [a, b] });
201 }
202 };
203 let body = &bytes[4..];
205 let (guid_bytes, after_guid_offset) = parse_guid(body)?;
212 if body.len() < after_guid_offset + 4 {
213 return Err(WireError::UnexpectedEof {
214 needed: after_guid_offset + 4,
215 offset: 4,
216 });
217 }
218 let kind_slice = &body[after_guid_offset..after_guid_offset + 4];
219 let mut kind_arr = [0u8; 4];
220 kind_arr.copy_from_slice(kind_slice);
221 let kind = if little_endian {
222 u32::from_le_bytes(kind_arr)
223 } else {
224 u32::from_be_bytes(kind_arr)
225 };
226 let len_offset = after_guid_offset + 4;
227 if body.len() < len_offset + 4 {
228 return Err(WireError::UnexpectedEof {
229 needed: len_offset + 4,
230 offset: 4,
231 });
232 }
233 let mut len_arr = [0u8; 4];
234 len_arr.copy_from_slice(&body[len_offset..len_offset + 4]);
235 let data_len = if little_endian {
236 u32::from_le_bytes(len_arr)
237 } else {
238 u32::from_be_bytes(len_arr)
239 } as usize;
240 if data_len > MAX_DATA_LEN {
241 return Err(WireError::ValueOutOfRange {
242 message: "ParticipantMessageData.data exceeds MAX_DATA_LEN",
243 });
244 }
245 let data_offset = len_offset + 4;
246 if body.len() < data_offset + data_len {
247 return Err(WireError::UnexpectedEof {
248 needed: data_offset + data_len,
249 offset: 4,
250 });
251 }
252 let data = body[data_offset..data_offset + data_len].to_vec();
253 Ok(Self {
254 participant_guid: guid_bytes,
255 kind,
256 data,
257 })
258 }
259
260 #[must_use]
262 pub fn prefix(&self) -> GuidPrefix {
263 let mut p = [0u8; 12];
264 p.copy_from_slice(&self.participant_guid[..12]);
265 GuidPrefix::from_bytes(p)
266 }
267
268 #[must_use]
270 pub fn is_vendor_kind(&self) -> bool {
271 self.kind >= PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE
272 }
273}
274
275fn full_guid_bytes(prefix: GuidPrefix) -> [u8; 16] {
276 let mut g = [0u8; 16];
277 g[..12].copy_from_slice(&prefix.to_bytes());
278 g[12] = 0;
280 g[13] = 0;
281 g[14] = 1;
282 g[15] = 0xC1;
283 g
284}
285
286fn parse_guid(body: &[u8]) -> Result<([u8; 16], usize), WireError> {
289 if body.len() >= 24 {
291 let mut g = [0u8; 16];
292 g.copy_from_slice(&body[..16]);
293 return Ok((g, 16));
294 }
295 if body.len() >= 20 {
297 let mut g = [0u8; 16];
298 g[..12].copy_from_slice(&body[..12]);
299 g[14] = 1;
301 g[15] = 0xC1;
302 return Ok((g, 12));
303 }
304 Err(WireError::UnexpectedEof {
305 needed: 24,
306 offset: 4,
307 })
308}
309
310#[cfg(test)]
311mod tests {
312 #![allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
313 use super::*;
314 use alloc::vec;
315
316 fn sample_prefix() -> GuidPrefix {
317 GuidPrefix::from_bytes([0xA, 0xB, 0xC, 0xD, 1, 2, 3, 4, 5, 6, 7, 8])
318 }
319
320 #[test]
321 fn participant_message_data_automatic_default_data_empty() {
322 let m = ParticipantMessageData::automatic(sample_prefix());
323 assert_eq!(
324 m.kind,
325 PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE
326 );
327 assert!(m.data.is_empty());
328 assert_eq!(m.prefix(), sample_prefix());
329 }
330
331 #[test]
332 fn participant_message_data_kind_constants_match_spec() {
333 assert_eq!(
336 PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE,
337 0x0000_0000
338 );
339 assert_eq!(
340 PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_BY_PARTICIPANT_LIVELINESS_UPDATE,
341 0x0000_0001
342 );
343 assert_eq!(PARTICIPANT_MESSAGE_DATA_KIND_VENDOR_BASE, 0x8000_0000);
344 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}