extract!() { /* proc-macro */ }
Expand description

Generates a struct and an implementation of Extract (and optionally Span) for that struct.

Example

The following code is an example of the usage of the extract! macro:

use tarrasque::{Endianness, extract};

extract! {
    /// A 2D point.
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    pub struct Point[4](endianness: Endianness) {
        /// The x-coordinate of this point.
        pub x: u16 = [endianness],
        /// The y-coordinate of this point.
        pub y: u16 = [endianness],
    }
}

The [4] that follows Point is an optional component that statically defines the number of bytes consumed by the generated Extract implementation. When this component is present, a Span implementation is generated using the specified span.

The (endianness: Endianness) that follows [4] is another optional component that defines the parameter used by the Extract implementation. In this case, a specified endianness is used to extract the u16s instead of using the default (big-endian). When this component is omitted, a placeholder parameter of type () is used instead.

Though not shown here, structs may also make use of generics and lifetimes. See below for an example.

Each field has a corresponding expression which is used to populate it in the Extract implementation. Square brackets indicate that the field is to be populated by extracting a value of that type from the stream. The expression in the square brackets is used as the argument for the extract method. If the square brackets do not contain an expression, () is used as the argument.

Expressions not wrapped in square brackets are treated as normal expressions. The [endianness] expression could be replaced with the equivalent stream.extract(endianness)?. Note the usage of stream which is implicitly available in these expressions.

Expansion

The usage of extract! shown above generates the following code:

use tarrasque::{Endianness, extract};

/// A 2D point.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Point {
    /// The x-coordinate of this point.
    pub x: u16,
    /// The y-coordinate of this point.
    pub y: u16,
}

impl<'s> ::tarrasque::Extract<'s, Endianness> for Point {
    #[inline]
    fn extract(
        mut stream: &mut ::tarrasque::Stream<'s>, endianness: Endianness
    ) -> ::tarrasque::ExtractResult<'s, Self> {
        let x = stream.extract(endianness)?;
        let y = stream.extract(endianness)?;
        Ok(Point { x, y })
    }
}

impl ::tarrasque::Span for Point {
    const SPAN: usize = 4;
}

Generics and Lifetimes

The following code is an example of the usage of the extract! macro with generics and lifetimes.

use tarrasque::{Extract, Span, extract};

extract! {
    /// A pair of values.
    pub struct Pair<'s, T>[2 * T::SPAN] where T: Extract<'s, ()> + Span {
        pub bytes: &'s [u8] = &stream[..],
        pub left: T = [],
        pub right: T = [],
    }
}

Note: As shown above, the lifetime 's must be used to refer to the lifetime of the stream.