下面是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具体语法规则的文档?
我尝试实现Dump类似于serdes的proc_macro Serialize。
为了这个目的,我有一个箱子foo包含我的“原始”结构(P1和P2在这种情况下),这应该只是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)
我不知道正确的方法是什么,如何在此板条箱中使用依赖项。我当前的是:

这当然是不可能的。
我想念什么?我该怎么做才能打破依赖圈?
/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) 我正在尝试编写一个类似函数的过程宏my_macro,该宏可扩展为lazy_static宏调用。我想以一种用户不需要my_macro在lazy_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) 我正在尝试为我的特征实现自定义派生宏,它们确实有效!
但是我有一个小问题。我似乎找不到一种方法来将通用参数包含到特征中。
具体来说,我想做这样的事情: #[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)
如您所见,我在引用块中包含了固定的'a、V和E,而不是我想要实现的目标,即能够使用我想要的泛型类型灵活地派生特征。
我想要的是类似于这样的东西:
#[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) 我正在处理一个程序宏,该宏需要一个位置来在运行它的系统上存储状态。cargo clean运行时应清除状态。
过去,我假设target目录是正确的位置。但是,我的假设可能不正确,因为:
rustc和冲突cargo。为了避免这些问题,我一直在尝试确定一种正确定位位置的方法,但是并没有成功。我找到的最接近的是OUT_DIRCargo为构建脚本设置的环境变量,不幸的是,它没有为程序宏运行设置。
请注意,此问题不是“ 是否可以在Rust的程序宏中存储状态?”的重复项。。这个问题通常涵盖程序宏状态,而这个问题是关于在包装箱的文件结构中确定合适的位置。
我正在开发一个程序宏,它做了很多工作,可以大大减慢编译速度。所做的工作不会影响函数的语义;也就是说,如果给定相同的参数集,则返回值不会根据是否应用宏而改变。
为了使编辑-比较-测试循环更快,我想根据与包的编译方式相关的条件使宏成为无操作。我希望能够特别确定两个属性:
Cargo公开构建脚本的优化级别(通过环境变量OPT_LEVEL和PROFILE),但不公开模式(构建、文档等)。然而,这些信息似乎都没有暴露给程序宏。
我有一个 proc-macro 箱,其中有一个宏,当扩展时,需要使用 Rust 内置类型的自定义特征实现。我试图在同一个板条箱中定义该特征,但 Rust 告诉我,一个 proc-macro 板条箱只能有公共宏(用 注释的函数#[proc_macro]),其他任何东西都不能是公共的。因此,我将该特征放入另一个板条箱中,并将其作为依赖项包含在 proc-macro 板条箱中。但这意味着任何想要使用我的 proc-macro 板条箱的人也必须依赖于其他特征板条箱。
所以我想知道是否有一种方法可以向 proc-macro 板条箱添加公共特征,或者以其他方式使 proc-macro 和特征板条箱以某种方式链接起来,以便最终用户无法尝试在没有另一个的情况下使用一个?如果两者都不可行,唯一的解决方案是记录依赖关系,这有点脆弱。
我正在尝试编写将接受 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) 我有一个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 macro(attribute macro作者是)中的数据
我正在实现一个 proc 宏,并在另一个板条箱中进行测试。当我编译客户端包时,proc 宏的调用站点抛出错误:
error: proc macro panicked
--> foo/src/main.rs:17:1
Run Code Online (Sandbox Code Playgroud)
该错误发生在 proc 宏实现中。
这个错误不是很有帮助,因为它没有指出具体失败的地方。可以使用唯一的错误消息来找出它,但是作为跟踪的一部分,在 proc 宏实现中获得错误起源的确切文件和行号会简单得多。
有什么办法可以实现这一点吗?
rust ×10
rust-proc-macros ×10
macros ×2
rust-cargo ×2
enums ×1
rust-crates ×1
rust-macros ×1
traits ×1