我正在过程宏上下文中寻找file!()
和module_path!()
的等效项。
例如,以下操作无效:
file.rs
:
#[some_attribute]
const A: bool = true;
macro.rs
:
#[proc_macro_attribute]
pub fn some_attribute(attr: TokenStream, input: TokenStream) -> TokenStream {
println!("{}", file!());
input
}
此打印的macro.rs
有意义,但我想要的是file.rs
。有没有办法做到这一点? module_path!()
也有类似的方法吗?
对此的要求是必须在编译时进行。
我正在尝试在OUT_DIR
中创建一个包含常量值的文件,该属性随模块及其所在的文件一起添加。
这里的问题是println!("{}", file!());
是在编译时执行的,而不是在运行时执行的。类似于最近给定的here答案,您可以编辑原始函数并将代码插入其开头,这将在runtime处执行。您仍然可以使用过程宏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(); }
请注意,代码已添加之前函数主体内部的内容。我们可以在末尾插入它,但是这将打破返回不带分号的值的可能性。