Expand description
This crate facilitates processing an iterator of some Result
type.
It provides the same functionality provided by
Itertools::process_results
,
hence the name, but with a more much ergonomic interface, some extra
helper methods and a macro to reduce boiler-plate.
At a high level this crate is composed of 3 items: an extension trait IterResult
that is
implemented for all iterators of Result
type, Fallible
struct that
wraps the iterator, and ErrorCollector
that stores the errors.
IterResult
is an extension trait that contains methods that consumes itself and wrap it
with Fallible
and appropriate the error collector.
Fallible
has methods Fallible::process
and Fallible::process_no_discard
that accept a closure, which allows the caller to process an impl Iterator<Item = Result<T, E>>
as an impl Iterator<Item = T>
and to handle the errors in a composable manner.
ErrorCollector
is a trait that let the implementor determine how errors are stored, whether
or not an error shall stop the iteration, as well as how should errors be returned.
Implementations are provided for common types like
Option
and Vec
to allow the iteration to stop and
return the first error encountered and return, or to finish the iteration and stop all errors
in a Vec
. Unit struct Ignore
is also provided that ignores all the errors encountered.
§Examples
§Simple Iteration
use process_results::IterResult;
let v = vec![Ok(1i64), Ok(4), Ok(-3), Err("Error"), Ok(10)];
let res: Result<i64, _> = v.into_iter().failfast().process(|it| it.sum());
assert_eq!(res, Err("Error"));
§Accumulate Errors
use process_results::IterResult;
let v = vec![
Ok(1i64),
Err("Error1"),
Ok(4),
Ok(-3),
Err("Error2"),
Ok(10),
];
let res: Result<i64, _> = v
.into_iter()
.accumulate()
.process(|it| it.sum());
assert_eq!(res, Err(vec!["Error1", "Error2"]));
§Nested Errors
Here is an example that read lines from files in a folder, parse each line as i32
while saving the lines that cannot be parsed successfully.
use process_results::*;
use process_results::fallible;
use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
let res_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("res");
let res_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("res");
let (sum, err) = res_dir
.read_dir()
.unwrap()
.failfast()
.process(|it| {
it.filter(|entry| entry.file_type().map_or(false, |t| t.is_file()))
.map(|entry| {
File::open(entry.path())
.map(BufReader::new)
.map(|f| (entry.file_name(), f))
})
.failfast()
.process(|it| {
it.flat_map(|(name, f)| {
f.lines()
.enumerate()
.map(move |(ln_no, ln)| ln.map(|ln| (name.clone(), ln_no, ln)))
})
.failfast()
.process(|it| {
it.map(|(name, ln_no, ln)| {
ln.parse::<i32>().map_err(|_e| {
format!("{}-{}: {}", name.to_string_lossy(), ln_no + 1, ln)
})
})
.accumulate()
.process_no_discard::<_, i32>(|it| it.sum())
})
})
})
.unwrap()
.unwrap()
.unwrap();
assert_eq!(sum, 11966);
assert_eq!(
err.unwrap(),
vec![
"test1.txt-7: sadfs",
"test2.txt-3: 1000000000000000000000000000000000000000000000000000000000",
"test2.txt-6: hello world",
"test2.txt-8: 1.35"
]
);
§Nested Errors with Macro
The same code as the last one, but utilizing macro fallible!
.
use process_results::*;
use process_results::fallible;
use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
let res_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("res");
let (sum, err) = fallible!(
res_dir.read_dir().unwrap().failfast(),
|it| it
.filter(|entry| entry.file_type().map_or(false, |t| t.is_file()))
.map(|entry| File::open(entry.path()).map(BufReader::new)
.map(|f| (entry.file_name(), f))).failfast(),
|it| it.flat_map(
|(name, f)| f.lines()
.enumerate()
.map(move |(ln_no, ln)| ln.map(|ln| (name.clone(), ln_no, ln)))
).failfast(),
|it| it
.map(
|(name, ln_no, ln)| ln.parse::<i32>()
.map_err(|_e| format!("{}-{}: {}", name.to_string_lossy(), ln_no + 1, ln))
)
.accumulate(),
no_discard i32: |it| it.sum()
).unwrap().unwrap().unwrap();
assert_eq!(sum, 11966);
assert_eq!(
err.unwrap(),
vec![
"test1.txt-7: sadfs",
"test2.txt-3: 1000000000000000000000000000000000000000000000000000000000",
"test2.txt-6: hello world",
"test2.txt-8: 1.35"
]
);
Modules§
Macros§
- fallible
- A macro used to reduce boilerplate when nesting multiple calls to
process
orprocess_no_discard
inside each other.
Structs§
Traits§
- Iter
Result - An extension trait implemented for all iterators of
Result
types.