use std::ffi::OsStr; use std::fs; use std::io; use std::path::{Path, PathBuf}; pub struct Walkdir { dirs: Vec, } impl Walkdir { pub fn new>(root: P) -> io::Result { let root = root.as_ref(); let dirs = vec![root.read_dir()?]; Ok(Walkdir { dirs }) } pub fn with_ext, const N1: usize, const N2: usize>( self, include: [S; N1], exclude: [S; N2], ) -> io::Result> { let dir = self; Ok(Walkext { dir, include, exclude }) } pub fn next(&mut self) -> io::Result> { match self.dirs.pop() { None => Ok(None), Some(mut dir) => match dir.next() { None => self.next(), Some(entry) => { self.dirs.push(dir); match entry { Err(err) => Err(err), Ok(file) => match file.path() { path if path.ends_with("testdata") => self.next(), path if path.is_file() => Ok(Some(path)), path if path.is_dir() => { let dir2 = path.read_dir()?; self.dirs.push(dir2); return self.next(); } _ => self.next(), }, } } }, } } } pub struct Walkext, const N1: usize, const N2: usize> { dir: Walkdir, include: [S; N1], exclude: [S; N2], } impl, const N1: usize, const N2: usize> Walkext { pub fn next(&mut self) -> io::Result> { while let Some(file) = self.dir.next()? { if !self.include.iter().any(|ext| { // TODO: find better way to compare path extension let ext = ext.as_ref().to_str().unwrap(); let filename = file.to_str().unwrap(); return filename.ends_with(ext); }) { continue; } if self.exclude.iter().any(|ext| { let ext = ext.as_ref().to_str().unwrap(); let filename = file.to_str().unwrap(); return filename.ends_with(ext); }) { continue; } return Ok(Some(file)); } Ok(None) } } #[cfg(test)] mod tests { use super::Walkdir; use std::env; use std::fs; use std::io; #[test] fn list_files() -> io::Result<()> { let temp = env::temp_dir(); let dir = temp.join("walkdir_test"); fs::create_dir_all(&dir)?; println!("list all files..."); let mut walk = Walkdir::new(&dir)?; while let Ok(Some(path)) = walk.next() { println!("{:?}", path); } println!("list go files..."); let mut walk = Walkdir::new(&dir)?.with_ext(["go"], [])?; while let Ok(Some(path)) = walk.next() { println!("{:?}", path); } Ok(()) } }