rust 如何创建proc_macro_attribute?

cdmah0mi  于 2023-04-30  发布在  Mac
关注(0)|答案(2)|浏览(265)

现在,proc_macroshave been stabilized,一个人如何创造这样的东西?
根据我所看到的,可以在fn whatsitsname(attrs: TokenStream, code: TokenStream) -> TokenStream上添加#[proc_macro_attribute]注解,但是我如何注册它呢?如何添加自定义属性?

ndasle7k

ndasle7k1#

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

货物清单

我们在宏定义的crate上添加一个依赖项。

[package]
name = "foo"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]

[dependencies]
my_macro = { path = "my_macro" }

**src/ www.example.com 我们

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

#[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/ www.example.com 我们

我们将#[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转换成有用的东西,然后输出同样有用的东西。板条箱synquote是这两项任务的当前黄金标准。处理TokenStreammacros chapter of The Rust Programming LanguageAPI documentation中有介绍。
还有#[proc_macro],它接受以下形式的函数:

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

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

3ks5zfa0

3ks5zfa02#

如果我正确理解了RFC 1566,您:

  • 创建一个proc_macro类型的crate,i。即其Cargo.toml应该包含
[lib]
proc-macro = true
  • 在该crate中,创建用#[proc_macro_attribute]注解的实现。用于类函数宏的#[proc_macro]和用于自定义派生的#[proc_macro_derive]工作原理相同,只是它们只有一个TokenStream参数。这些在proc_macro crate中定义。

第一个标记流是属性中的参数,第二个标记流是注解项的主体。

  • 然后在想要使用宏的crate中,只需依赖于proc_macro crate并使用#[macro_use]属性(#[macro_use] extern crate ...).

应该够了
书中的附录应该扩展到提到#[proc_macro_derive]之外的其他proc宏类型。它没有可能是一个bug。

相关问题