Проблема здесь в том, что println!("{}", file!());
выполняется в время компиляции , а не во время выполнения. Подобно ответу, который недавно был дан здесь , вы можете отредактировать исходную функцию и вставить свой код в ее начало, которое будет выполнено в время выполнения на этот раз. Вы все еще можете использовать процедурные макросы file!()
и module_path!()
. Вот macro.rs
с таким подходом:
#[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()
}
Вы можете использовать его следующим образом в main.rs
:
use mylib::some_attribute;
#[some_attribute]
fn yo() -> () { println!("yo"); }
fn main() { yo(); }
Обратите внимание, что код добавляется перед что находится внутри тела функции. Мы могли бы вставить его в конце, но это лишило бы возможности возврата значения без точки с запятой.
РЕДАКТИРОВАТЬ: Позже понял, что OP хочет, чтобы он работал во время время компиляции .