Determine the parameter type when calling a macro

Viewed 39

I have a macro with a path parameter and now I want to call it through a method. However I have a hard time figuring out the parameter type of the of the method parameter that would be passed as a macro parameter.

Below is simple repro. This example use case doesn't make sense but it shows my problem clearly.

Following works:

fn main() {
    let val  = get_value!(true, DataValue::Int).unwrap();
    println!("{}", val);
}

#[macro_export]
macro_rules! get_value {
    ( $rs: expr, $data_value_type: path ) => {{
        let rand_val = return_data_value($rs);

        if let $data_value_type(val) = rand_val {
            Ok(val)
        } else {
            Err("This would not work")
        }
    }};
}


fn return_data_value(random_select: bool) -> DataValue {
    if random_select {
        DataValue::Int(1)
    } else {
        DataValue::Float(2.3)
    }
}


enum DataValue {
    Int(i32),
    Float(f64),
    String(String),
    Bool(bool),
}

Now I want to create a function that calls the macro: (In the real world scenario this would be a much more complex one, but this shows the problem I have)

fn invoke_macro(random_select: bool, fun: <What type?>) -> i32 {
    get_value!(random_select, fun).unwrap()
}

So here, what is the type of the parameter fun should be? Whatever I did so far gave me following error:

error: expected tuple struct or tuple variant, found local variable `fun`
label: not a tuple struct or tuple variant

Compiler tells me that the type of $data_value_type (macro parameter) for this particular invocation is fn(i32) -> DataValue {DataValue::Int} but I don't know how I can use that to figure out the parameter type.

1 Answers

You cannot. Not every macro can be made into a function, since macros can do syntax transformations and functions cannot.

DataValue::Int (for instance) is a function, like any tuple struct/enum variant, and that's why the compiler says this is its type. This function allows you to create the variant, like in (playground):

#[derive(Debug)]
struct S(i32);

let f: fn(i32) -> S = S;
let s = f(123);
dbg!(s);

But here, you don't use it as a function, but rather for pattern matching. This does not have a type and cannot be expressed.

Related