[英]How do I create a proc_macro_attribute?
Now that proc_macros
have been stabilized , how does one create such a thing? 现在proc_macros
已稳定下来 ,如何创建这样的东西?
From what I've seen, there's the option of putting a #[proc_macro_attribute]
annotation on a fn whatsitsname(attrs: TokenStream, code: TokenStream) -> TokenStream
, but how can I register it? 从我所看到的,可以在fn whatsitsname(attrs: TokenStream, code: TokenStream) -> TokenStream
上放置#[proc_macro_attribute]
批注,但是我该如何注册? How can I add custom attributes? 如何添加自定义属性?
The Rust compiler has a fairly complete test suite . Rust编译器具有相当完整的测试套件 。 When looking for examples of newly-introduced features, I frequently start there: 在寻找新功能的示例时,我经常从这里开始:
$ 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 ...]
Here's a fully worked example: 这是一个完整的示例:
$ tree
.
├── Cargo.toml
├── my_macro
│ ├── Cargo.toml
│ ├── src
│ │ └── lib.rs
└── src
└── main.rs
Cargo.toml 货物清单
We add a dependency on our macro-defining crate. 我们添加了对宏定义板条箱的依赖。
[package]
name = "foo"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
[dependencies]
my_macro = { path = "my_macro" }
src/main.rs src / main.rs
We import the attribute macro and add it to a function. 我们导入属性宏并将其添加到函数中。
#[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 my_macro / Cargo.toml
We specify crate_type
as proc_macro
. 我们将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 my_macro / src / lib.rs
We add #[proc_macro_attribute]
to each function that should be a macro. 我们将#[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")
}
cargo run 货物运行
entering
args tokens: 3
input tokens: 7
exiting
The "hard" part is wrangling the TokenStream
into something useful and then outputting something equally useful. “困难”部分是将TokenStream
成有用的东西,然后输出同样有用的东西。 The crates syn and quote are the current gold standards for those two tasks. 包装箱syn和quote是这两项任务的当前黄金标准。 Dealing with TokenStream
is covered in the macros chapter of The Rust Programming Language as well as API documentation . Rust编程语言的宏一章以及API文档中 介绍了如何处理TokenStream
。
There's also #[proc_macro]
, which takes functions of the form: 还有#[proc_macro]
,它采用以下形式的函数:
#[proc_macro]
pub fn the_name_of_the_macro(input: TokenStream) -> TokenStream
And can be invoked as the_name_of_the_macro!(...)
. 可以作为the_name_of_the_macro!(...)
调用。
If I understand RFC 1566 correctly, you: 如果我正确理解RFC 1566 ,则您:
Create a crate of type proc_macro
, ie its Cargo.toml
should contain 创建一个类型为proc_macro
的板条箱,即其Cargo.toml
应该包含
[lib] proc-macro = true
In that crate, create the implementation, annotated with #[proc_macro_attribute]
. 在该板条箱中,创建带有#[proc_macro_attribute]
注释的实现。 The #[proc_macro]
for function-like macros and #[proc_macro_derive]
for custom derives work the same, except they only have one TokenStream
argument. #[proc_macro]
函数的宏的#[proc_macro_derive]
针对自定义函数的#[proc_macro_derive]
的派生工作相同,只是它们只有一个TokenStream
参数。 These are defined in the proc_macro
crate. 这些在proc_macro
板条箱中定义。
The first token stream is the arguments in the attribute, the second is the body of the annotated item. 第一个令牌流是属性中的参数,第二个令牌流是带注释项的主体。
Then in the crate that wants to use the macro, simply depend on the proc_macro crate and import it with #[macro_use]
attribute ( #[macro_use] extern crate
…). 然后,在要使用该宏的板条箱中,只需依赖proc_macro板条箱,并使用#[macro_use]
属性( #[macro_use] extern crate
…)将其导入。
That should be enough. 那应该足够了。
The appendix in Book should be extended to mention the other proc macro types beyond #[proc_macro_derive]
. 本书的附录应扩展为提及#[proc_macro_derive]
以外的其他proc宏类型。 That it does not is probably a bug. 可能不是错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.