Skip to main content

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}