标签: rust-proc-macros

如何以编程方式获取结构的字段数?

我有一个自定义结构,如下所示:

struct MyStruct {
    first_field: i32,
    second_field: String,
    third_field: u16,
}
Run Code Online (Sandbox Code Playgroud)

是否有可能以编程方式获取结构字段的数量(例如,通过方法调用field_count()):

let my_struct = MyStruct::new(10, "second_field", 4);
let field_count = my_struct.field_count(); // Expecting to get 3
Run Code Online (Sandbox Code Playgroud)

对于这个结构:

struct MyStruct2 {
    first_field: i32,
}
Run Code Online (Sandbox Code Playgroud)

......以下电话应该返回1:

let my_struct_2 = MyStruct2::new(7);
let field_count = my_struct2.field_count(); // Expecting to get count 1
Run Code Online (Sandbox Code Playgroud)

有没有像这样的API field_count()或者只能通过宏获得它?

如果使用宏可以实现这一点,那么应该如何实现?

struct rust rust-macros rust-proc-macros

20
推荐指数
2
解决办法
1886
查看次数

如何使用引用宏报告过程宏中的错误?

我正在编写一个程序宏,它工作正常,但我无法以符合人体工程学的方式报告错误.使用panic!"工作"但不优雅,并且不会很好地向用户显示错误消息.

我知道我可以在解析a时报告错误TokenStream,但是在解析之后我需要在遍历AST时产生错误.

宏调用如下所示:

attr_test! {
    #[bool]
    FOO
}
Run Code Online (Sandbox Code Playgroud)

并应输出:

const FOO: bool = false;
Run Code Online (Sandbox Code Playgroud)

这是宏代码:

extern crate proc_macro;
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::{Attribute, parse_macro_input, Ident, Meta};

struct AttrTest {
    attributes: Vec<Attribute>,
    name: Ident,
}

impl Parse for AttrTest {
    fn parse(input: ParseStream) -> Result<Self> {
        Ok(AttrTest {
            attributes: input.call(Attribute::parse_outer)?,
            name: input.parse()?,
        })
    }
}

#[proc_macro]
pub fn attr_test(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let test: AttrTest = parse_macro_input!(tokens);
    let name = test.name;
    let first_att …
Run Code Online (Sandbox Code Playgroud)

error-handling rust rust-macros rust-proc-macros

10
推荐指数
2
解决办法
615
查看次数

在实现 proc 宏时,如何检查类型是否实现了特征?

我正在尝试创建一个proc-macro派生和实现结构的特征,并且我需要结构中的所有字段都实现Display

我该如何检查?

此外,我如何检查属性是否Iterator也实现了?(我想处理迭代器的项目是否也实现了显示)。

我正在使用synquote板条箱。我设法解析struct并生成实现。但对于像Vec和这样的类型Option,我想检查他们是否Iterator正确实现和处理它。

syn::Field结构具有ty我认为应该作为起点的属性,但是查看文档我无法猜测任何方法来检查此类型是否实现了某种特征。

rust rust-proc-macros

10
推荐指数
1
解决办法
3419
查看次数

如何将 rustdoc 注释添加到 proc 宏生成的代码中?

我编写了一个proc-macro库来配合我正在编写的库 - 它们一起使用,前者用于抽象掉后者中的大量冗余代码。

我在 proc 宏中成功生成了多个结构和实现。我也在使用cargo doc该库,我的文档正是我所期望的。但是,我在 proc 宏中创建的文档注释未按预期工作。我的 proc 宏中的一些代码大致如下所示:

#[proc_macro_derive(MyDerive)]
pub fn derive(input: TokenStream) -> TokenStream {
    ...
    let expanded = quote! {
        ...
        impl #my_struct {
            /// This comment doesn't show up in documentation
            pub fn foo(&self, n: i32) -> bool {
               false
            }

            /// This comment DOES show up in documentation
            pub fn bar(n: i32) -> Vec<String> {
               ...
            }
        }
    }
    expanded.into()
}
Run Code Online (Sandbox Code Playgroud)

当我打开生成的文档时:

  • foo本身出现在文档中,但其注释没有
  • bar及其评论在文档中
  • 如果我更改 的评论bar …

rust rust-cargo rust-proc-macros

9
推荐指数
0
解决办法
1870
查看次数

如何在程序宏生成的代码中创建卫生标识符?

在编写声明性 ( macro_rules!) 宏时,我们会自动获得宏卫生。在这个例子中,我声明了一个f在宏中命名的变量并传入一个标识符f,该标识符成为一个局部变量:

macro_rules! decl_example {
    ($tname:ident, $mname:ident, ($($fstr:tt),*)) => {
        impl std::fmt::Display for $tname {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                let Self { $mname } = self;
                write!(f, $($fstr),*)
            }
        }
    }
}

struct Foo {
    f: String,
}

