Skip to main content

nros_serdes/
lib.rs

1//! CDR serialization/deserialization for nros.
2//!
3//! Implements OMG Common Data Representation (CDR) encoding compatible with
4//! ROS 2. All types use little-endian byte order with natural alignment.
5//!
6//! # Examples
7//!
8//! ```
9//! use nros_serdes::{CdrReader, CdrWriter, DeserError, Deserialize, SerError, Serialize};
10//!
11//! // Serialize a u32 into a CDR buffer
12//! let mut buf = [0u8; 64];
13//! let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
14//! 42u32.serialize(&mut writer).unwrap();
15//! let len = writer.position();
16//!
17//! // Deserialize it back
18//! let mut reader = CdrReader::new_with_header(&buf[..len]).unwrap();
19//! let value = u32::deserialize(&mut reader).unwrap();
20//! assert_eq!(value, 42);
21//! ```
22//!
23//! # Features
24//!
25//! - `std` — Enable standard library support
26//! - `alloc` — Enable heap allocation (`String`, `Vec<T>`)
27
28#![no_std]
29
30#[cfg(feature = "std")]
31extern crate std;
32
33#[cfg(feature = "alloc")]
34extern crate alloc;
35
36pub mod cdr;
37pub mod error;
38pub mod format;
39pub mod primitives;
40pub mod schema;
41pub mod size;
42pub mod traits;
43pub mod walk;
44
45#[cfg(test)]
46mod compat_tests;
47
48pub use cdr::{
49    CdrReader, CdrWriter, DHeaderMark, DHeaderScope, EncodingVersion, LeDecode, LeSliceView,
50};
51pub use error::{DeserError, SerError};
52pub use schema::{Field, FieldType, Message, NestedType};
53pub use traits::{Deserialize, DeserializeView, Serialize};
54pub use walk::{
55    SchemaError, SchemaSerializer, SchemaSink, SchemaSource, decode_to_cdr, encode_from_cdr,
56};
57
58/// Length of the CDR encapsulation header (representation identifier + options).
59pub const CDR_HEADER_LEN: usize = 4;
60
61/// CDR encapsulation header for little-endian encoding
62pub const CDR_LE_HEADER: [u8; CDR_HEADER_LEN] = [0x00, 0x01, 0x00, 0x00];
63
64/// CDR encapsulation header for big-endian encoding
65pub const CDR_BE_HEADER: [u8; CDR_HEADER_LEN] = [0x00, 0x00, 0x00, 0x00];
66
67/// XCDR2 DELIMITED-CDR little-endian encapsulation header (`D_CDR2_LE`, repr id
68/// `0x0009`). The representation for APPENDABLE types under XCDR2 (phase-303 W2 /
69/// RFC-0055 / #0267): every appendable struct — top-level and each nested one —
70/// is preceded by a 4-byte DHEADER carrying its member-block size.
71pub const CDR2_DELIMITED_LE_HEADER: [u8; CDR_HEADER_LEN] = [0x00, 0x09, 0x00, 0x00];
72
73/// Write the little-endian CDR header into the first `CDR_HEADER_LEN` bytes of `dst`.
74///
75/// Returns the remaining payload slice `&mut dst[CDR_HEADER_LEN..]` on success,
76/// or `None` if `dst` is shorter than the header.
77#[inline]
78pub fn write_cdr_le_header(dst: &mut [u8]) -> Option<&mut [u8]> {
79    if dst.len() < CDR_HEADER_LEN {
80        return None;
81    }
82    dst[..CDR_HEADER_LEN].copy_from_slice(&CDR_LE_HEADER);
83    Some(&mut dst[CDR_HEADER_LEN..])
84}
85
86/// Strip the CDR encapsulation header from `src`, returning the payload slice.
87///
88/// Does not verify header contents — callers that need to validate the
89/// representation identifier should do so separately. Returns `src` unchanged
90/// if it is shorter than the header (so downstream parsers fail with a clearer
91/// error than an out-of-bounds slice).
92#[inline]
93pub fn strip_cdr_header(src: &[u8]) -> &[u8] {
94    if src.len() >= CDR_HEADER_LEN {
95        &src[CDR_HEADER_LEN..]
96    } else {
97        src
98    }
99}