Skip to main content

CDR2 Serialization

HDDS uses CDR2 (Common Data Representation version 2) for serializing data, ensuring interoperability with all DDS implementations.

Overview​

CDR2 is the standard serialization format for DDS/RTPS, providing:

  • Binary encoding - Compact and fast
  • Platform independence - Cross-architecture compatibility
  • Type safety - Preserves IDL type information
  • Interoperability - Works with all DDS vendors

Encoding Formats​

HDDS supports multiple CDR encodings:

FormatIDDescription
CDR1 (Plain)0x0000Original CDR, big-endian default
CDR2 (Plain)0x0001Little-endian default
PL_CDR10x0002Parameter list, mutable types
PL_CDR20x0003Parameter list, little-endian
XCDR20x0006Extended CDR2 for XTypes
D_CDR20x0007Delimited CDR2

Default: XCDR2 (0x0006)

Wire Format​

Encapsulation Header​

Every serialized payload starts with a 4-byte header:

Byte 0-1: Encapsulation ID (e.g., 0x0006 for XCDR2)
Byte 2: Options (flags)
Byte 3: Reserved (0x00)
// Encapsulation header structure
struct EncapsulationHeader {
id: u16, // Format identifier
options: u8, // Bit 0: endianness (0=BE, 1=LE)
reserved: u8, // Always 0
}

Primitive Types​

IDL TypeWire SizeAlignment
boolean1 byte1
octet/int8/uint81 byte1
int16/uint162 bytes2
int32/uint324 bytes4
int64/uint648 bytes8
float4 bytes4
double8 bytes8
char1 byte1
wchar2 bytes2

Alignment Rules​

Data is aligned to natural boundaries:

Offset:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
┌──┬──┬──┬──┬──────────┬──────────────────────┐
│u8│ │u16 │ u32 │ u64 │
└──┴──┴──┴──┴──────────┴──────────────────────┘
↑ ↑ ↑ ↑
pad(1) align(2) align(4) align(8)

String Encoding​

┌────────────┬────────────────────────────┐
│ Length (4) │ UTF-8 data + NUL terminator│
└────────────┴────────────────────────────┘

Example: "Hello" (5 chars)

00 00 00 06   48 65 6C 6C 6F 00
└─ length ─┘ └─ "Hello\0" ───┘

Sequence Encoding​

┌────────────┬──────────────────────────────┐
│ Count (4) │ Elements (each aligned) │
└────────────┴──────────────────────────────┘

Example: sequence<uint32> with [1, 2, 3]

00 00 00 03   00 00 00 01   00 00 00 02   00 00 00 03
└─ count ─┘ └── 1 ────┘ └── 2 ────┘ └── 3 ────┘

Array Encoding​

Fixed-size arrays have no length prefix:

float values[4];  // IDL

// Wire format: 16 bytes (4 x float32)
00 00 80 3F 00 00 00 40 00 00 40 40 00 00 80 40
└── 1.0 ──┘ └── 2.0 ──┘ └── 3.0 ──┘ └── 4.0 ──┘

Struct Encoding​

Members are serialized in declaration order with alignment:

struct SensorData {
uint32 sensor_id; // Offset 0, align 4
float temperature; // Offset 4, align 4
uint64 timestamp; // Offset 8, align 8
}; // Total: 16 bytes

Wire format:

00 00 00 01   42 28 00 00   00 00 00 00 12 34 56 78
└─ sensor ─┘ └─ temp ──┘ └────── timestamp ─────┘

XCDR2 Extensions​

XCDR2 adds support for extensible types:

Delimited Headers (DHEADER)​

For mutable/appendable types:

┌──────────────┬────────────────────────────┐
│ Size (4) │ Serialized members │
└──────────────┴────────────────────────────┘

Member Headers (EMHEADER)​

For optional and mutable members:

┌──────────────────────────────┬─────────────────┐
│ Member ID + Flags (4) │ Member data │
└──────────────────────────────┴─────────────────┘

Bits 0-27: Member ID
Bits 28-29: Length code (0=1B, 1=2B, 2=4B, 3=8B/NEXTINT)
Bit 30: Must understand
Bit 31: Extended header follows

Optional Fields​

@optional float temperature;

// Present: EMHEADER + value
// Absent: No bytes (or sentinel in PL_CDR)

Configuration​

Setting Data Representation​

use hdds::QoS;

let qos = QoS::reliable().data_representation(DataRepresentation::XCDR2);

// Or for compatibility with older implementations
let qos = QoS::reliable().data_representation(DataRepresentation::CDR2);

Endianness​

HDDS uses little-endian by default (native on x86/ARM):

// Force big-endian for legacy systems
let config = SerializationConfig::default()
.byte_order(ByteOrder::BigEndian);

Performance​

Serialization Speed​

PayloadSerializeDeserialize
64 B struct50 ns40 ns
256 B struct120 ns100 ns
1 KB struct400 ns350 ns
4 KB struct1.5 us1.3 us

Size Overhead​

ContentRaw SizeCDR SizeOverhead
4 primitives20 B24 B20%
Struct + string50 B58 B16%
Large array4 KB4.004 KB0.1%

Manual Serialization​

For advanced use cases:

use hdds::serialization::{CdrSerializer, CdrDeserializer};

// Serialize
let mut buf = Vec::new();
let mut ser = CdrSerializer::new(&mut buf);
ser.serialize_u32(sensor_id)?;
ser.serialize_f32(temperature)?;
ser.serialize_string("status")?;

// Deserialize
let mut de = CdrDeserializer::new(&buf);
let sensor_id = de.deserialize_u32()?;
let temperature = de.deserialize_f32()?;
let status = de.deserialize_string()?;

Troubleshooting​

Alignment Issues​

Error: Deserialization failed - unexpected alignment

Check that IDL types match on both sides.

Endianness Mismatch​

Error: Invalid data (endianness?)

Verify encapsulation header byte order matches data.

Type Mismatch​

Error: Type hash mismatch

Regenerate types from the same IDL on both sides.

Next Steps​