Skip to main content

Complete Runnable Example

Copy and run this example to see serialization in action.
use cerulion_core::prelude::*;
use std::thread;
use std::time::Duration;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
struct SensorData {
    temperature: f32,
    pressure: f32,
    timestamp: u64,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let manager = TopicManager::create()?;

    // Create subscriber
    let _subscriber = manager.register_subscriber("sensors", None)?;

    // Create publisher
    let _publisher = manager.register_publisher("sensors", false, false)?;
    thread::sleep(Duration::from_millis(100));

    // Send a message - serialization happens automatically
    let data = SensorData {
        temperature: 23.5,
        pressure: 1013.25,
        timestamp: 1234567890,
    };
    manager.send_message("sensors", &data)?;
    println!("Sent: temp={}°C, pressure={}hPa", data.temperature, data.pressure);

    // Receive and deserialize - from_bytes() handles relocatable messages automatically
    thread::sleep(Duration::from_millis(50));
    match manager.pull("sensors") {
        Ok(Some(bytes)) => {
            match SensorData::from_bytes(&bytes) {
                Ok(received) => {
                    println!("Received: temp={}°C, pressure={}hPa", 
                        received.temperature, received.pressure);
                }
                Err(e) => eprintln!("Deserialization error: {}", e),
            }
        }
        Ok(None) => println!("No message available"),
        Err(e) => eprintln!("Error: {}", e),
    }

    Ok(())
}

Walkthrough

1. Define Your Message Type

#[derive(Copy, Clone, Debug)]
#[repr(C)]
struct SensorData {
    temperature: f32,
    pressure: f32,
    timestamp: u64,
}
Define a struct with Copy and #[repr(C)]. The #[repr(C)] attribute ensures C-compatible memory layout, which is required for serialization.
The #[repr(C)] attribute ensures the struct has a C-compatible memory layout, which is required for zero-copy serialization and enables cross-language compatibility.

2. Send Messages

let data = SensorData {
    temperature: 23.5,
    pressure: 1013.25,
    timestamp: 1234567890,
};
manager.send_message("sensors", &data)?;
Messages are sent by reference. The send_message() method automatically serializes the struct using its to_bytes() implementation. No manual serialization code is needed.
For Copy types, serialization uses raw byte conversion via the raw::struct_to_bytes() function. The struct is converted to bytes using its #[repr(C)] memory layout.

3. Receive and Deserialize

match manager.pull("sensors") {
    Ok(Some(bytes)) => {
        match SensorData::from_bytes(&bytes) {
            Ok(received) => println!("Received: {:?}", received),
            Err(e) => eprintln!("Error: {}", e),
        }
    }
    Ok(None) => {}
    Err(e) => eprintln!("Error: {}", e),
}
The from_bytes() method automatically:
  • Handles relocatable-wrapped messages (extracts payload if present)
  • Validates byte length matches the type size
  • Deserializes using raw::bytes_to_struct()
from_bytes() automatically unwraps relocatable messages. If the bytes are wrapped in a relocatable message format, it extracts the payload field. If not, it uses the bytes directly. This provides backward compatibility with both wrapped and unwrapped messages.

4. How Serialization Works

For Local Communication:
  • Data is sent as raw bytes using zero-copy shared memory (iceoryx2)
  • No serialization occurs - direct memory copy
  • Fastest possible performance
For Network Communication:
  • Struct is serialized to bytes using #[repr(C)] layout
  • Bytes are sent over Zenoh network
  • Deserialization happens on the receiving end

What to Try Next

  • Use different message types - Try arrays, nested structs, or fixed-size strings
  • Check message size - Use std::mem::size_of::<YourType>() to see the serialized size
  • Use protobuf - Try the ProtoSerializable trait for cross-language compatibility
  • Explore supported types - See what types work with automatic serialization

Next Steps