1#![doc = include_str!("../README.md")]
2
3use std::error::Error;
4use std::ffi::OsStr;
5use std::fs::{DirEntry, OpenOptions};
6use std::io::Read;
7use std::path::Path;
8use std::{fs, io};
9
10pub fn visit_files<P, E>(
16 dir: P,
17 extensions: &[&str],
18 cb: &mut dyn FnMut(&DirEntry) -> Result<(), E>,
19) -> Result<(), E>
20where
21 P: AsRef<Path>,
22 E: Error + From<io::Error>,
23{
24 for entry in fs::read_dir(dir.as_ref())? {
25 let entry = entry?;
26 let path = entry.path();
27 if path.is_dir() {
28 visit_files(&path, extensions, cb)?;
29 } else {
30 let ext = path.extension();
31 if extensions
32 .iter()
33 .any(|expected| Some(OsStr::new(expected)) == ext)
34 {
35 cb(&entry)?;
36 }
37 }
38 }
39 Ok(())
40}
41
42pub fn visit_files_contents<P, E>(
48 dir: P,
49 extensions: &[&str],
50 cb: &mut dyn FnMut(&DirEntry, String) -> Result<(), E>,
51) -> Result<(), E>
52where
53 P: AsRef<Path>,
54 E: Error + From<io::Error>,
55{
56 visit_files(dir, extensions, &mut |file| {
57 let mut content = String::new();
58 OpenOptions::new()
59 .read(true)
60 .open(file.path())?
61 .read_to_string(&mut content)?;
62 cb(file, content)
63 })?;
64 Ok(())
65}