How Copy Type Serialization Works
Cerulion Core automatically implementsSerializableMessage for any Copy type. This means you can use simple structs without writing any serialization code.
Blanket Implementation
TheSerializableMessage trait is automatically implemented for all Copy types:
This means you can use simple structs like
SensorData without writing any serialization code. Just make sure your struct implements Copy and has #[repr(C)] layout.Simple Example
Here’s a simple struct that works automatically:The
#[repr(C)] attribute ensures the struct has a C-compatible memory layout, which is required for zero-copy serialization. This also enables future cross-language compatibility.How It Works
Serialization Flow
- For Local Communication: Data is sent as raw bytes using zero-copy shared memory (iceoryx2)
- For Network Communication: Data is serialized to bytes and sent over Zenoh
Memory Layout
With#[repr(C)], the memory layout is guaranteed to match C struct layout:
Example Memory Layout:
Memory Layout Table:
| Field | Type | Size | Offset | Byte Range |
|---|---|---|---|---|
timestamp | u64 | 8 bytes | 0 | 0-7 |
temperature | f32 | 4 bytes | 8 | 8-11 |
pressure | f32 | 4 bytes | 12 | 12-15 |
- Fields are stored contiguously in memory (no padding with
#[repr(C)]) - Total size: 16 bytes (8 + 4 + 4)
- Memory layout matches C struct layout exactly
- Each field starts immediately after the previous one
The
#[repr(C)] attribute ensures the struct has the same memory layout as a C struct. This is essential for:- Zero-copy serialization (local transport)
- Cross-language compatibility (future Python/C++ support)
- Predictable binary format
Checking Type Size
You can check the size of your message type:When to Use Copy Types
Copy types are ideal for:- ✅ Simple, fixed-size data structures - Sensor readings, coordinates, status flags
- ✅ High-performance requirements - Zero-copy local transport, minimal serialization overhead
- ✅ Same-language communication - When all components are in Rust
- ✅ Predictable message sizes - Fixed-size arrays and primitives
- ⚠️ Cross-language communication - Need Python/C++ compatibility
- ⚠️ Schema evolution - Need to add/remove fields over time
- ⚠️ Complex nested structures - Deeply nested or variable-size data
- ⚠️ Guaranteed compatibility - Need versioned message formats
Relocatable Message Support
Thefrom_bytes() implementation automatically handles relocatable-wrapped messages:
- Checks if bytes are relocatable-wrapped
- If wrapped, extracts the
payloadfield - If not wrapped, uses bytes directly
- Deserializes using
raw::bytes_to_struct()
This automatic handling provides backward compatibility. Your code doesn’t need to know whether messages are wrapped or not -
from_bytes() handles both cases transparently.