Macro format_struct::format_struct

source ·
macro_rules! format_struct {
    ($($(#[$m:meta])* $vis:vis struct $endian:tt $name:ident {
        $($(#[doc = $field_doc:literal])* $field_vis:vis $field_name:ident: $ty:tt),*,
    })+) => { ... };
    (@impl_conv $name:ident$(<$gen:ident>)? size $size_expr:expr) => { ... };
    (@endian_type little) => { ... };
    (@endian_type big) => { ... };
    (@endian_type dynamic) => { ... };
    (@wrapper_type [$ty:ident; $n:literal] $endian:tt) => { ... };
    (@wrapper_type u8 $endian:tt) => { ... };
    (@wrapper_type i8 $endian:tt) => { ... };
    (@wrapper_type u16 $endian:tt) => { ... };
    (@wrapper_type i16 $endian:tt) => { ... };
    (@wrapper_type u32 $endian:tt) => { ... };
    (@wrapper_type i32 $endian:tt) => { ... };
    (@wrapper_type u64 $endian:tt) => { ... };
    (@wrapper_type i64 $endian:tt) => { ... };
    (@wrapper_type u128 $endian:tt) => { ... };
    (@wrapper_type i128 $endian:tt) => { ... };
}
Expand description

Defines a structure that can be transmuted from/into a byte slice for parsing/constructing binary formats in a zero-copy way.

The macro achieves this by replacing all multibyte integers with wrapper types that are byte arrays internally and only allowing integer and fixed size array fields in a structure.

Accepted syntax is similar to a standard structure definition in Rust with some differences:

  • The struct keyword is followed by either little or big keywords if you want fixed endianness or dynamic keyword if you want dynamic endianness.
  • Fields of the generated structure may only have documentation meta, other meta types are disallowed.

§Examples

format_struct! {
    /// A little-endian test structure.
    #[derive(Default, Clone)]
    pub struct little Test {
        /// this byte is public
        pub byte: u8,
        short: u16,
        word: i32,
        dword: i64,
        qword: u128,
        byte_arr: [u8; 16],
    }
}

It is also possible to define multiple structures in one macro invocation:

format_struct! {
    struct little Foo {
        byte: u8,
    }

    struct big Bar {
        a: u64,
    }

    pub struct little Baz {
        z: [u8; 33],
    }
}

§Allowed field types

Currently only integer types (u8, u16, u32, u64, u128 and their signed counterparts) are allowed and statically sized integer arrays ([u8; N]).

§Layout

The fields in the structure are laid out in declaration order without any padding. That means that the following structure will take 7 bytes instead of 16 you might expect:

format_struct! {
    struct little SmallStruct {
        byte: u8,
        dword: u64,
    }
}