如何创建 proc_macro_attribute? [英] How do I create a proc_macro_attribute?

查看:41
本文介绍了如何创建 proc_macro_attribute?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在 proc_macros 已经稳定了,如何创造这样的东西?

Now that proc_macros have been stabilized, how does one create such a thing?

据我所知,可以选择在 fn whatsitsname(attrs: TokenStream, code: TokenStream) 上添加 #[proc_macro_attribute] 注释 ->TokenStream,但是如何注册呢?如何添加自定义属性?

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? How can I add custom attributes?

推荐答案

Rust 编译器有一个相当完整的 测试套件.在寻找新引入功能的示例时,我经常从那里开始:

The Rust compiler has a fairly complete test suite. 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 ...]

这是一个完整的例子:

$ tree
.
├── Cargo.toml
├── my_macro
│   ├── Cargo.toml
│   ├── src
│   │   └── lib.rs
└── src
    └── main.rs

Cargo.toml

我们添加了对定义宏的 crate 的依赖.

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

我们导入属性宏并将其添加到函数中.

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

我们将 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] 添加到每个应该是宏的函数中.

We add #[proc_macro_attribute] to each function that should be a macro.

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 转换成有用的东西,然后输出同样有用的东西.板条箱 synquote 是这两项任务的当前黄金标准.处理 TokenStream 包含在 宏章节Rust 编程语言 以及 API文档.

The "hard" part is wrangling the TokenStream into something useful and then outputting something equally useful. The crates syn and quote are the current gold standards for those two tasks. Dealing with TokenStream is covered in the macros chapter of The Rust Programming Language as well as API documentation.

还有 #[proc_macro],它采用以下形式的函数:

There's also #[proc_macro], which takes functions of the form:

#[proc_macro]
pub fn the_name_of_the_macro(input: TokenStream) -> TokenStream

并且可以作为 the_name_of_the_macro!(...) 调用.

And can be invoked as the_name_of_the_macro!(...).

这篇关于如何创建 proc_macro_attribute?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