22个版本 (5个稳定版)
1.0.4 | 2020年7月31日 |
---|---|
1.0.2 | 2020年4月9日 |
1.0.0 | 2020年3月25日 |
0.4.12 | 2020年3月23日 |
0.4.3 | 2019年11月7日 |
#1903 在 过程宏
每月下载量:4,190,081
在 13,587 个crate中使用(通过 proc-macro-error)
11KB
238 行
使过程宏的错误报告既简单又容易
这个crate旨在使过程宏中的错误报告简单易用。尽可能少地迁移基于 panic!
的错误!
此外,你可以显式地将一个虚拟令牌流附加到你的错误中。
为了实现这一点,这个crate作为 proc_macro::Diagnostic
和 compile_error!
的小型适配器。它根据编译器的版本检测发出错误的最佳方式。当底层诊断类型最终稳定时,这个crate将简单地委托给它,无需更改你的代码!
因此,你只需使用这个crate,就可以在稳定版之前提前获得 proc_macro::Diagnostic
的一些功能,并且让你的错误报告代码面向未来。
[dependencies]
proc-macro-error = "1.0"
支持rustc 1.31及以上版本
快速示例
代码
#[proc_macro]
#[proc_macro_error]
pub fn make_fn(input: TokenStream) -> TokenStream {
let mut input = TokenStream2::from(input).into_iter();
let name = input.next().unwrap();
if let Some(second) = input.next() {
abort! { second,
"I don't like this part!";
note = "I see what you did there...";
help = "I need only one part, you know?";
}
}
quote!( fn #name() {} ).into()
}
这是在终端中渲染错误的方式
这是你的用户将在他们的IDE中看到的内容
示例
类似panic的使用
use proc_macro_error::{
proc_macro_error,
abort,
abort_call_site,
ResultExt,
OptionExt,
};
use proc_macro::TokenStream;
use syn::{DeriveInput, parse_macro_input};
use quote::quote;
// This is your main entry point
#[proc_macro]
// This attribute *MUST* be placed on top of the #[proc_macro] function
#[proc_macro_error]
pub fn make_answer(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
if let Err(err) = some_logic(&input) {
// we've got a span to blame, let's use it
// This immediately aborts the proc-macro and shows the error
//
// You can use `proc_macro::Span`, `proc_macro2::Span`, and
// anything that implements `quote::ToTokens` (almost every type from
// `syn` and `proc_macro2`)
abort!(err, "You made an error, go fix it: {}", err.msg);
}
// `Result` has some handy shortcuts if your error type implements
// `Into<Diagnostic>`. `Option` has one unconditionally.
more_logic(&input).expect_or_abort("What a careless user, behave!");
if !more_logic_for_logic_god(&input) {
// We don't have an exact location this time,
// so just highlight the proc-macro invocation itself
abort_call_site!(
"Bad, bad user! Now go stand in the corner and think about what you did!");
}
// Now all the processing is done, return `proc_macro::TokenStream`
quote!(/* stuff */).into()
}
proc_macro::Diagnostic
类似的使用
use proc_macro_error::*;
use proc_macro::TokenStream;
use syn::{spanned::Spanned, DeriveInput, ItemStruct, Fields, Attribute , parse_macro_input};
use quote::quote;
fn process_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
attrs
.iter()
.filter_map(|attr| match process_attr(attr) {
Ok(res) => Some(res),
Err(msg) => {
emit_error!(attr, "Invalid attribute: {}", msg);
None
}
})
.collect()
}
fn process_fields(_attrs: &Fields) -> Vec<TokenStream> {
// processing fields in pretty much the same way as attributes
unimplemented!()
}
#[proc_macro]
#[proc_macro_error]
pub fn make_answer(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
let attrs = process_attrs(&input.attrs);
// abort right now if some errors were encountered
// at the attributes processing stage
abort_if_dirty();
let fields = process_fields(&input.fields);
// no need to think about emitted errors
// #[proc_macro_error] will handle them for you
//
// just return a TokenStream as you normally would
quote!(/* stuff */).into()
}
实际示例
structopt-derive
(类似abort的使用)auto-impl
(类似emit的使用)
限制
- 警告只在nightly上发出,在稳定版上被忽略。
- “帮助”建议在稳定版上不能有自己的span信息(本质上继承父span)。
- 如果你的宏意外触发panic,将不会显示任何错误。这不是技术限制,而是有意设计。
panic
不用于错误报告。
MSRV策略
proc_macro_error
将始终与 proc-macro 圣三角:proc_macro2
、syn
和 quote
库兼容。换句话说,如果您拥有这个圣三角 - 您也可以使用 proc_macro_error
。
重要!
如果您想使用
#[proc_macro_error]
与synstructure
一起,您必须在decl_derive!
调用内部放置该属性。不幸的是,由于 pre-1.34 rustc 中的一些错误,将 proc-macro 属性放置在宏调用内部不起作用,因此您的 MSRV 实际上是 1.34。
动机
proc-macros 中的错误处理很糟糕。目前的选择不多:要么将错误“向上冒泡”到宏的顶层并转换为 compile_error!
调用,要么使用古老的恐慌。这两种方式都很糟糕
-
前者很糟糕,因为对于会崩溃宏的临界错误来说,取消展开适当的错误处理是相当多余的;因此,人们通常选择不费心去处理它,而是使用恐慌。简单的
.expect
太诱人了。此外,如果您决定在您的宏中实现基于
Result
的架构,一旦proc_macro::Diagnostic
最终稳定,您将不得不完全重写它。这并不酷。 -
后者很糟糕,因为没有方法可以通过
panic!
来传递范围信息。rustc
会突出显示调用本身,但不会突出显示调用内的特定标记。此外,恐慌根本不是用于错误报告的;恐慌用于错误检测(例如在
None
上展开或超出范围的索引)或早期开发阶段,当时您需要尽快有一个原型,所以错误处理可以稍后再说。混合这些用法只会使事情变得更糟。 -
有一个
proc_macro::Diagnostic
,这是很棒的,但它已经实验了超过一年,不太可能很快稳定。这个库的 API 故意设计成与
proc_macro::Diagnostic
兼容,并在可能的情况下委托给它。一旦Diagnostics
稳定,这个库将 始终 委托给它,用户端无需进行代码更改。
话虽如此,我们需要一个解决方案,但这个解决方案必须满足以下条件
- 它必须比
panic!
更好。主要观点:它必须提供一种将范围信息传递给用户的方法。 - 它必须尽可能少地迁移到
panic!
。理想情况下,一个新的宏,具有类似的语义以及执行范围信息的能力。 - 它必须与
proc_macro::Diagnostic
保持兼容。 - 它必须在稳定版上可用.
该软件包旨在提供此类机制。您只需将顶层函数#[proc_macro]
注解为#[proc_macro_error]
属性,并将panic转换为适当的abort!
/abort_call_site!
,参见指南。
免责声明
请注意,本软件包的用途仅限于过程宏中的错误报告,对于其他任何用途,请使用Result
和?
(可能还需要使用许多辅助工具之一)。
许可证
根据您的选择,在Apache License, Version 2.0或MIT许可证下授权。除非您明确声明,否则您提交给本软件包的任何有意贡献,根据Apache-2.0许可证定义,均应按照上述方式双授权,不附加任何额外条款或条件。
lib.rs
:
这是用于与proc-macro-error
一起使用的#[proc_macro_error]
属性。就是这样。
依赖关系
~85KB