Macro tarrasque::extract [−][src]
macro_rules! extract { ( $(#[$attribute:meta])* pub $name:ident$([$length:expr])*$(($($pname:ident: $pty:ty),*))* { $($(#[$fattribute:meta])* $fname:ident: $ftype:ty = ($($fextract:tt)*),)* } ) => { ... }; ( $(#[$attribute:meta])* pub $name:ident<$lt:tt>$([$length:expr])*$(($($pname:ident: $pty:ty),*))* { $($(#[$fattribute:meta])* $fname:ident: $ftype:ty = ($($fextract:tt)*),)* } ) => { ... }; ( @IMPL: $name:ident$(<$lt:tt>)*: : $($fname:ident: $ftype:ty = ($($fextract:tt)*),)* ) => { ... }; ( @IMPL: $name:ident$(<$lt:tt>)*: ($pname:ident: $pty:ty): $($fname:ident: $ftype:ty = ($($fextract:tt)*),)* ) => { ... }; ( @IMPL: $name:ident$(<$lt:tt>)*: ($($pname:ident: $pty:ty),*): $($fname:ident: $ftype:ty = ($($fextract:tt)*),)* ) => { ... }; (@EXTRACT: $stream:expr, $s:ident => $f:expr) => { ... }; (@EXTRACT: $stream:expr, [extract]) => { ... }; (@EXTRACT: $stream:expr, [extract($param:expr)]) => { ... }; (@EXTRACT: $stream:expr, [extract($($param:expr),*)]) => { ... }; (@EXTRACT: $stream:expr, $expr:expr) => { ... }; }
Defines a struct with a corresponding Extract
implementation.
This macro allows for some flexibility in both the definition of the struct and the
implementation of the associated Extract
implementation.
Struct Definition
First, it is possible to define a lifetime associated with the struct, which is necessary when
you want to store references to the stream of bytes in the struct. An example of this is shown
in the second example below. Note: due to macro limitations, this lifetime must be 'a
.
Second, it is possible to specify that the associated Extract
implementation always attempts
to consume a fixed number of bytes. This will add a Span
implementation for the struct. An
example of this is shown in the first example below, as the [8]
that comes after the name of
the struct.
Extract
Implementation
First, it is possible to specify the parameters used by the associated Extract
implementation.
These parameters are defined in the form of function parameters. An example of this is shown in
the second example below.
Second, each of the expressions used to populate the fields of the struct in the associated
Extract
implementation can take one of several forms:
- A typical expression
Example:(a + b)
in the first example below - An
extract
call with optional arguments on theStream
in use
Example:([extract])
or([extract(Endianness::Little)])
in the first example below - An expression utilizing the
Stream
in use
Example:(s => s.extract(Endianness::Little).map(|i: u16| i + 1))
in the first example below
In all cases where expressions are valid, both parameters and preceding fields may be utilized.
For example, c: u16 = (a + b)
in the first example below utilizes the two preceding fields.
Examples
Zero parameters and no lifetime:
extract! { /// An example struct. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub Struct[8] { a: u16 = ([extract]), b: u16 = ([extract]), c: u16 = (a + b), d: u16 = ([extract(Endianness::Little)]), e: u16 = (s => s.extract(Endianness::Little).map(|i: u16| i + 1)), } } let bytes = &[1, 2, 3, 4, 5, 6, 7, 8]; let mut stream = Stream(bytes); let value: Struct = stream.extract(()).unwrap(); assert_eq!(value.a, 0x0102); assert_eq!(value.b, 0x0304); assert_eq!(value.c, 0x0406); assert_eq!(value.d, 0x0605); assert_eq!(value.e, 0x0808);
Two parameters and a lifetime:
extract! { /// An example struct. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub Struct<'a>(left: usize, right: usize) { foo: &'a str = ([extract(left)]), bar: &'a str = ([extract(right)]), } } let mut stream = Stream(&[102, 111, 111, 98, 97, 114]); let value: Struct = stream.extract((3, 3)).unwrap(); assert_eq!(value.foo, "foo"); assert_eq!(value.bar, "bar");