use crate::domain::Document;
use crate::ZeroOneOrMany;
use std::marker::PhantomData;
use std::path::Path;
pub struct File;
pub struct Files;
pub struct Directory;
pub struct Github;
pub trait ContextSource: Send + Sync + 'static {
fn into_documents(self) -> ZeroOneOrMany<Document>;
}
pub struct Context<T> {
_phantom: PhantomData<T>,
source: Box<dyn ContextSource>,
}
impl<T> Context<T> {
fn new(source: impl ContextSource) -> Self {
Self {
_phantom: PhantomData,
source: Box::new(source),
}
}
}
impl Context<File> {
pub fn of(path: impl AsRef<Path>) -> Self {
Self::new(FileContext {
path: path.as_ref().to_path_buf(),
})
}
}
struct FileContext {
path: std::path::PathBuf,
}
impl ContextSource for FileContext {
fn into_documents(self) -> ZeroOneOrMany<Document> {
ZeroOneOrMany::One(Document::from_file(self.path).load())
}
}
impl Context<Files> {
pub fn glob(pattern: impl AsRef<str>) -> Self {
Self::new(FilesContext {
pattern: pattern.as_ref().to_string(),
})
}
}
struct FilesContext {
pattern: String,
}
impl ContextSource for FilesContext {
fn into_documents(self) -> ZeroOneOrMany<Document> {
glob::glob(&self.pattern)
.ok()
.map(|paths| {
let docs: Vec<Document> = paths
.filter_map(Result::ok)
.map(|path| Document::from_file(path).load())
.collect();
ZeroOneOrMany::from_vec(docs)
})
.unwrap_or(ZeroOneOrMany::None)
}
}
impl Context<Directory> {
pub fn of(path: impl AsRef<Path>) -> Self {
Self::new(DirectoryContext {
path: path.as_ref().to_path_buf(),
})
}
}
struct DirectoryContext {
path: std::path::PathBuf,
}
impl ContextSource for DirectoryContext {
fn into_documents(self) -> ZeroOneOrMany<Document> {
std::fs::read_dir(&self.path)
.ok()
.map(|entries| {
let docs: Vec<Document> = entries
.filter_map(Result::ok)
.filter_map(|entry| {
let path = entry.path();
if path.is_file() {
Some(Document::from_file(path).load())
} else {
None
}
})
.collect();
ZeroOneOrMany::from_vec(docs)
})
.unwrap_or(ZeroOneOrMany::None)
}
}
impl Context<Github> {
pub fn glob(pattern: impl AsRef<str>) -> Self {
Self::new(GithubContext {
pattern: pattern.as_ref().to_string(),
})
}
}
struct GithubContext {
pattern: String,
}
impl ContextSource for GithubContext {
fn into_documents(self) -> ZeroOneOrMany<Document> {
ZeroOneOrMany::None
}
}
unsafe impl<T> Send for Context<T> {}
unsafe impl<T> Sync for Context<T> {}