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}