Skip to content

Instantly share code, notes, and snippets.

@matklad
Last active November 13, 2017 15:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matklad/9ccac802025f80d62bf0225f484ef1f0 to your computer and use it in GitHub Desktop.
Save matklad/9ccac802025f80d62bf0225f484ef1f0 to your computer and use it in GitHub Desktop.
Extension traits to work with Rust Iterators of Results conveniently
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