3 个版本
0.1.2 | 2022 年 9 月 17 日 |
---|---|
0.1.1 | 2022 年 8 月 22 日 |
0.1.0 | 2022 年 8 月 22 日 |
#1978 in Rust 模式
120KB
1K SLoC
fused_error
一个用于处理可组合错误的简单库。
文档
用法
将此添加到您的 Cargo.toml
[dependencies]
fused_error = "0.1"
以下是一个简单示例,演示了可组合错误的强大功能
use std::{
num::{IntErrorKind, ParseIntError},
iter::Sum,
str::FromStr
};
use fused_error::{Accumulator, FusedResult, IteratorExt};
/// Take an iterator of textual data, adding up all of the parsed numbers.
///
/// Unlike the standard way of returning a `Result<N, N::Err>`, this doesn't
/// short-circuit, it keeps track of the current sum, and reports any
/// further diagnostics past the first failure.
fn calculate_sum<N, E, I>(iter: I) -> FusedResult<N, N::Err>
where
N: FromStr + Sum,
E: AsRef<str>,
I: IntoIterator<Item = E>,
{
// Error accumulators collect errors to defer handling them, providing
// more holistic diagnostics:
let mut acc = Accumulator::new();
let sum = iter
.into_iter()
.map(|item| item.as_ref().parse::<N>())
// `fused_error` adds certain methods to iterators; no more
// disrupting iterator chains and `collect` hells for results!
.accumulate(&mut acc)
.sum();
// fused results let you easily pass around error accumulators and
// are perfect for cases where a yielded "ok" value and an error case
// aren't mutually exclusive.
FusedResult::new(sum, acc)
}
let result: FusedResult<i32, _> = calculate_sum(["1", "2", "3", "4"]);
assert_eq!(result.value(), &10);
assert_eq!(result.errors(), []);
let result: FusedResult<i8, _> = calculate_sum(["", "-129", "foo", "128"]);
assert_eq!(result.value(), &0);
assert_eq!(
result
.errors()
.into_iter()
.map(|err| err.kind().clone())
.collect::<Vec<_>>(),
[
IntErrorKind::Empty,
IntErrorKind::NegOverflow,
IntErrorKind::InvalidDigit,
IntErrorKind::PosOverflow,
],
);
let result: FusedResult<u8, _> = calculate_sum(["-1", "", "0", "1"]);
assert_eq!(result.value(), &1);
assert_eq!(
result
.errors()
.into_iter()
.map(|err| err.kind().clone())
.collect::<Vec<_>>(),
[IntErrorKind::InvalidDigit, IntErrorKind::Empty],
);
或者,当使用 syn
功能以增强互操作性时,以下是一个 fused_error
在过程宏中提供帮助的示例
use fused_error::{Accumulator, FusedError};
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use syn::{AttributeArgs, DeriveInput, ItemFn};
#[proc_macro_attribute]
pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
fn inner(args: TokenStream, input: TokenStream) -> syn::Result<TokenStream2> {
let mut acc = Accumulator::<syn::Error>::new();
// fn(TokenStream) -> syn::Result<AttributeArgs>
let args = acc.handle(parse_args(args));
let item = acc.handle(syn::parse::<ItemFn>(input));
// Throw all of the collected parse errors, or continue:
acc = acc.checkpoint()?;
// SAFETY: any `None` value would short-circuit at the last
// checkpoint.
let mut args = unsafe { args.unwrap_unchecked() };
let mut item = unsafe { item.unwrap_unchecked() };
// fn(&AttributeArgs) -> syn::Result<()>
acc.handle(validate_args(&args));
// fn(&ItemFn) -> syn::Result<()>
acc.handle(validate_item(&item));
// Throw all of the validation parse errors, or continue:
acc = acc.checkpoint()?;
// Do multiple steps that can short-circuit:
let tokens = acc.handle_in(|| {
// fn(&mut AttributeArgs, &mut ItemFn) -> syn::Result<()>
prepare(&mut args, &mut item)?;
// fn(AttributeArgs, ItemFn) -> syn::Result<TokenStream2>
expand(args, item)
});
// If this closure is called, we know `tokens` is `Some`:
acc.err_or_else(|| unsafe { tokens.unwrap_unchecked() })
}
inner(args, input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
许可证
许可协议为以下之一:
- Apache 许可证 2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则任何有意提交以包含在作品中的贡献,如 Apache-2.0 许可证中定义,均应按上述方式双重许可,而无需任何附加条款或条件。
依赖项
~0–355KB