Last active
November 13, 2017 15:48
-
-
Save matklad/9ccac802025f80d62bf0225f484ef1f0 to your computer and use it in GitHub Desktop.
Extension traits to work with Rust Iterators of Results conveniently
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use result_iterator::ResultIterator; | |
use std::fs::{self, DirEntry}; | |
use std::io; | |
use std::path::Path; | |
fn file_names(path: &Path) -> Result<Vec<String>, io::Error> { | |
let result = fs::read_dir(path)? | |
.map_then(|entry| { | |
let is_file = entry.file_type()?.is_file(); | |
Ok((entry, is_file)) | |
}) | |
.filter_ok(|&(_, is_file)| is_file) | |
.map_ok(|(entry, _)| entry.file_name().into_string().unwrap()) | |
.collect::<Result<Vec<_>, _>>()?; | |
Ok(result) | |
} | |
fn main() { | |
for path in file_names(Path::new(".")).expect("failed to read directory contents") { | |
println!("{}", path); | |
} | |
} | |
mod result_iterator { | |
pub trait ResultIterator<R, E>: Iterator<Item=Result<R, E>> { | |
fn map_ok<B, F>(self, f: F) -> MapOk<Self, F> | |
where Self: Sized, F: FnMut(R) -> B | |
{ | |
MapOk { iter: self, f: f } | |
} | |
fn filter_ok<F>(self, f: F) -> FilterOk<Self, F> | |
where Self: Sized, F: FnMut(&R) -> bool | |
{ | |
FilterOk { iter: self, f: f } | |
} | |
fn map_then<B, F>(self, f: F) -> MapThen<Self, F> | |
where Self: Sized, F: FnMut(R) -> Result<B, E> | |
{ | |
MapThen { iter: self, f: f } | |
} | |
} | |
impl<R, E, T> ResultIterator<R, E> for T where T: Iterator<Item=Result<R, E>> {} | |
pub struct MapOk<I, F> { | |
iter: I, | |
f: F, | |
} | |
impl<I, F, R1, R2, E> Iterator for MapOk<I, F> | |
where I: Iterator<Item=Result<R1, E>>, | |
F: FnMut(R1) -> R2 | |
{ | |
type Item = Result<R2, E>; | |
fn next(&mut self) -> Option<Self::Item> { | |
let f = &mut self.f; | |
self.iter.next().map(|r| r.map(f)) | |
} | |
} | |
pub struct MapThen<I, F> { | |
iter: I, | |
f: F, | |
} | |
impl<I, F, R1, R2, E> Iterator for MapThen<I, F> | |
where I: Iterator<Item=Result<R1, E>>, | |
F: FnMut(R1) -> Result<R2, E> | |
{ | |
type Item = Result<R2, E>; | |
fn next(&mut self) -> Option<Self::Item> { | |
let f = &mut self.f; | |
self.iter.next().map(|r| r.and_then(f)) | |
} | |
} | |
pub struct FilterOk<I, F> { | |
iter: I, | |
f: F, | |
} | |
impl<I, F, R1, E> Iterator for FilterOk<I, F> | |
where I: Iterator<Item=Result<R1, E>>, | |
F: FnMut(&R1) -> bool | |
{ | |
type Item = Result<R1, E>; | |
fn next(&mut self) -> Option<Self::Item> { | |
let f = &mut self.f; | |
while let Some(result) = self.iter.next() { | |
match result { | |
Err(e) => return Some(Err(e)), | |
Ok(x) => if f(&x) { | |
return Some(Ok(x)); | |
}, | |
} | |
} | |
None | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment