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>;
}