bomboni_fs/
lib.rs

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
10/// Recursively visits files in a directory with specified extensions.
11///
12/// # Errors
13///
14/// Returns an error if directory reading fails or the callback returns an error.
15pub 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
42/// Recursively visits files in a directory and reads their contents.
43///
44/// # Errors
45///
46/// Returns an error if directory reading fails, file reading fails, or callback returns an error.
47pub 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}