[][src]Macro manger::consume_enum

macro_rules! consume_enum {
    (
        $enum_name:ident {
            $(
                $ident:ident => [
                    $(
                        $( $( $prop_name:ident )?: $cons_type:ty $( { $cons_condition:expr } )? )?
                        $( > $cons_expr:expr )?
                    ),*
                    ;
                    $(
                        ( $( $prop:expr ),* )
                    )?
                ]
            ),+
        }
    ) => { ... };
    ( @internal $enum_name:ident, $ident:ident, $( $prop_name:ident ),*, => ( $( $prop:expr ),* ) ) => { ... };
    ( @internal $enum_name:ident, $ident:ident, $( $prop_name:ident ),* ) => { ... };
}

A macro used for defining the way a enum should be consumed. It will implement Consumable for this enum.

Examples

use manger::consume_enum;

#[derive(PartialEq, Debug)]
enum HowManyFruits {
    HasBananas(u32),
    HasGrapes(u32),
    NotThisOne,
    Unknown
}
consume_enum! (
    HowManyFruits {
        HasBananas => [
            // Now a list of sequential instruction
            //
            // Note: We have a comma after every instruction, but we end
            // with a semicolon.

            // Consuming expression looks like `> EXPRESSION`
            > "bananas:",

            // Consuming arbitrary data from a certain type looks like `: TYPE`
            //
            // Here we use the build in Whitespace type of consume anytype
            // whitespace character.
            //
            // Note: Optionally, we can suffix a type with `{ Fn(data) -> bool }` to add
            // an extra condition for consuming. Therefore, if we would have wrote
            // `: char { |c| c.is_whitespace() }`, it would have had the same behaviour.
            : manger::common::Whitespace,

            // Saving data looks as such `KEY: TYPE`
            //
            // Note: Optionally, we can suffix a type with `{ Fn(data) -> bool }` to add
            // an extra condition for consuming. Therefore, if we could have suffixed
            // `{ |data| data >= 5 }`, we would require the `num_of_bananas` to be at
            // least 5.
            num_of_bananas: u32;

            // Now we can use all our saved data to define what to do
            // with that data.
            //
            // Since HasBananas takes a (u32) we have to fill such a data structure.
            (num_of_bananas)
        ],

        // We can do the same for another variant.
        HasGrapes => [
            > "grape boxes: ",
            num_of_grapes_boxes: u32,
            > ", grapes per box: ",
            num_of_grapes_per_box: u32;

            // Here we calculate how many grapes there are in total
            (num_of_grapes_boxes*num_of_grapes_per_box)
        ],
         
        // We can also add an catch-all clause.
        Unknown => [ > ""; ]

        // We can also have a variant we are not consuming to.
        // Here we are not consuming to the `HowManyBananas::NotThisOne` variant.
    }
);

// Now we can consume HowManyFruits as normal.
use manger::Consumable;

let source = "bananas: 5";
let (how_many_fruits, _) = <HowManyFruits>::consume_from(source)?;

assert_eq!(how_many_fruits, HowManyFruits::HasBananas(5));

Syntax

The syntax for the macro is not very complicated. Much of the intuition on the Rust primitive and std types can we reapplied and only a few new concepts have to be applied.

The ENBF syntax is as follows:

Please note that the syntax ignores interproduction rule

syntax = enum_name, "{",
            {(variant_definition, ",")}*,
            variant_definition,
         "}";

variant_definition = variant_name, "=>", "[",
                        {(instruction, ",")}*,
                        instruction, ";",
                        [ "(", RUST_EXPR*, ")" ], # RUST_EXPR is an arbitrary rust
                                                  # expression it can use all the RUST_IDENT
                                                  # defined in the previous section.
                     "]";

instruction = expr_instruction | type_instruction;

expr_instruction = ">", RUST_EXPR;    # RUST_EXPR is an arbitrary rust expression. It should
                                      # return a instance of a type that has the `Consumable`
                                      # trait.

type_instruction = [ RUST_IDENT ], ":", RUST_TYPE; # RUST_IDENT is an arbitrary rust identity
                                                   # an it will assigned to that property if no
                                                   # tuple syntax is defined.
                                                   # RUST_TYPE is an arbitrary rust type that
                                                   # implements `Consumable`.

Note

  1. Although this macro works without importing any manger traits, they will also not be imported afterwards. Importing traits should still be done if methods of the trait are supposed to be used afterwards.

  2. This macro assumed that we are in the same module as the enum mentioned was defined. Some undefined behaviour might occur if this macro is called outside of the module the enum was created.