How to write a macro that displays the file and line number and a variable number of arguments?

2.9k views Asked by At

I've found several useful macros in Rust, namely: file!(), line!(), stringify!() I've also found that Rust allows macros with variable arguments, as stated here:

macro_rules! print_all {
    ($($args:expr),*) => {{
        $(
            println!("{}", $args);
        )*
    }}
}

My goal is to somehow combine all those macros inside one which I will use during troubleshooting/debugging. So calling trace! macro on the following example:

let a: i32 = 1;
let b: i32 = 2;
trace!(a,b)

should expand to something like this:

println!("TRACE: file: {}, line: {}, a: {}, b: {}", file!(), line!(), a, b);

Is it possible? If yes, how would such a macro work?

1

There are 1 answers

0
Peter Hall On

You could do something like this:

macro_rules! trace {
    ($($args: expr),*) => {
        print!("TRACE: file: {}, line: {}", file!(), line!());
        $(
            print!(", {}: {}", stringify!($args), $args);
        )*
        println!(""); // to get a new line at the end
    }
}

There is likely a small overhead to calling print! multiple times, since each call will result in a system call and will also check for IO errors. However, constructing a single formatting string for arbitrary arguments would need a procedural macro, which I think is beyond the scope of the question.

You could also use a BufWriter to limit it to a single system call, but it might not be worth the effort.