16 releases
Uses new Rust 2024
| new 0.4.7 | Apr 10, 2026 |
|---|---|
| 0.4.6 | Apr 5, 2026 |
| 0.4.4 | Mar 26, 2026 |
| 0.3.7 | Feb 23, 2026 |
| 0.3.3 | Jan 26, 2026 |
#14 in #derive-macro
Used in 3 crates
(via osal-rs-serde)
18KB
148 lines
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.4", 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
allocfeature)
Best Practices
- Always use derive when possible - It's less error-prone than manual implementation
- Keep structs simple - Avoid deeply nested structures when possible
- Consider field order - Put frequently accessed fields first
- Document binary format - Add comments about the serialized format
- 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 usagearrays_tuples.rs- Arrays and tuplesnested_structs.rs- Nested structuresoptional_fields.rs- Optional fieldsrobot_control.rs- Complex embedded example
License
LGPL-2.1-or-later - See LICENSE for details.
Author
Antonio Salsi - passy.linux@zresa.it
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Links
Dependencies
~115–480KB
~11K SLoC