use std::path::PathBuf;
use crate::parser::DocumentFormat;
use super::types::{IndexMode, IndexOptions};
#[derive(Debug, Clone)]
pub(crate) enum IndexSource {
Path(PathBuf),
Content {
data: String,
format: DocumentFormat,
},
Bytes {
data: Vec<u8>,
format: DocumentFormat,
},
}
impl IndexSource {
pub fn format(&self) -> Option<DocumentFormat> {
match self {
IndexSource::Path(_) => None,
IndexSource::Content { format, .. } => Some(*format),
IndexSource::Bytes { format, .. } => Some(*format),
}
}
pub fn is_path(&self) -> bool {
matches!(self, IndexSource::Path(_))
}
pub fn is_content(&self) -> bool {
matches!(self, IndexSource::Content { .. })
}
pub fn is_bytes(&self) -> bool {
matches!(self, IndexSource::Bytes { .. })
}
}
#[derive(Debug, Clone)]
pub struct IndexContext {
pub(crate) source: IndexSource,
pub(crate) name: Option<String>,
pub(crate) options: IndexOptions,
}
impl IndexContext {
pub fn from_path(path: impl Into<PathBuf>) -> Self {
Self {
source: IndexSource::Path(path.into()),
name: None,
options: IndexOptions::default(),
}
}
pub fn from_content(content: impl Into<String>, format: DocumentFormat) -> Self {
Self {
source: IndexSource::Content {
data: content.into(),
format,
},
name: None,
options: IndexOptions::default(),
}
}
pub fn from_bytes(bytes: Vec<u8>, format: DocumentFormat) -> Self {
Self {
source: IndexSource::Bytes {
data: bytes,
format,
},
name: None,
options: IndexOptions::default(),
}
}
pub fn with_name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn with_options(mut self, options: IndexOptions) -> Self {
self.options = options;
self
}
pub fn with_mode(mut self, mode: IndexMode) -> Self {
self.options.mode = mode;
self
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
pub fn options(&self) -> &IndexOptions {
&self.options
}
}
impl From<PathBuf> for IndexContext {
fn from(path: PathBuf) -> Self {
Self::from_path(path)
}
}
impl From<&std::path::Path> for IndexContext {
fn from(path: &std::path::Path) -> Self {
Self::from_path(path.to_path_buf())
}
}
impl From<&str> for IndexContext {
fn from(path: &str) -> Self {
Self::from_path(path)
}
}
impl From<String> for IndexContext {
fn from(path: String) -> Self {
Self::from_path(path)
}
}
impl std::fmt::Display for IndexSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IndexSource::Path(p) => write!(f, "path:{}", p.display()),
IndexSource::Content { format, .. } => write!(f, "content:{}", format.extension()),
IndexSource::Bytes { format, .. } => write!(f, "bytes:{}", format.extension()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_path() {
let ctx = IndexContext::from_path("./test.md");
assert!(ctx.source.is_path());
assert!(ctx.name.is_none());
}
#[test]
fn test_from_content() {
let ctx = IndexContext::from_content("# Title", DocumentFormat::Markdown);
assert!(ctx.source.is_content());
assert!(ctx.name.is_none());
}
#[test]
fn test_from_bytes() {
let ctx = IndexContext::from_bytes(vec![1, 2, 3], DocumentFormat::Pdf);
assert!(ctx.source.is_bytes());
}
#[test]
fn test_with_name() {
let ctx = IndexContext::from_path("./test.md").with_name("My Document");
assert_eq!(ctx.name(), Some("My Document"));
}
#[test]
fn test_with_mode() {
let ctx = IndexContext::from_path("./test.md").with_mode(IndexMode::Force);
assert_eq!(ctx.options.mode, IndexMode::Force);
}
#[test]
fn test_chaining() {
let ctx = IndexContext::from_content("<html>", DocumentFormat::Html)
.with_name("page")
.with_mode(IndexMode::Force);
assert!(ctx.source.is_content());
assert_eq!(ctx.name(), Some("page"));
assert_eq!(ctx.options.mode, IndexMode::Force);
}
#[test]
fn test_from_path_trait() {
let ctx = IndexContext::from(PathBuf::from("./test.md"));
assert!(ctx.source.is_path());
}
#[test]
fn test_source_format() {
let content_source = IndexSource::Content {
data: "test".to_string(),
format: DocumentFormat::Html,
};
assert_eq!(content_source.format(), Some(DocumentFormat::Html));
let path_source = IndexSource::Path(PathBuf::from("./test.md"));
assert_eq!(path_source.format(), None);
}
}