How can I consolidate a macro that utilizes tt fragments for variations of input?


#1

I needed to create some tests for my project where a function call would return a vector, and I needed to verify the right items are coming back in that vector (and the right # of items). This was littering my code with really long assert_eq!() calls.

To make matters worse there were some times when I did not really want to do a full equality check but I actually needed to do a pattern match, including saving off one of the properties. The use case was I needed to check that the 2nd event matched Event::Abc { id: _, ref name} if name == &"hi" while at the same time saving off the id value to use in the next step in the check (but I don’t want to hardcode what the expected ID value is because it can be anything, it just needs to work for the next stage of the test).

So I spent all day working on (and probably bothered a lot of helpful people on IRC) the following macro to solve this: https://gist.github.com/KallDrexx/6d5112715a0fc29d46353188078ec725

This allows me to do:

fn main() {
    let test1 = Test::Value1 { v1: 5, v2: "test".to_string() };
    let test2 = Test::Value1 { v1: 8, v2: "test2".to_string() };
    let test3 = Test::Value1 { v1: 8, v2: "test3".to_string() };
    let test4 = Test::Value1 { v1: 8, v2: "test4".to_string() };
    let vector = vec![test2, test1, test3, test4];
    
    let result;
    
    assert_vec_match!(vector,
        Test::Value1 { v1: _, ref v2} if v2 == "test2",
        Test::Value1 { v1, ref v2} if v2 == "test" => {result = v1},
        Test::Value1 { v1: 8, v2: _} => (),
        Test::Value1 { v1: 8, v2: _},
    );
   
    println!("{}", result); // prints 5
}

The only issue with this is there is a lot of redundancy in that macro. Each format a pattern may be in one of the 4 formats (as shown in the example) but they can be in any order.

Is there any good way to consolidate the logic in the macro at all?