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§
- Error
Stream - A non-empty stream of errors.
Traits§
- Collect
AllErrors - A trait for collecting errors from an iterator of results, returning all errors if anything failed.
- Combine
Errors - A trait for converting a tuple of
Result<_, ErrorStream<_>>s into aResultof a tuple or combinedErrorStream.