osal-rs-serde-derive

Crates.ioosal-rs-serde-derive
lib.rsosal-rs-serde-derive
version0.3.2
created_at2026-01-21 10:39:53.958788+00
updated_at2026-01-23 16:10:26.558288+00
descriptionDerive macros for osal-rs-serde serialization framework
homepagehttps://github.com/HiHappyGarden/osal-rs
repositoryhttps://github.com/HiHappyGarden/osal-rs
max_upload_size
id2058845
size18,046
Antonio Salsi (passy1977)

documentation

https://docs.rs/osal-rs-serde-derive

README

OSAL-RS-Serde Derive Macros

Procedural macros for automatic implementation of serialization traits in osal-rs-serde.

Overview

This crate provides #[derive(Serialize, Deserialize)] macros that automatically implement the Serialize and Deserialize traits for your custom types. These macros are the recommended way to use osal-rs-serde.

Usage

Add the derive feature to enable these macros:

[dependencies]
osal-rs-serde = { version = "0.3", features = ["derive"] }

Then use the macros on your structs:

use osal_rs_serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct SensorData {
    temperature: i16,
    humidity: u8,
    pressure: u32,
}

Supported Struct Types

Named Fields (Most Common)

#[derive(Serialize, Deserialize)]
struct Point {
    x: i32,
    y: i32,
}

Tuple Structs

#[derive(Serialize, Deserialize)]
struct Color(u8, u8, u8);

Unit Structs

#[derive(Serialize, Deserialize)]
struct Marker;

Supported Field Types

The derive macros work with any type that implements Serialize/Deserialize:

Primitives

#[derive(Serialize, Deserialize)]
struct AllPrimitives {
    a: bool,
    b: u8,
    c: i16,
    d: u32,
    e: i64,
    f: f32,
    g: f64,
}

Arrays

#[derive(Serialize, Deserialize)]
struct WithArrays {
    samples: [u16; 8],
    matrix: [[f32; 3]; 3],
}

Tuples

#[derive(Serialize, Deserialize)]
struct WithTuples {
    coordinate: (i32, i32),
    rgb: (u8, u8, u8),
}

Option Types

#[derive(Serialize, Deserialize)]
struct WithOptionals {
    required_id: u32,
    optional_name: Option<u8>,
    optional_value: Option<i16>,
}

Nested Structs

#[derive(Serialize, Deserialize)]
struct Inner {
    value: i32,
}

#[derive(Serialize, Deserialize)]
struct Outer {
    id: u32,
    inner: Inner,
}

Collections (with alloc feature)

#[derive(Serialize, Deserialize)]
struct WithCollections {
    items: Vec<u32>,
    name: String,
}

Complex Examples

Embedded System Telemetry

use osal_rs_serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct SensorReading {
    sensor_id: u8,
    value: i16,
    timestamp: u64,
}

#[derive(Serialize, Deserialize)]
struct TelemetryPacket {
    device_id: u32,
    readings: [SensorReading; 4],
    battery_level: u8,
    status_flags: u16,
}

Robot Control

use osal_rs_serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct MotorState {
    motor_id: u8,
    speed: i16,
    current: u16,
    enabled: bool,
}

#[derive(Serialize, Deserialize)]
struct RobotCommand {
    timestamp: u64,
    motors: [MotorState; 4],
    emergency_stop: bool,
}

Configuration with Optional Fields

use osal_rs_serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct DeviceConfig {
    device_id: u32,
    baudrate: u32,
    timeout_ms: Option<u16>,
    retry_count: Option<u8>,
    enabled: bool,
}

Serialization Order

Fields are serialized in the order they are declared in the struct:

#[derive(Serialize, Deserialize)]
struct Example {
    first: u8,    // Byte 0
    second: u16,  // Bytes 1-2
    third: u32,   // Bytes 3-6
}

This produces the binary layout: [first, second_lo, second_hi, third_0, third_1, third_2, third_3]

Limitations

Enums

Currently, enums are not supported by the derive macro:

// ❌ NOT SUPPORTED YET
#[derive(Serialize, Deserialize)]
enum Status {
    Active,
    Inactive,
}

For enums, implement the traits manually or use an integer representation:

// ✅ WORKAROUND
#[derive(Serialize, Deserialize)]
struct Status {
    code: u8,  // 0 = Inactive, 1 = Active
}

Unions

Unions are not supported:

// ❌ NOT SUPPORTED
#[derive(Serialize, Deserialize)]
union Data {
    integer: i32,
    float: f32,
}

Generic Types

Generic types are not yet supported in the current version:

// ❌ NOT SUPPORTED YET
#[derive(Serialize, Deserialize)]
struct Container<T> {
    value: T,
}

Generated Code

The derive macros generate implementations similar to:

// For this struct:
#[derive(Serialize, Deserialize)]
struct Point {
    x: i32,
    y: i32,
}

// The macro generates approximately:
impl Serialize for Point {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        serializer.serialize_struct_start("Point", 2)?;
        serializer.serialize_field("x", &self.x)?;
        serializer.serialize_field("y", &self.y)?;
        serializer.serialize_struct_end()?;
        Ok(())
    }
}

impl Deserialize for Point {
    fn deserialize<D: Deserializer>(deserializer: &mut D, name: &str) -> Result<Self, D::Error> {
        deserializer.deserialize_struct_start(name)?;
        let result = Self {
            x: deserializer.deserialize_field::<i32>("x")?,
            y: deserializer.deserialize_field::<i32>("y")?,
        };
        deserializer.deserialize_struct_end()?;
        Ok(result)
    }
}

Debugging

To see the generated code, use cargo expand:

cargo install cargo-expand
cargo expand --example your_example

Error Messages

Common errors and solutions:

"the trait bound T: Serialize is not satisfied"

Solution: Ensure all field types implement Serialize:

#[derive(Serialize, Deserialize)]
struct MyType {
    value: CustomType,  // CustomType must implement Serialize
}

"expected named fields"

Solution: Make sure you're using a supported struct type (named fields, tuple, or unit).

Performance

The derive macros generate efficient code with:

  • No runtime overhead compared to manual implementation
  • Inlining opportunities for the compiler
  • Zero-cost abstractions
  • No allocations (except for Vec/String with alloc feature)

Best Practices

  1. Always use derive when possible - It's less error-prone than manual implementation
  2. Keep structs simple - Avoid deeply nested structures when possible
  3. Consider field order - Put frequently accessed fields first
  4. Document binary format - Add comments about the serialized format
  5. Use Option for optional data - Don't use magic values

Examples

See the parent crate's examples/ directory for complete working examples:

  • with_derive.rs - Basic usage
  • arrays_tuples.rs - Arrays and tuples
  • nested_structs.rs - Nested structures
  • optional_fields.rs - Optional fields
  • robot_control.rs - Complex embedded example

License

GPL-3.0 - See LICENSE for details.

Author

Antonio Salsi passy.linux@zresa.it

Commit count: 191

cargo fmt