I just discovered that Result FromIterator collection inversion nests to an arbitrary depth
I wrote this little utility function for Advent of Code (given how many puzzles require parsing input line-by-line):
pub fn parse_items<I, O, E>(input: I) -> impl Iterator<Item = io::Result<Result<O, E>>>
where
I: BufRead,
O: FromStr<Err = E>,
{
input.lines().filter_map(|line| {
let line = match line {
Ok(line) => line,
Err(e) => return Some(Err(e)),
};
let line = line.trim();
if line.is_empty() {
None
} else {
Some(Ok(line.parse()))
}
})
}
And it turns out that this use of it is completely legal:
let numbers: io::Result<Result<Vec<Line>, Error>> = aoc::parse_items(input).collect();
let numbers = numbers??;
It makes sense, given the FromIterator impl:
impl<A, E, V> FromIterator<Result<A, E>> for Result<V, E> where
V: FromIterator<A>,
Because Result<Vec<Line>> impls FromIterator<Result<Line>> and therefore io::Result<Result<Vec<Line>>> impls FromIterator<io::Result<Result<Line>>, but it's still kind of mind-bending to think about.