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 the Stream 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");