macro_rules! loadable_trait {
($Trait:ident, $Err:ty, $Out:ty, $get:ident, $get_with_path:ident) => {
pub(crate) trait $Trait {
fn $get(self) -> Result<$Out, $Err>;
fn $get_with_path(self) -> Result<(std::path::PathBuf, $Out), $Err>;
}
impl<T: $Trait> $Trait for Result<T, $Err> {
fn $get(self) -> Result<$Out, $Err> {
self.map(|t| t.$get())?
}
fn $get_with_path(self) -> Result<(std::path::PathBuf, $Out), $Err> {
self.map(|t| t.$get_with_path())?
}
}
};
}
macro_rules! loader_dir_doc {
(files_only) => {
"Creates a new loader on all files within a directory (ignores subdirectories)."
};
(all_entries) => {
"Creates a new loader on all entries within a directory. Entries are not \
filtered: a non-file entry's path is yielded too and surfaces as an error \
when loaded."
};
}
macro_rules! loader_dir_entries {
(files_only, $entries:expr, $Err:ty) => {
$entries.filter_map(|entry| {
let path = entry.ok()?.path();
if path.is_file() { Some(Ok(path)) } else { None }
})
};
(all_entries, $entries:expr, $Err:ty) => {
$entries.map(|entry| {
Ok(entry
.map_err($crate::loaders::file::FileLoaderError::IoError)
.map_err(<$Err>::from)?
.path())
})
};
}
macro_rules! loader_scaffold {
($Loader:ident, $Err:ty, dir: $dir_kind:ident $(, extra: $P:ident)?) => {
pub struct IntoIter<'a, T> {
iterator: Box<dyn Iterator<Item = T> + 'a>,
}
impl<'a, T $(, $P)?> IntoIterator for $Loader<'a, T $(, $P)?> {
type Item = T;
type IntoIter = IntoIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
iterator: self.iterator,
}
}
}
impl<T> Iterator for IntoIter<'_, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iterator.next()
}
}
impl<'a, T: 'a $(, $P)?> $Loader<'a, Result<T, $Err> $(, $P)?> {
pub fn ignore_errors(self) -> $Loader<'a, T $(, $P)?> {
$Loader {
iterator: Box::new(self.iterator.filter_map(|res| res.ok())),
$(_processor: std::marker::PhantomData::<$P>,)?
}
}
}
impl<'a $(, $P)?> $Loader<'a, Result<std::path::PathBuf, $Err> $(, $P)?> {
pub fn with_glob(
pattern: &str,
) -> Result<$Loader<'_, Result<std::path::PathBuf, $Err> $(, $P)?>, $Err> {
let paths = ::glob::glob(pattern)
.map_err($crate::loaders::file::FileLoaderError::PatternError)
.map_err(<$Err>::from)?;
Ok($Loader {
iterator: Box::new(paths.map(|path| {
path.map_err($crate::loaders::file::FileLoaderError::GlobError)
.map_err(<$Err>::from)
})),
$(_processor: std::marker::PhantomData::<$P>,)?
})
}
#[doc = loader_dir_doc!($dir_kind)]
pub fn with_dir(
directory: &str,
) -> Result<$Loader<'_, Result<std::path::PathBuf, $Err> $(, $P)?>, $Err> {
let entries = std::fs::read_dir(directory)
.map_err($crate::loaders::file::FileLoaderError::IoError)
.map_err(<$Err>::from)?;
Ok($Loader {
iterator: Box::new(loader_dir_entries!($dir_kind, entries, $Err)),
$(_processor: std::marker::PhantomData::<$P>,)?
})
}
}
};
}
macro_rules! loader_from_bytes {
($Loader:ident) => {
impl<'a> $Loader<'a, Vec<u8>> {
pub fn from_bytes(bytes: Vec<u8>) -> $Loader<'a, Vec<u8>> {
$Loader {
iterator: Box::new(vec![bytes].into_iter()),
}
}
pub fn from_bytes_multi(bytes_vec: Vec<Vec<u8>>) -> $Loader<'a, Vec<u8>> {
$Loader {
iterator: Box::new(bytes_vec.into_iter()),
}
}
}
};
}
pub mod file;
pub use file::FileLoader;
#[cfg(all(test, any(feature = "pdf", feature = "epub")))]
mod test_fixtures;
#[cfg(feature = "pdf")]
#[cfg_attr(docsrs, doc(cfg(feature = "pdf")))]
pub mod pdf;
#[cfg(feature = "pdf")]
pub use pdf::PdfFileLoader;
#[cfg(feature = "epub")]
#[cfg_attr(docsrs, doc(cfg(feature = "epub")))]
pub mod epub;
#[cfg(feature = "epub")]
pub use epub::{EpubFileLoader, RawTextProcessor, StripXmlProcessor, TextProcessor};