osal_rs_serde/lib.rs
1/***************************************************************************
2 *
3 * osal-rs-serde
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
18 *
19 ***************************************************************************/
20
21//! # OSAL-RS-Serde - Serialization/Deserialization Framework
22//!
23//! A lightweight, extensible serialization framework inspired by Serde,
24//! designed for embedded systems and no-std environments.
25//!
26//! ## Overview
27//!
28//! This library provides a flexible serialization/deserialization framework that:
29//! - **No-std compatible**: Works perfectly in bare-metal embedded environments
30//! - **Memory-efficient**: Optimized for resource-constrained systems
31//! - **Derive macro support**: `#[derive(Serialize, Deserialize)]` for automatic implementation
32//! - **Extensible**: Create custom serializers for any format (binary, JSON, MessagePack, etc.)
33//! - **Type-safe**: Leverages Rust's type system for compile-time guarantees
34//! - **Standalone**: Can be used in any project, not just with osal-rs
35//!
36//! ## Supported Types
37//!
38//! - **Primitives**: `bool`, `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `u128`, `i128`, `f32`, `f64`
39//! - **Compound types**: Arrays `[T; N]`, tuples `(T1, T2, T3)` (up to 3 elements), `Option<T>`
40//! - **Collections**: `Vec<T>`, byte slices, strings (with `alloc` feature)
41//! - **Custom types**: Any struct implementing `Serialize`/`Deserialize`
42//! - **Nested structs**: Full support for struct composition
43//!
44//! ## Memory Layout
45//!
46//! The default `ByteSerializer` uses little-endian binary format:
47//! - Primitives: Native sizes (1, 2, 4, 8, or 16 bytes)
48//! - `bool`: 1 byte (0 or 1)
49//! - `Option<T>`: 1 byte tag + sizeof(T) if Some, 1 byte if None
50//! - Arrays `[T; N]`: sizeof(T) * N (no length prefix)
51//! - Tuples: concatenation of all elements
52//! - Structs: concatenation of all fields in declaration order
53//!
54//! ## Quick Start
55//!
56//! ### Using Derive Macros (Recommended)
57//!
58//! #### Basic Struct Example
59//!
60//! ```ignore
61//! use osal_rs_serde::{Serialize, Deserialize, to_bytes, from_bytes};
62//!
63//! #[derive(Serialize, Deserialize)]
64//! struct SensorData {
65//! temperature: i16,
66//! humidity: u8,
67//! pressure: u32,
68//! }
69//!
70//! fn main() {
71//! let data = SensorData {
72//! temperature: 25,
73//! humidity: 60,
74//! pressure: 1013,
75//! };
76//!
77//! // Serialize
78//! let mut buffer = [0u8; 32];
79//! let len = to_bytes(&data, &mut buffer).unwrap();
80//! println!("Serialized {} bytes", len);
81//!
82//! // Deserialize
83//! let read_data: SensorData = from_bytes(&buffer[..len]).unwrap();
84//! println!("Temperature: {}", read_data.temperature);
85//! }
86//! ```
87//!
88//! #### Struct with Optional Fields
89//!
90//! ```ignore
91//! use osal_rs_serde::{Serialize, Deserialize, to_bytes, from_bytes};
92//!
93//! #[derive(Serialize, Deserialize)]
94//! struct Config {
95//! device_id: u32,
96//! name: Option<u8>, // Optional device name code
97//! enabled: bool,
98//! timeout: Option<u16>, // Optional timeout in ms
99//! }
100//!
101//! fn main() {
102//! let config = Config {
103//! device_id: 100,
104//! name: Some(42),
105//! enabled: true,
106//! timeout: None,
107//! };
108//!
109//! let mut buffer = [0u8; 64];
110//! let len = to_bytes(&config, &mut buffer).unwrap();
111//! let decoded: Config = from_bytes(&buffer[..len]).unwrap();
112//! }
113//! ```
114//!
115//! #### Struct with Arrays and Tuples
116//!
117//! ```ignore
118//! use osal_rs_serde::{Serialize, Deserialize, to_bytes, from_bytes};
119//!
120//! #[derive(Serialize, Deserialize)]
121//! struct TelemetryPacket {
122//! timestamp: u64,
123//! coordinates: (i32, i32, i32), // x, y, z
124//! samples: [u16; 8], // 8 sensor readings
125//! status: u8,
126//! }
127//!
128//! fn main() {
129//! let packet = TelemetryPacket {
130//! timestamp: 1642857600,
131//! coordinates: (100, 200, 50),
132//! samples: [10, 20, 30, 40, 50, 60, 70, 80],
133//! status: 0xFF,
134//! };
135//!
136//! let mut buffer = [0u8; 128];
137//! let len = to_bytes(&packet, &mut buffer).unwrap();
138//! println!("Telemetry packet: {} bytes", len);
139//! }
140//! ```
141//!
142//! #### Nested Structs
143//!
144//! ```ignore
145//! use osal_rs_serde::{Serialize, Deserialize, to_bytes, from_bytes};
146//!
147//! #[derive(Serialize, Deserialize)]
148//! struct Location {
149//! latitude: i32,
150//! longitude: i32,
151//! }
152//!
153//! #[derive(Serialize, Deserialize)]
154//! struct Device {
155//! id: u32,
156//! battery: u8,
157//! location: Location,
158//! active: bool,
159//! }
160//!
161//! fn main() {
162//! let device = Device {
163//! id: 42,
164//! battery: 85,
165//! location: Location {
166//! latitude: 45500000,
167//! longitude: 9200000,
168//! },
169//! active: true,
170//! };
171//!
172//! let mut buffer = [0u8; 64];
173//! let len = to_bytes(&device, &mut buffer).unwrap();
174//! let decoded: Device = from_bytes(&buffer[..len]).unwrap();
175//! println!("Device at {}, {}",
176//! decoded.location.latitude,
177//! decoded.location.longitude);
178//! }
179//! ```
180//!
181//! #### Complex Embedded System Example
182//!
183//! ```ignore
184//! use osal_rs_serde::{Serialize, Deserialize, to_bytes, from_bytes};
185//!
186//! #[derive(Serialize, Deserialize, Debug, PartialEq)]
187//! struct MotorControl {
188//! motor_id: u8,
189//! speed: i16, // -1000 to 1000
190//! direction: bool, // true = forward, false = reverse
191//! current: u16, // mA
192//! }
193//!
194//! #[derive(Serialize, Deserialize, Debug, PartialEq)]
195//! struct RobotState {
196//! timestamp: u64,
197//! motors: [MotorControl; 4], // 4 motors
198//! battery_voltage: u16, // mV
199//! temperature: i8, // °C
200//! error_flags: u32,
201//! }
202//!
203//! fn main() {
204//! let state = RobotState {
205//! timestamp: 1000000,
206//! motors: [
207//! MotorControl { motor_id: 0, speed: 500, direction: true, current: 1200 },
208//! MotorControl { motor_id: 1, speed: 500, direction: true, current: 1150 },
209//! MotorControl { motor_id: 2, speed: -300, direction: false, current: 800 },
210//! MotorControl { motor_id: 3, speed: -300, direction: false, current: 850 },
211//! ],
212//! battery_voltage: 12400, // 12.4V
213//! temperature: 35,
214//! error_flags: 0,
215//! };
216//!
217//! let mut buffer = [0u8; 256];
218//! let len = to_bytes(&state, &mut buffer).unwrap();
219//! println!("Robot state serialized: {} bytes", len);
220//!
221//! // Deserialize and check
222//! let decoded: RobotState = from_bytes(&buffer[..len]).unwrap();
223//! assert_eq!(state, decoded);
224//! println!("Battery: {}mV, Temp: {}°C",
225//! decoded.battery_voltage,
226//! decoded.temperature);
227//! }
228//! ```
229//!
230//! ### Manual Implementation (For Custom Behavior)
231//!
232//! ```ignore
233//! use osal_rs_serde::{Serialize, Deserialize, Serializer, Deserializer};
234//!
235//! struct Point {
236//! x: i32,
237//! y: i32,
238//! }
239//!
240//! impl Serialize for Point {
241//! fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
242//! serializer.serialize_i32("x", self.x)?;
243//! serializer.serialize_i32("y", self.y)?;
244//! Ok(())
245//! }
246//! }
247//!
248//! impl Deserialize for Point {
249//! fn deserialize<D: Deserializer>(deserializer: &mut D, _name: &str) -> Result<Self, D::Error> {
250//! Ok(Point {
251//! x: deserializer.deserialize_i32("x")?,
252//! y: deserializer.deserialize_i32("y")?,
253//! })
254//! }
255//! }
256//! ```
257//!
258//! ## Integration with OSAL-RS
259//!
260//! Perfect for inter-task communication using queues:
261//!
262//! ```ignore
263//! use osal_rs::os::{Queue, QueueFn};
264//! use osal_rs_serde::{Serialize, Deserialize, to_bytes, from_bytes};
265//!
266//! #[derive(Serialize, Deserialize)]
267//! struct Message {
268//! command: u8,
269//! data: [u16; 4],
270//! }
271//!
272//! fn sender(queue: &Queue) {
273//! let msg = Message { command: 0x42, data: [1, 2, 3, 4] };
274//! let mut buffer = [0u8; 32];
275//! let len = to_bytes(&msg, &mut buffer).unwrap();
276//! queue.post(&buffer[..len], 100).unwrap();
277//! }
278//!
279//! fn receiver(queue: &Queue) {
280//! let mut buffer = [0u8; 32];
281//! queue.fetch(&mut buffer, 100).unwrap();
282//! let msg: Message = from_bytes(&buffer).unwrap();
283//! }
284//! ```
285//!
286//! ## Supported Types
287//!
288//! - **Primitives**: All integer types (u8-u128, i8-i128), f32, f64, bool
289//! - **Compound**: Arrays `[T; N]`, tuples (up to 3 elements), `Option<T>`
290//! - **Collections**: `Vec<T>`, `String` (requires `alloc` feature)
291//! - **Custom**: Any type implementing `Serialize`/`Deserialize`
292//! - **Nested**: Full support for nested structs
293//!
294//! ## Creating Custom Serializers
295//!
296//! You can create custom serializers for different formats (JSON, MessagePack, CBOR, etc.)
297//! by implementing the `Serializer` and `Deserializer` traits:
298//!
299//! ```ignore
300//! use osal_rs_serde::{Serializer, Error};
301//!
302//! struct JsonSerializer<'a> {
303//! buffer: &'a mut [u8],
304//! position: usize,
305//! }
306//!
307//! impl<'a> Serializer for JsonSerializer<'a> {
308//! type Error = Error;
309//!
310//! fn serialize_u32(&mut self, name: &str, v: u32) -> Result<(), Self::Error> {
311//! // Write JSON format: "name": value
312//! // Implementation here...
313//! Ok(())
314//! }
315//!
316//! // Implement other serialize_* methods...
317//! }
318//! ```
319//!
320//! See `examples/custom_serializer.rs` for a complete implementation example.
321//!
322//! ## Performance & Binary Size
323//!
324//! - **Zero-copy**: Reads/writes directly to/from buffers
325//! - **No allocations**: Works entirely with stack buffers (or Vec with `alloc`)
326//! - **Predictable**: Buffer size calculable at compile time
327//! - **Small code size**: Minimal overhead, optimized for embedded targets
328//!
329//! ## Features
330//!
331//! - `default`: Includes `alloc` feature
332//! - `alloc`: Enables Vec, String support
333//! - `std`: Enables standard library (error traits, etc.)
334//! - `derive`: Enables `#[derive(Serialize, Deserialize)]` macros (**recommended**)
335//!
336//! ## Examples
337//!
338//! The `examples/` directory contains complete working examples:
339//! - `basic.rs` - Simple struct serialization
340//! - `with_derive.rs` - Using derive macros
341//! - `arrays_tuples.rs` - Arrays and tuples
342//! - `nested_structs.rs` - Nested structures
343//! - `optional_fields.rs` - Optional fields with Option<T>
344//! - `robot_control.rs` - Complex embedded system
345//! - `custom_serializer.rs` - Custom serializer implementation
346
347#![cfg_attr(not(feature = "std"), no_std)]
348#![warn(missing_docs)]
349
350#[cfg(feature = "alloc")]
351extern crate alloc;
352
353pub mod error;
354pub mod ser;
355pub mod de;
356
357use alloc::vec::Vec;
358pub use error::{Error, Result};
359pub use ser::{Serialize, Serializer, ByteSerializer};
360pub use de::{Deserialize, Deserializer, ByteDeserializer};
361
362// Re-export derive macros when the derive feature is enabled
363#[cfg(feature = "derive")]
364pub use osal_rs_serde_derive::{Serialize, Deserialize};
365
366/// Serialize a value to a byte buffer.
367///
368/// This is a convenience function that handles serialization in a single call.
369///
370/// # Examples
371///
372/// ```ignore
373/// use osal_rs_serde::to_bytes;
374///
375/// let value = 42u32;
376/// let mut buffer = [0u8; 4];
377/// let len = to_bytes(&value, &mut buffer).unwrap();
378/// assert_eq!(len, 4);
379/// ```
380pub fn to_bytes<T>(value: &T, buffer: &mut [u8]) -> Result<usize>
381where
382 T: Serialize
383{
384 let mut serializer = ByteSerializer::new(buffer);
385 value.serialize("", &mut serializer)?;
386 Ok(serializer.position())
387}
388
389/// Serialize a value to a dynamically sized byte vector.
390///
391/// This is a convenience function that handles serialization to a growable Vec<u8>.
392///
393/// # Examples
394///
395/// ```ignore
396/// use osal_rs_serde::to_dyn_bytes;
397/// use alloc::vec::Vec;
398///
399/// let value = 42u32;
400/// let mut buffer = Vec::new();
401/// let len = to_dyn_bytes(&value, &mut buffer).unwrap();
402/// assert_eq!(len, 4);
403/// ```
404pub fn to_dyn_bytes<T>(value: &T, buffer: &mut Vec<u8>) -> Result<usize>
405where
406 T: Serialize
407{
408 let mut serializer = ByteSerializer::new(buffer);
409 value.serialize("", &mut serializer)?;
410 Ok(serializer.position())
411}
412
413/// Deserialize a value from a byte buffer.
414///
415/// This is a convenience function that handles deserialization in a single call.
416///
417/// # Examples
418///
419/// ```ignore
420/// use osal_rs_serde::from_bytes;
421///
422/// let buffer = [42u8, 0, 0, 0];
423/// let value: u32 = from_bytes(&buffer).unwrap();
424/// assert_eq!(value, 42);
425/// ```
426pub fn from_bytes<T>(buffer: &[u8]) -> Result<T>
427where
428 T: Deserialize
429{
430 let mut deserializer = ByteDeserializer::new(buffer);
431 T::deserialize(&mut deserializer, "")
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437
438 #[test]
439 fn test_primitive_serialization() {
440 let mut buffer = [0u8; 4];
441 let len = to_bytes(&42u32, &mut buffer).unwrap();
442 assert_eq!(len, 4);
443
444 let value: u32 = from_bytes(&buffer).unwrap();
445 assert_eq!(value, 42);
446 }
447}