Difference between metavariables within Rust macro_rules

113 Views Asked by At

I wrote a macro but now I am trying to extend it so I can pass it a function. I read the Rust Reference and I don't really understand metavariables. I feel like everything I want is going to be an expression, but how can I pass error to an expression without breaking everything?

macro_rules! unwrap_or_return {
    ( $a:expr, $b:expr ) => {
        match $a {
            Ok(x) => x,
            Err(_) => return Err($b),
        }
    };
    // new part
    ( $a:expr, $fun:FUNCTION ) => {
        match $a {
            Ok(x) => x,
            Err(error) => return Err($fun(error)),
        }
    };
}
1

There are 1 best solutions below

0
On BEST ANSWER
macro_rules! unwrap_or_return {
    // This needs to go fist since is's more specific version of expression branch below would
    // make this one unreachable if preceded.
    //
    // What I ve done here is something that looks like a closure to the user and is probably what
    // you want. The metavariables are something predefined by rust and they simply capture some
    // portion of syntax. In this case, $p captures a closure or function parameter syntax which we
    // can inject into error pattern. Since the $p is written  by the user, the identifier is
    // visible to to other code made by user.
    ($a:expr, |$p:pat_param| $body:expr) => {
        match $a {
            Ok(x) => x,
            Err($p) => return Err($body.into()),
        }
    };

    ($a:expr, $b:expr) => {
        match $a {
            Ok(x) => x,
            Err(_) => return Err($b.into()),
        }
    };
}

fn example() -> Result<(), String> {
    let a = Ok::<usize, String>(1);
    let b = Err("error".to_string());

    let _x = unwrap_or_return!(a, "error");
    let _y = unwrap_or_return!(b, |e| format!("error: {}", e));

    Ok(())
}