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#![forbid(unsafe_code)]
29#![no_std]
30
31#[cfg(feature = "std")]
32extern crate std;
33
34#[cfg(feature = "alloc")]
35extern crate alloc;
36
37pub mod cdr;
38pub mod error;
39pub mod format;
40pub mod primitives;
41pub mod schema;
42pub mod size;
43pub mod traits;
44pub mod walk;
45
46#[cfg(test)]
47mod compat_tests;
48
49pub use cdr::{
50 CdrReader, CdrWriter, DHeaderMark, DHeaderScope, EncodingVersion, LeDecode, LeSliceView,
51};
52pub use error::{DeserError, SerError};
53pub use schema::{Field, FieldType, Message, NestedType};
54pub use traits::{Deserialize, DeserializeView, Serialize};
55pub use walk::{
56 SchemaError, SchemaSerializer, SchemaSink, SchemaSource, decode_to_cdr, encode_from_cdr,
57};
58
59/// Length of the CDR encapsulation header (representation identifier + options).
60pub const CDR_HEADER_LEN: usize = 4;
61
62/// CDR encapsulation header for little-endian encoding
63pub const CDR_LE_HEADER: [u8; CDR_HEADER_LEN] = [0x00, 0x01, 0x00, 0x00];
64
65/// CDR encapsulation header for big-endian encoding
66pub const CDR_BE_HEADER: [u8; CDR_HEADER_LEN] = [0x00, 0x00, 0x00, 0x00];
67
68/// XCDR2 DELIMITED-CDR little-endian encapsulation header (`D_CDR2_LE`, repr id
69/// `0x0009`). The representation for APPENDABLE types under XCDR2 (phase-303 W2 /
70/// RFC-0055 / #0267): every appendable struct — top-level and each nested one —
71/// is preceded by a 4-byte DHEADER carrying its member-block size.
72pub const CDR2_DELIMITED_LE_HEADER: [u8; CDR_HEADER_LEN] = [0x00, 0x09, 0x00, 0x00];
73
74/// Write the little-endian CDR header into the first `CDR_HEADER_LEN` bytes of `dst`.
75///
76/// Returns the remaining payload slice `&mut dst[CDR_HEADER_LEN..]` on success,
77/// or `None` if `dst` is shorter than the header.
78#[inline]
79pub fn write_cdr_le_header(dst: &mut [u8]) -> Option<&mut [u8]> {
80 if dst.len() < CDR_HEADER_LEN {
81 return None;
82 }
83 dst[..CDR_HEADER_LEN].copy_from_slice(&CDR_LE_HEADER);
84 Some(&mut dst[CDR_HEADER_LEN..])
85}
86
87/// Strip the CDR encapsulation header from `src`, returning the payload slice.
88///
89/// Does not verify header contents — callers that need to validate the
90/// representation identifier should do so separately. Returns `src` unchanged
91/// if it is shorter than the header (so downstream parsers fail with a clearer
92/// error than an out-of-bounds slice).
93#[inline]
94pub fn strip_cdr_header(src: &[u8]) -> &[u8] {
95 if src.len() >= CDR_HEADER_LEN {
96 &src[CDR_HEADER_LEN..]
97 } else {
98 src
99 }
100}