3 个版本

0.1.2 2022 年 9 月 17 日
0.1.1 2022 年 8 月 22 日
0.1.0 2022 年 8 月 22 日

#1978 in Rust 模式

MIT/Apache

120KB
1K SLoC

fused_error

一个用于处理可组合错误的简单库。

Build Status Latest Version

文档

带有示例的模块文档.

用法

将此添加到您的 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 许可证中定义,均应按上述方式双重许可,而无需任何附加条款或条件。

依赖项

~0–355KB