The problem here is that println!("{}", file!());
is executed at compile time and not at runtime. Similar to an answer that was recently given here, you can edit the original function and insert your code at the beginning of it, which will be executed at runtime this time. You can still use the procedural macros file!()
and module_path!()
. Here is a macro.rs
with this approach:
#[proc_macro_attribute]
pub fn some_attribute(_attr: TokenStream, input: TokenStream) -> TokenStream {
// prefix to be added to the function's body
let mut prefix: TokenStream = "
println!(\"Called from {:?} inside module path {:?}\",
file!(), module_path!());
".parse().unwrap();
// edit TokenStream
input.into_iter().map(|tt| {
match tt {
TokenTree::Group(ref g) // match function body
if g.delimiter() == proc_macro::Delimiter::Brace => {
// add logic before function body
prefix.extend(g.stream());
// return new function body as TokenTree
TokenTree::Group(proc_macro::Group::new(
proc_macro::Delimiter::Brace, prefix.clone()))
},
other => other, // else just forward
}
}).collect()
}
You can use it like this in your main.rs
:
use mylib::some_attribute;
#[some_attribute]
fn yo() -> () { println!("yo"); }
fn main() { yo(); }
Note that the code is added before what's inside of the function's body. We could have inserted it at the end, but this would break the possibility of returning a value without a semicolon.
EDIT: Later realized that the OP wants it to run at compile time.