macro_loop 0.4.3

A macro for writing repetitive Rust code using loops, conditionals, and bindings
Documentation

Discontinued

This crate has been renamed to repetitive. Please use that instead.

See https://github.com/Noam2Stein/repetitive.

macro_loop

macro_loop is a macro for writing repetitive Rust code using loops, conditionals, and bindings.

This is similar to the paste, seq-macro and tt-call crates, but attempts to make it more readable and scalable.

macro_loop supports:

  • for loops - loops over list values which can be literals or identifiers.
  • if statements - declares a condition over fragments and only emits the body if the condition is met.
  • concat idents/strings - merges idents/string into one anywhere in the code.

These features together allow for simple, readable and scalable macro logic.

Examples

Concat:

macro_loop! {
    struct @[T ype];
}

// outputs:
// struct Type;
macro_loop! {
    fn main() {
        println!(@[concat _ "strings" => str]);

        // outputs:
        // println!("concat_strings");
    }
}

For loops:

macro_loop! {
    @for N in 2..=4 {
        struct @[Vec @N];
    }
}

// outputs:
// struct Vec2;
// struct Vec3;
// struct Vec4;
macro_loop! {
    // Generates combinations of T x N
    @for N in 2..=4, T in [bool, i32, f32] {
        struct @[@T x @N];
    }
}

// outputs:
// struct boolx2;
// struct boolx3;
// struct boolx4;
// struct i32x2;
// ...

If statements:

// Only prints if `$a` and `$b` are NOT equal.
macro_rules! not_equal {
    ($a:ident $b:ident) => {
        macro_loop! {
            @if $a != $b {
                println!("{}", stringify!($a != $b))
            }
        }
    };
}

fn main() {
    not_equal!(a a); // doesn't print
    not_equal!(a b); // does print
    not_equal!(b b); // doesn't print
}

Let statements:

#[derive(Debug, Clone, Copy)]
struct Vec4 {
    x: f32,
    y: f32,
    z: f32,
    w: f32,
}

// Declare all swizzle fns
impl Vec4 {
    macro_loop! {
        @let components = [x, y, z, w];

        @for X in @components, Y in @components, Z in @components, W in @components {
            pub fn @[@X @Y @Z @W](self) -> Vec4 {
                Vec4 { x: self.@X, y: self.@Y, z: self.@Z, w: self.@W }
            }
        }
    }
}

Patterns:

fn main() {
    macro_loop! {
        @for [KEY, VALUE] in [["one", 1], ["two", 2], ["three", 3]] {
            println!("{} => {}", @KEY, @VALUE);
        }
    }
}