Crate fused_error

Source
Expand description

A simple library for working with composable errors.

§Examples

Basic usage:

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],
);

§Features

So far, there is only one opt-in feature: syn. Enabling this feature implements FusedError on syn::Error, as that was one of the main motivations for creating this library.

§Motivation

syn already has great composable errors that you combine with syn::Error::combine. Also, darling has a great system that was the primary inspiration for error accumulators and their drop mechanic. However, of course, darling’s accumulators are only to be used with darling errors and their accumulator API is far more limited to reflect this.

The original use case for this crate, deferring and collecting multiple errors, is primarily helpful in parsing: the more diagnostics you can provide in one pass limits the need of frequently changing something, building, fixing the one error, and trying again.

Modules§

accumulated
Working with remote error types using Accumulated<E>.
accumulator
Error accumulation via Accumulator<E>.
iter
Extending iterator functionality with IteratorExt.
prelude
A prelude to import the main items exported by this library:
result
Assigning error accumulators to working values with FusedResult<T, E>.

Structs§

Accumulated
A thin wrapper to handle remote error types as if they implemented FusedError.
Accumulator
An error accumulator.
FusedResult
A result type that links an Accumulator<E> with a persistently “ok” value of T.

Traits§

FusedError
Interface for error types that can store multiple error messages within one instance.
IntoResultParts
A trait for splitting a result value into its “ok” and “error” parts.
IteratorExt
Extends Iterator with methods for complex error handling:

Type Aliases§

PackedResult
A FusedResult<T, E> that can short-circuit with an error, dropping the “ok” value.