现在proc_macros
have been stabilized,一个人如何创造这样的东西?
根据我所看到的,可以选择在#[proc_macro_attribute]
上放置一个fn whatsitsname(attrs: TokenStream, code: TokenStream) -> TokenStream
注释,但是我该如何注册?如何添加自定义属性?
答案 0 :(得分:3)
Rust编译器具有相当完整的test suite。在寻找新功能的示例时,我经常从这里开始:
$ rg -c proc_macro_attribute
src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs:2
src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs:1
[... 35 other matches ...]
这是一个完整的示例:
$ tree
.
├── Cargo.toml
├── my_macro
│ ├── Cargo.toml
│ ├── src
│ │ └── lib.rs
└── src
└── main.rs
Cargo.toml
我们对宏定义板条箱添加了依赖性。
[package]
name = "foo"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
[dependencies]
my_macro = { path = "my_macro" }
src / main.rs
我们导入属性宏并将其添加到函数中。
#[macro_use]
extern crate my_macro;
#[log_entry_and_exit(hello, "world")]
fn this_will_be_destroyed() -> i32 {
42
}
fn main() {
dummy()
}
my_macro / Cargo.toml
我们将crate_type
指定为proc_macro
。
[package]
name = "my_macro"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
[lib]
crate_type = ["proc-macro"]
my_macro / src / lib.rs
我们向应该为宏的每个函数添加#[proc_macro_attribute]
。
extern crate proc_macro;
use proc_macro::*;
#[proc_macro_attribute]
pub fn log_entry_and_exit(args: TokenStream, input: TokenStream) -> TokenStream {
let x = format!(r#"
fn dummy() {{
println!("entering");
println!("args tokens: {{}}", {args});
println!("input tokens: {{}}", {input});
println!("exiting");
}}
"#,
args = args.into_iter().count(),
input = input.into_iter().count(),
);
x.parse().expect("Generated invalid tokens")
}
货物运行
entering
args tokens: 3
input tokens: 7
exiting
“困难”部分是将TokenStream
整理成有用的东西,然后输出同样有用的东西。包装箱syn和quote是这两项任务的当前黄金标准。 macros chapter of The Rust Programming Language和API documentation都涵盖了与TokenStream
的交易。
还有#[proc_macro]
,它具有以下形式的功能:
#[proc_macro]
pub fn the_name_of_the_macro(input: TokenStream) -> TokenStream
并且可以作为the_name_of_the_macro!(...)
调用。
答案 1 :(得分:2)
如果我正确理解RFC 1566,则您:
创建类型为proc_macro
的板条箱,即其Cargo.toml
应该包含
[lib]
proc-macro = true
在该板条箱中,创建以#[proc_macro_attribute]
注释的实现。函数式宏的#[proc_macro]
和自定义派生的#[proc_macro_derive]
的工作原理相同,只是它们只有一个TokenStream
参数。这些是在proc_macro
板条箱中定义的。
第一个令牌流是属性中的参数,第二个是注释项的主体。
然后在要使用宏的板条箱中,只需依赖proc_macro条板箱和
使用#[macro_use]
属性(#[macro_use] extern crate
...)导入。
那应该足够了。
appendix in Book应该扩展为提及#[proc_macro_derive]
之后的其他proc宏类型。可能不是错误。