标签: rust-proc-macros

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

下面是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
查看次数

实现proc宏时循环依赖包

我尝试实现Dump类似于serdes的proc_macro Serialize

为了这个目的,我有一个箱子foo包含我的“原始”结构(P1P2在这种情况下),这应该只是dumpable。

接下来,我确实有一个foo_derive包含程序宏本身的板条箱。

因为我想支持多种格式,所以我有第三个板条箱foo_dump,其中包含trait定义Dump(例如,可以转储此结构)和Dumper(这是后端应实现的)。非常直截了当的到这一点。

现在,我想编译它时,出现以下错误:

$ cargo build
error: cyclic package dependency: package `foo v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo)` depends on itself. Cycle:
package `foo v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo)`
    ... which is depended on by `foo_dump v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo_dump)`
    ... which is depended on by `foo_derive v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo_derive)`
Run Code Online (Sandbox Code Playgroud)

我不知道正确的方法是什么,如何在此板条箱中使用依赖项。我当前的是:

依存关系

这当然是不可能的。

我想念什么?我该怎么做才能打破依赖圈?


mcve @ github

/Cargo.toml

[workspace]
members = [ 
    "foo",
    "foo_derive",
    "foo_dump",
]
Run Code Online (Sandbox Code Playgroud)

/foo/Cargo.toml

[package]
name …
Run Code Online (Sandbox Code Playgroud)

rust rust-macros rust-proc-macros

5
推荐指数
1
解决办法
202
查看次数

如何编写一个扩展为宏调用的过程宏,而不需要用户导入宏的包?

我正在尝试编写一个类似函数的过程宏my_macro,该宏可扩展为lazy_static宏调用。我想以一种用户不需要my_macrolazy_static其板条箱的依赖项中列出并显式使用它的方式编写它(use lazy_static::lazy_static)。

这是最小的示例代码:

lib.rs(my_macro 箱)

extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;

#[proc_macro]
pub fn my_macro(_item: TokenStream) -> TokenStream {
    quote!(
        lazy_static! {
            static ref EXAMPLE: u8 = 42;
        }
    ).into()
}
Run Code Online (Sandbox Code Playgroud)

Cargo.toml(my_macro 箱)

[package]
name = "my_macro"
version = "0.1.0"
edition = "2018"

[dependencies]
quote = "0.6"
lazy_static = "1.2.0"

[lib]
proc-macro = true
Run Code Online (Sandbox Code Playgroud)

lib.rs(使用包)

use my_macro::my_macro;
// use lazy_static::lazy_static;

my_macro!();

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn …
Run Code Online (Sandbox Code Playgroud)

macros rust rust-proc-macros

5
推荐指数
0
解决办法
777
查看次数

如何让我的自定义派生宏接受特征通用参数?

我正在尝试为我的特征实现自定义派生宏,它们确实有效!

但是我有一个小问题。我似乎找不到一种方法来将通用参数包含到特征中。

具体来说,我想做这样的事情: #[derive(MyCustomDerive<'a, B, C>)]

相反,现在我正在对泛型进行硬编码,如下所示:

