use std::{fs, path::PathBuf, string::FromUtf8Error};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum FileLoaderError {
#[error("Invalid glob pattern: {0}")]
InvalidGlobPattern(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("Pattern error: {0}")]
PatternError(#[from] glob::PatternError),
#[error("Glob error: {0}")]
GlobError(#[from] glob::GlobError),
#[error("String conversion error: {0}")]
StringUtf8Error(#[from] FromUtf8Error),
}
loadable_trait!(Readable, FileLoaderError, String, read, read_with_path);
impl Readable for PathBuf {
fn read(self) -> Result<String, FileLoaderError> {
fs::read_to_string(self).map_err(FileLoaderError::IoError)
}
fn read_with_path(self) -> Result<(PathBuf, String), FileLoaderError> {
let contents = fs::read_to_string(&self);
Ok((self, contents?))
}
}
impl Readable for Vec<u8> {
fn read(self) -> Result<String, FileLoaderError> {
Ok(String::from_utf8(self)?)
}
fn read_with_path(self) -> Result<(PathBuf, String), FileLoaderError> {
let res = String::from_utf8(self)?;
Ok((PathBuf::from("<memory>"), res))
}
}
pub struct FileLoader<'a, T> {
iterator: Box<dyn Iterator<Item = T> + 'a>,
}
#[allow(private_bounds)] impl<'a, T: Readable + 'a> FileLoader<'a, T> {
pub fn read(self) -> FileLoader<'a, Result<String, FileLoaderError>> {
FileLoader {
iterator: Box::new(self.iterator.map(Readable::read)),
}
}
pub fn read_with_path(self) -> FileLoader<'a, Result<(PathBuf, String), FileLoaderError>> {
FileLoader {
iterator: Box::new(self.iterator.map(Readable::read_with_path)),
}
}
}
loader_scaffold!(FileLoader, FileLoaderError, dir: files_only);
loader_from_bytes!(FileLoader);
#[cfg(test)]
mod tests;