Module error_stream

Module error_stream 

Source
Expand description

Types, traits, and macros for working with non-empty streams of errors.

The ErrorStream<_> type provides a collection that stores a non-empty, unordered stream of errors. This is valuable for collecting as many errors as possible before returning them to the user, which allows the user to work through the errors in the order of their choosing. This is particularly useful for CLI tools.

Example usage:

use spacetimedb_data_structures::error_stream::{
    ErrorStream,
    CombineErrors,
    CollectAllErrors
};
use std::collections::HashSet;

enum MyError { /* ... */ };
type MyErrors = ErrorStream<MyError>;

type Name =
    /* ... */
    ;

type Age =
    /* ... */
    ;

fn validate_name(name: String) -> Result<Name, MyErrors> {
    // ...
}

fn validate_age(age: i32) -> Result<Age, MyErrors> {
    // ...
}

fn validate_person(
    name: String,
    age: i32,
    friends: Vec<String>
) -> Result<(Name, Age, HashSet<Name>), MyErrors> {
    // First, we perform some validation on various pieces
    // of input data, WITHOUT using `?`.
    let name: Result<Name, MyErrors> = validate_name(name);
    let age: Result<Age, MyErrors> = validate_age(age);

    // If we have multiple pieces of data, we can use
    // `collect_all_errors` to build an arbitrary collection from them.
    // If there are any errors, all of these errors
    // will be returned in a single ErrorStream.
    let friends: Result<HashSet<Name>, MyErrors> = friends
        .into_iter()
        .map(validate_name)
        .collect_all_errors();

    // Now, we can combine the results into a single result.
    // If there are any errors, they will be returned in a
    // single ErrorStream.
    let (name, age, friends): (Name, Age, HashSet<Name>) =
        (name, age, friends).combine_errors()?;

    Ok((name, age, friends))
}

§Best practices

§Use ErrorStream everywhere

It is best to use ErrorStream everywhere in a multiple-error module, even for methods that return only a single error. CombineAllErrors and CollectAllErrors can only be implemented for types built from Result<_, ErrorStream<_>> due to trait conflicts. ErrorStream uses a smallvec::SmallVec internally, so it is efficient for single errors.

You can convert an E to an ErrorStream<E> using .into().

§Not losing any errors

When using this module, it is best to avoid using ? until as late as possible, and to completely avoid using the Result<Collection<_>, _>::collect method. Both of these may result in errors being discarded.

Prefer using Result::and_then for chaining operations that may fail, and CollectAllErrors::collect_all_errors for collecting errors from iterators.

Macros§

expect_error_matching
Helper macro to match against an error stream, expecting a specific error. For use in tests. Panics if a matching error is not found. Multiple matches are allowed.

Structs§

ErrorStream
A non-empty stream of errors.

Traits§

CollectAllErrors
A trait for collecting errors from an iterator of results, returning all errors if anything failed.
CombineErrors
A trait for converting a tuple of Result<_, ErrorStream<_>>s into a Result of a tuple or combined ErrorStream.