let gen = quote! {
        impl #impl_generics Graph<'a, V, E> for #name #ty_generics #where_clause {
            fn Map(&self) -> &MAP<V, E> {
                &self.map
            }
            ...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我在引用块中包含固定的'aVE,而不是我想要实现的目标,即能够使用我想要的泛型类型灵活地派生特征。

我想要的是类似于这样的东西:

#[derive(MyCustomDerive<'a, B, C>)]

导致与此相同的事情

let gen = quote! {
        impl #impl_generics Graph<'a, B, C> for #name #ty_generics #where_clause {
            fn Map(&self) -> &MAP<B, C> {
                &self.map
            }
            ...
}
Run Code Online (Sandbox Code Playgroud)

这将允许我保留(当然如果有必要)V 和 E 用于其他事情,并且在我看来使代码更易于控制。感谢您的帮助!

更新 1:这就是我的派生函数的样子

pub fn derive(ast: …
Run Code Online (Sandbox Code Playgroud)

rust rust-proc-macros

5
推荐指数
1
解决办法
1617
查看次数

什么地方适合存储程序宏构件,以便通过“货物清理”进行清理?

我正在处理一个程序宏,该宏需要一个位置来在运行它的系统上存储状态。cargo clean运行时应清除状态。

过去,我假设target目录是正确的位置。但是,我的假设可能不正确,因为:

  1. 我的文件和目录可能与rustc和冲突cargo
  2. 目标目录的位置可以更改为默认值。

为了避免这些问题,我一直在尝试确定一种正确定位位置的方法,但是并没有成功。我找到的最接近的是OUT_DIRCargo为构建脚本设置的环境变量,不幸的是,它没有为程序宏运行设置。

请注意,此问题不是“ 是否可以在Rust的程序宏中存储状态?”的重复项。这个问题通常涵盖程序宏状态,而这个问题是关于在包装箱的文件结构中确定合适的位置。

rust rust-cargo rust-proc-macros

5
推荐指数
1
解决办法
146
查看次数

如何在过程宏中确定编译属性?

我正在开发一个程序宏,它做了很多工作,可以大大减慢编译速度。所做的工作不会影响函数的语义;也就是说,如果给定相同的参数集,则返回值不会根据是否应用宏而改变。

为了使编辑-比较-测试循环更快,我想根据与包的编译方式相关的条件使宏成为无操作。我希望能够特别确定两个属性:

  1. 为什么执行宏:构建/运行、文档、测试
  2. 是否为优化构建而执行宏。

Cargo公开构建脚本的优化级别(通过环境变量OPT_LEVELPROFILE),但不公开模式(构建、文档等)。然而,这些信息似乎都没有暴露给程序宏。

rust rust-cargo rust-proc-macros

5
推荐指数
0
解决办法
249
查看次数

有没有办法在 proc-macro 箱中拥有公共特征?

我有一个 proc-macro 箱,其中有一个宏,当扩展时,需要使用 Rust 内置类型的自定义特征实现。我试图在同一个板条箱中定义该特征,但 Rust 告诉我,一个 proc-macro 板条箱只能有公共宏(用 注释的函数#[proc_macro]),其他任何东西都不能是公共的。因此,我将该特征放入另一个板条箱中,并将其作为依赖项包含在 proc-macro 板条箱中。但这意味着任何想要使用我的 proc-macro 板条箱的人也必须依赖于其他特征板条箱。

所以我想知道是否有一种方法可以向 proc-macro 板条箱添加公共特征,或者以其他方式使 proc-macro 和特征板条箱以某种方式链接起来,以便最终用户无法尝试在没有另一个的情况下使用一个?如果两者都不可行,唯一的解决方案是记录依赖关系,这有点脆弱。

traits rust rust-crates rust-proc-macros

5
推荐指数
1
解决办法
1825
查看次数

为什么 Rust 找不到使用 proc_macro_attribute 生成的枚举的方法?

我正在尝试编写将接受 Rust 枚举的程序宏,例如

#[repr(u8)]
enum Ty {
    A,
    B
}
Run Code Online (Sandbox Code Playgroud)

并为枚举生成一个方法,让我将 u8 转换为允许的变体,如下所示

fn from_byte(byte: u8) -> Ty {
    match {
        0 => Ty::A,
        1 => Ty::B,
        _ => unreachable!()
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我使用proc_macrolib实现的。(没有外部库)

#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_quote)]
extern crate proc_macro;

use proc_macro::{TokenStream, Diagnostic, Level, TokenTree, Ident, Group, Literal};
use proc_macro::quote;

fn report_error(tt: TokenTree, msg: &str) {
    Diagnostic::spanned(tt.span(), Level::Error, msg).emit();
}

fn variants_from_group(group: Group) -> Vec<Ident> {
    let mut iter = group.stream().into_iter();
    let mut res = vec![];
    while let Some(TokenTree::Ident(id)) = …
Run Code Online (Sandbox Code Playgroud)

enums rust rust-proc-macros

5
推荐指数
1
解决办法
340
查看次数

Proc宏执行顺序

我有一个proc macro看起来像这样的:

#[proc_macro_attribute]
pub fn my_macro(_meta: CompilerTokenStream, input: CompilerTokenStream) -> CompilerTokenStream { //* bits of code */ }
Run Code Online (Sandbox Code Playgroud)

然后我有一个derive macro

#[proc_macro_derive(Operations)]
pub fn operations(input: proc_macro::TokenStream) -> proc_macro::TokenStream { //* bits of code */ }
Run Code Online (Sandbox Code Playgroud)

是否可以使派生宏在属性一之后展开?

原因是我有一个箱子,里面有一些静态变量来跟踪数据。我需要读取derive macroattribute macro作者是)中的数据

macros rust rust-proc-macros

5
推荐指数
1
解决办法
1681
查看次数

有什么方法可以跟踪 proc 宏中发生错误的位置吗?

我正在实现一个 proc 宏,并在另一个板条箱中进行测试。当我编译客户端包时,proc 宏的调用站点抛出错误:

error: proc macro panicked
  --> foo/src/main.rs:17:1
Run Code Online (Sandbox Code Playgroud)

该错误发生在 proc 宏实现中。

这个错误不是很有帮助,因为它没有指出具体失败的地方。可以使用唯一的错误消息来找出它,但是作为跟踪的一部分,在 proc 宏实现中获得错误起源的确切文件和行号会简单得多。

有什么办法可以实现这一点吗?

rust rust-proc-macros

5
推荐指数
1
解决办法
2109
查看次数