irox_structs/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// SPDX-License-Identifier: MIT
// Copyright 2024 IROX Contributors
//

//!
//! A very simple 'Struct' library that provides a single trait.  This is intended to be most
//! generally used in concert with [`irox_structs_derive`] to generate the impls.
//!
//! A Struct is a linear sequence in memory of serialized bytes - serialized in the order the
//! fields are present in the struct with no adjacency or packing.
//!
//! ## Strict Sizing
//! By default, [`irox_structs_derive`] will allow variably sized types like [`String`] and [`Vec<u8>`].
//! If you know you don't need/use these, apply a `#[strict_sizing]` attribute, and the generator
//! will add a `pub const STRUCT_SIZE: usize` to the struct
//!
//! ## Choosing Endianness:
//! Apply either the `#[big_endian]` or `#[little_endian]` attributes when deriving [`Struct`] and
//! it will use the appropriate serializers.  If not specified, it defaults to big endian.
//!
//! ### Example Big Endian:
//! ```
//! use irox_structs::Struct;
//! use irox_bits::Error;
//!
//! #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Struct)]
//! #[strict_sizing]
//! pub struct UdpHeader {
//!     source_port: u16,
//!     dest_port: u16,
//!     length: u16,
//!     checksum: u16,
//! }
//!
//! pub fn main() -> Result<(), Error>{
//!     assert_eq!(8, UdpHeader::STRUCT_SIZE);
//!
//!    let header = UdpHeader {
//!         source_port: 0x0064,
//!         dest_port: 0x0400,
//!         length: 0x1388,
//!         checksum: 0x01C2,
//!     };
//!    let mut output_buf: Vec<u8> = Vec::new();
//!
//!    header.write_to(&mut output_buf)?;
//!    assert_eq!(output_buf.len(), 8);
//!    assert_eq!(&[0x00u8, 0x64, 0x04, 0x00, 0x13, 0x88, 0x01, 0xC2],
//!                 output_buf.as_slice());
//!
//!    let parsed = UdpHeader::parse_from(&mut output_buf.as_slice())?;
//!     assert_eq!(header, parsed);
//!  Ok(())
//! }
//! ```
//! ### Example Little Endian:
//! ```
//! use irox_structs::Struct;
//! use irox_bits::Error;
//!
//! #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Struct)]
//! #[little_endian]
//! #[strict_sizing]
//! pub struct UdpHeader {
//!     source_port: u16,
//!     dest_port: u16,
//!     length: u16,
//!     checksum: u16,
//! }
//!
//! pub fn main() -> Result<(), Error>{
//!     assert_eq!(8, UdpHeader::STRUCT_SIZE);
//!    let header = UdpHeader {
//!         source_port: 0x0064,
//!         dest_port: 0x0400,
//!         length: 0x1388,
//!         checksum: 0x01C2,
//!     };
//!    let mut output_buf: Vec<u8> = Vec::new();
//!
//!    header.write_to(&mut output_buf)?;
//!    assert_eq!(output_buf.len(), 8);
//!    assert_eq!(&[0x64u8, 0x00, 0x00, 0x04, 0x88, 0x13, 0xC2, 0x01],
//!                 output_buf.as_slice());
//!
//!    let parsed = UdpHeader::parse_from(&mut output_buf.as_slice())?;
//!     assert_eq!(header, parsed);
//!  Ok(())
//! }
//! ```

pub use irox_bits::{Bits, Error, MutBits};
pub use irox_structs_derive::*;
#[cfg(feature = "alloc")]
extern crate alloc;

///
/// A struct is a series of bytes in memory, serialized in the order that the
/// fields are present in the struct.
///
/// Generally speaking, you shouldn't need to implement this, unless you need
/// some custom encoding.  It's intended to be used with [`irox_structs_derive`] to automatically
/// generate the impl.
pub trait Struct {
    type ImplType;

    ///
    /// Write the encoding of the type to the specified output buffer
    fn write_to<T: MutBits>(&self, out: &mut T) -> Result<(), Error>;

    ///
    /// Returns the encoded bytes as a vector
    #[cfg(feature = "alloc")]
    fn as_bytes(&self) -> Result<alloc::vec::Vec<u8>, Error> {
        let mut buf: Vec<u8> = Vec::new();
        self.write_to(&mut buf)?;
        Ok(buf)
    }

    ///
    /// Parses and creates the impl type from the input stream, consuming bytes along
    /// the way.
    fn parse_from<T: Bits>(input: &mut T) -> Result<Self::ImplType, Error>;
}