diff --git a/src/tools/fs.rs b/src/tools/fs.rs index 447583b9..d3144ffa 100644 --- a/src/tools/fs.rs +++ b/src/tools/fs.rs @@ -4,7 +4,7 @@ use std::borrow::{Borrow, BorrowMut}; use std::ops::{Deref, DerefMut}; use std::os::unix::io::{AsRawFd, RawFd}; -use failure::Error; +use failure::*; use nix::dir; use nix::dir::Dir; @@ -125,3 +125,65 @@ pub fn scan_subdir<'a, P: ?Sized + nix::NixPath>( } })) } + +/// Helper trait to provide a combinators for directory entry iterators. +pub trait FileIterOps +where + Self: Sized + Iterator>, + T: Borrow, + E: Into + Send + Sync, +{ + /// Filter by file type. This is more convenient than using the `filter` method alone as this + /// also includes error handling and handling of files without a type (via an error). + fn filter_file_type(self, ty: dir::Type) -> FileTypeFilter { + FileTypeFilter { inner: self, ty } + } +} + +impl FileIterOps for I +where + I: Iterator>, + T: Borrow, + E: Into + Send + Sync, +{ +} + +/// This filters files from its inner iterator by a file type. Files with no type produce an error. +pub struct FileTypeFilter +where + I: Iterator>, + T: Borrow, + E: Into + Send + Sync, +{ + inner: I, + ty: nix::dir::Type, +} + +impl Iterator for FileTypeFilter +where + I: Iterator>, + T: Borrow, + E: Into + Send + Sync, +{ + type Item = Result; + + fn next(&mut self) -> Option { + loop { + let item = self.inner.next()?.map_err(|e| e.into()); + match item { + Ok(ref entry) => match entry.borrow().file_type() { + Some(ty) => { + if ty == self.ty { + return Some(item); + } else { + continue; + } + } + None => return Some(Err(format_err!("unable to detect file type"))), + }, + Err(_) => return Some(item), + } + } + } +} +