decl_example!(Foo, f, ("I am a Foo: {}", f));

fn main() {
    let f = Foo {
        f: "with a member named `f`".into(),
    };
    println!("{}", f);
}
Run Code Online (Sandbox Code Playgroud)

这段代码可以编译,但是如果查看部分展开的代码,您会发现存在明显的冲突:

impl std::fmt::Display …
Run Code Online (Sandbox Code Playgroud)

macros hygiene rust rust-proc-macros

8
推荐指数
2
解决办法
1643
查看次数

在其他宏内部/之前调用宏

我创建了一个类似函数的程序宏。我用声明性宏作为参数来调用它。我希望找到一种在处理过程宏之前扩展声明性宏的方法(或在过程宏内部扩展它)。示例(代码也可在https://github.com/Jasperav/rec_macro获取):

致电网站:

macro_rules! t {
    ($e:expr) => {
        $e.to_string() + " I am a macro"
    }
}

fn main() {
    re!(t!("hi"));
}
Run Code Online (Sandbox Code Playgroud)

过程宏箱:

#[proc_macro_hack]
pub fn re(input: TokenStream) -> TokenStream {
    panic!("{:#?}", input) // I can see "hi" and something like t!, but not the result of the macro expansion
}
Run Code Online (Sandbox Code Playgroud)

panic消息中,我看到声明性宏 ( t) 位于其中。我只想要这种情况下的原始值hi I am a macro(或某种syn类型)。就我而言,声明性宏应始终扩展为 a&strString

是否可以t在调用之前展开,或者在 proc 宏内手动re展开? …

rust rust-proc-macros

7
推荐指数
0
解决办法
1735
查看次数

将枚举变体用作函数的奇怪语法是什么?

下面是mod文档给出的例子syn::parse

enum Item {
    Struct(ItemStruct),
    Enum(ItemEnum),
}

struct ItemStruct {
    struct_token: Token![struct],
    ident: Ident,
    brace_token: token::Brace,
    fields: Punctuated<Field, Token![,]>,
}

impl Parse for Item {
    fn parse(input: ParseStream) -> Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(Token![struct]) {
            input.parse().map(Item::Struct)    // <-- here
        } else if lookahead.peek(Token![enum]) {
            input.parse().map(Item::Enum)      // <-- and here
        } else {
            Err(lookahead.error())
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

input.parse().map(Item::Struct)有效的普通 Rust 语法(看起来不是Item::Struct函数),还是库的一种特殊语法proc_macro?如果是后者,是否有proc_macro具体语法规则的文档?

rust rust-proc-macros

6
推荐指数
1
解决办法
1268
查看次数

是否可以判断一个字段是否是某种类型或在过程宏中实现某种方法?

我创建了一个实现特征的程序宏,但为了使其工作,我需要获取每个字段的原始字节。问题是如何获取字段的字节取决于字段的类型。

有没有某种方法可以测试某个函数是否存在于某个字段以及它是否不尝试另一个函数?

例如这样的事情:

if item.field::function_exist {
    //do code
} else {
    //do other code
}
Run Code Online (Sandbox Code Playgroud)

目前,我正在考虑创建另一个特征/成员函数,我只需为所有原语创建它,并为更大的字段(例如结构)创建一个程序宏。例如:

if item.field::as_bytes().exists {
    (&self.#index).as_bytes()
} else {
    let bytes = (&self.#index).to_bytes();
    &bytes
}
Run Code Online (Sandbox Code Playgroud)

对于字符串,它有as_bytes成员函数,而对于字符串则i32没有。这意味着当结构的成员字段不是字符串时,我需要额外的代码。我可能需要 amatch而不是 an if,但是if对于这个例子来说就足够了。

rust rust-proc-macros

6
推荐指数
1
解决办法
2971
查看次数

如何创建类似函数的程序宏?

应该如何a_proc_macro定义以便它“返回”一个 5?

fn main() {
    let a = a_proc_macro!();
    assert!(a == 5);
}
Run Code Online (Sandbox Code Playgroud)

rust rust-macros rust-proc-macros

6
推荐指数
1
解决办法
2360
查看次数

我们可以在过程宏属性中获取调用者的源代码位置吗?

我需要获取每个方法的调用者的源位置。我正在尝试创建一个proc_macro_attribute来捕获位置并打印它。

#[proc_macro_attribute]
pub fn get_location(attr: TokenStream, item: TokenStream) -> TokenStream {
    // Get and print file!(), line!() of source
    // Should print line no. 11
    item
}
Run Code Online (Sandbox Code Playgroud)
#[get_location]
fn add(x: u32, y: u32) -> u32 {
    x + y
}

fn main() {
    add(1, 5); // Line No. 11
}
Run Code Online (Sandbox Code Playgroud)

rust rust-macros rust-proc-macros

6
推荐指数
2
解决办法
2589
查看次数