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

let qos = DataWriterQos::default()
.data_representation(DataRepresentation::XCDR2);

// Or for compatibility with older implementations
let qos = DataWriterQos::default()
.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