irox_structs/lib.rs
1// SPDX-License-Identifier: MIT
2// Copyright 2024 IROX Contributors
3//
4
5//!
6//! A very simple 'Struct' library that provides a single trait. This is intended to be most
7//! generally used in concert with [`irox_structs_derive`] to generate the impls.
8//!
9//! A Struct is a linear sequence in memory of serialized bytes - serialized in the order the
10//! fields are present in the struct with no adjacency or packing.
11//!
12//! ## Strict Sizing
13//! By default, [`irox_structs_derive`] will allow variably sized types like [`String`] and [`Vec<u8>`].
14//! If you know you don't need/use these, apply a `#[strict_sizing]` attribute, and the generator
15//! will add a `pub const STRUCT_SIZE: usize` to the struct
16//!
17//! ## Choosing Endianness:
18//! Apply either the `#[big_endian]` or `#[little_endian]` attributes when deriving [`Struct`] and
19//! it will use the appropriate serializers. If not specified, it defaults to big endian.
20//!
21//! ### Example Big Endian:
22//! ```
23//! use irox_structs::Struct;
24//! use irox_bits::Error;
25//!
26//! #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Struct)]
27//! #[strict_sizing]
28//! pub struct UdpHeader {
29//! source_port: u16,
30//! dest_port: u16,
31//! length: u16,
32//! checksum: u16,
33//! }
34//!
35//! pub fn main() -> Result<(), Error>{
36//! assert_eq!(8, UdpHeader::STRUCT_SIZE);
37//!
38//! let header = UdpHeader {
39//! source_port: 0x0064,
40//! dest_port: 0x0400,
41//! length: 0x1388,
42//! checksum: 0x01C2,
43//! };
44//! let mut output_buf: Vec<u8> = Vec::new();
45//!
46//! header.write_to(&mut output_buf)?;
47//! assert_eq!(output_buf.len(), 8);
48//! assert_eq!(&[0x00u8, 0x64, 0x04, 0x00, 0x13, 0x88, 0x01, 0xC2],
49//! output_buf.as_slice());
50//!
51//! let parsed = UdpHeader::parse_from(&mut output_buf.as_slice())?;
52//! assert_eq!(header, parsed);
53//! Ok(())
54//! }
55//! ```
56//! ### Example Little Endian:
57//! ```
58//! use irox_structs::Struct;
59//! use irox_bits::Error;
60//!
61//! #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Struct)]
62//! #[little_endian]
63//! #[strict_sizing]
64//! pub struct UdpHeader {
65//! source_port: u16,
66//! dest_port: u16,
67//! length: u16,
68//! checksum: u16,
69//! }
70//!
71//! pub fn main() -> Result<(), Error>{
72//! assert_eq!(8, UdpHeader::STRUCT_SIZE);
73//! let header = UdpHeader {
74//! source_port: 0x0064,
75//! dest_port: 0x0400,
76//! length: 0x1388,
77//! checksum: 0x01C2,
78//! };
79//! let mut output_buf: Vec<u8> = Vec::new();
80//!
81//! header.write_to(&mut output_buf)?;
82//! assert_eq!(output_buf.len(), 8);
83//! assert_eq!(&[0x64u8, 0x00, 0x00, 0x04, 0x88, 0x13, 0xC2, 0x01],
84//! output_buf.as_slice());
85//!
86//! let parsed = UdpHeader::parse_from(&mut output_buf.as_slice())?;
87//! assert_eq!(header, parsed);
88//! Ok(())
89//! }
90//! ```
91
92pub use irox_bits::{Bits, Error, MutBits};
93pub use irox_structs_derive::*;
94#[cfg(feature = "alloc")]
95extern crate alloc;
96
97///
98/// A struct is a series of bytes in memory, serialized in the order that the
99/// fields are present in the struct.
100///
101/// Generally speaking, you shouldn't need to implement this, unless you need
102/// some custom encoding. It's intended to be used with [`irox_structs_derive`] to automatically
103/// generate the impl.
104pub trait Struct {
105 type ImplType;
106
107 ///
108 /// Write the encoding of the type to the specified output buffer
109 fn write_to<T: MutBits>(&self, out: &mut T) -> Result<(), Error>;
110
111 ///
112 /// Returns the encoded bytes as a vector
113 #[cfg(feature = "alloc")]
114 fn as_bytes(&self) -> Result<alloc::vec::Vec<u8>, Error> {
115 let mut buf: Vec<u8> = Vec::new();
116 self.write_to(&mut buf)?;
117 Ok(buf)
118 }
119
120 ///
121 /// Parses and creates the impl type from the input stream, consuming bytes along
122 /// the way.
123 fn parse_from<T: Bits>(input: &mut T) -> Result<Self::ImplType, Error>;
124}