use displaydoc::Display;
use std::{ffi, fs, io, path};
use thiserror::Error;
#[derive(Debug, Display, Error)]
pub enum DirReadError {
DirReadFailed(io::Error),
CouldNotReadEntry(io::Error),
NonUnicodeFilename(ffi::OsString),
}
pub fn read_dir_matching<P: AsRef<path::Path>>(
root: P,
filter: ®ex::Regex,
) -> Result<Vec<path::PathBuf>, DirReadError> {
let base = root.as_ref();
let mut paths = Vec::new();
for dir_result in fs::read_dir(base).map_err(DirReadError::DirReadFailed)? {
let dir_entry = dir_result.map_err(DirReadError::CouldNotReadEntry)?;
let filename = dir_entry
.file_name()
.into_string()
.map_err(DirReadError::NonUnicodeFilename)?;
if filter.is_match(&filename) {
paths.push(base.join(filename));
}
}
paths.sort();
Ok(paths)
}
#[derive(Debug)]
pub enum FlattenResult<I, E> {
Failed(Option<E>),
Inner(I),
}
pub trait FlattenResultsIter {
type Iter;
type Error;
fn flatten_results(self) -> FlattenResult<Self::Iter, Self::Error>;
}
impl<T, I, E> FlattenResultsIter for ::std::result::Result<I, E>
where
I: Iterator<Item = ::std::result::Result<T, E>>,
{
type Iter = I;
type Error = E;
fn flatten_results(self) -> FlattenResult<Self::Iter, Self::Error> {
match self {
Ok(inner) => FlattenResult::Inner(inner),
Err(e) => FlattenResult::Failed(Some(e)),
}
}
}
impl<T, I, E> Iterator for FlattenResult<I, E>
where
I: Iterator<Item = ::std::result::Result<T, E>>,
{
type Item = ::std::result::Result<T, E>;
fn next(&mut self) -> Option<Self::Item> {
match self {
FlattenResult::Failed(err) => err.take().map(Err),
FlattenResult::Inner(inner) => inner.next(),
}
}
}