Macro binary_layout::prelude::binary_layout
source · macro_rules! binary_layout { ($name: ident, $endianness: ident, {$($field_name: ident : $field_type: ty $(as $underlying_type: ty)?),* $(,)?}) => { ... }; (@impl_fields $endianness: ty, $offset_accumulator: expr, {}) => { ... }; (@impl_fields $endianness: ty, $offset_accumulator: expr, {$name: ident : $type: ty as $underlying_type: ty $(, $($tail:tt)*)?}) => { ... }; (@impl_fields $endianness: ty, $offset_accumulator: expr, {$name: ident : $type: ty $(, $($tail:tt)*)?}) => { ... }; (@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)*}) => { ... }; }
Expand description
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
binary_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 binary_layout! macro creates a View class with several accessors for each field that contain those identifier parts.
§Example
use binary_layout::prelude::*;
binary_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
- The module will also contain a
View
struct that offers the FieldView API.
This macro will also generate rustdoc documentation for everything it generates. One of the best ways to figure out how to use the generated layouts is to read the rustdoc documentation that was generated for them.
§Metadata Example
use binary_layout::prelude::*;
binary_layout!(my_layout, LittleEndian, {
field1: u16,
field2: u32,
});
assert_eq!(2, my_layout::field2::OFFSET);
assert_eq!(Some(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 aView
View::into_storage(self)
to destroy aView
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 theView
and returns a FieldView instance owning the storage. Mostly useful for slice fields when you want to return an owning slice.