Macro binary_layout::define_layout[][src]

macro_rules! define_layout {
    ($name: ident, $endianness: ident, {$($field_name: ident : $field_type: ty),* $(,)?}) => { ... };
    (_impl_fields $endianness: ty, $offset_accumulator: expr, {}) => { ... };
    (_impl_fields $endianness: ty, $offset_accumulator: expr, {$name: ident : $type: ty $(, $name_tail: ident : $type_tail: ty)*}) => { ... };
    (_impl_view_asref {}) => { ... };
    (_impl_view_asref {$name: ident $(, $name_tail: ident)*}) => { ... };
    (_impl_view_asmut {}) => { ... };
    (_impl_view_asmut {$name: ident $(, $name_tail: ident)*}) => { ... };
    (_impl_view_into {}) => { ... };
    (_impl_view_into {$name: ident $(, $name_tail: ident)*}) => { ... };
}

This macro defines a data layout. Given such a layout, the Field or FieldView APIs can be used to access data based on it.

Data layouts define

  • a name for the layout
  • and endianness for its fields (BigEndian or LittleEndian)
  • and an ordered collection of typed fields.

See supported field types for a list of supported field types.

API

define_layout!(<<Name>>, <<Endianness>>, {
  <<FieldName>>: <<FieldType>>,
  <<FieldName>>: <<FieldType>>,
  ...
});

Field names

Field names can be any valid Rust identifiers, but it is recommended to avoid names that contain storage, into_ or _mut. This is because the define_layout! macro creates a View class with several accessors for each field that contain those identifier parts.

Example

use binary_layout::prelude::*;

define_layout!(icmp_packet, BigEndian, {
  packet_type: u8,
  code: u8,
  checksum: u16,
  rest_of_header: [u8; 4],
  data_section: [u8], // open ended byte array, matches until the end of the packet
});

Generated code

See icmp_packet for an example.

This macro will define a module for you with several members:

  • For each field, there will be a struct containing
    • metadata like OFFSET and SIZE as rust consts
    • data accessors for the Field API
  • The module will also contain a View struct that offers the FieldView API.

Metadata Example

use binary_layout::prelude::*;

define_layout!(my_layout, LittleEndian, {
  field1: u16,
  field2: u32,
});
assert_eq!(2, my_layout::field2::OFFSET);
assert_eq!(4, my_layout::field2::SIZE);

struct View

See icmp_packet::View for an example.

You can create views over a storage by calling View::new. Views can be created based on

  • Immutable borrowed storage: &[u8]
  • Mutable borrowed storage: &mut [u8]
  • Owning storage: impl AsRef<u8> (for example: Vec<u8>)

The generated View struct will offer

  • View::new(storage) to create a View
  • View::into_storage(self) to destroy a View and return the storage held

and it will offer the following accessors for each field

  • ${field_name}(): Read access. This returns a FieldView instance with read access.
  • ${field_name}_mut(): Read access. This returns a FieldView instance with write access.
  • into_${field_name}: Extract access. This destroys the View and returns a FieldView instance owning the storage. Mostly useful for FieldView::extract.