use camino::Utf8PathBuf;
use serde::de::DeserializeOwned;
use thiserror::Error;
use crate::{
Globals, SiteConfig,
error::HauchiwaError,
loader::{File, GlobRegistryTask, Runtime},
task::Handle,
};
#[derive(Debug, Error)]
pub enum FrontmatterError {
#[error("UTF-8 conversion error: {0}")]
Utf8(#[from] std::str::Utf8Error),
#[error("Frontmatter parsing error: {0}")]
Parse(anyhow::Error),
}
#[derive(Clone)]
pub struct Content<T> {
pub path: Utf8PathBuf,
pub metadata: T,
pub content: String,
}
impl<G> SiteConfig<G>
where
G: Send + Sync + 'static,
{
pub fn load<R>(
&mut self,
path_glob: &'static str,
callback: impl Fn(&Globals<G>, &mut Runtime, File) -> anyhow::Result<R> + Send + Sync + 'static,
) -> Result<Handle<super::Registry<R>>, HauchiwaError>
where
G: Send + Sync + 'static,
R: Send + Sync + 'static,
{
Ok(self.add_task_opaque(GlobRegistryTask::new(
vec![path_glob],
vec![path_glob],
move |ctx, rt, file| {
let path = file.path.clone();
let data = callback(ctx.globals, rt, file)?;
Ok((path, data))
},
)?))
}
pub fn load_frontmatter<R>(
&mut self,
path_glob: &'static str,
) -> Result<Handle<super::Registry<Content<R>>>, HauchiwaError>
where
G: Send + Sync + 'static,
R: DeserializeOwned + Send + Sync + 'static,
{
Ok(self.add_task_opaque(GlobRegistryTask::new(
vec![path_glob],
vec![path_glob],
move |_, _, file: File| {
let data = std::str::from_utf8(&file.data).map_err(FrontmatterError::Utf8)?;
let (metadata, content) =
super::parse_yaml::<R>(data).map_err(FrontmatterError::Parse)?;
Ok((
file.path.clone(),
Content {
path: file.path,
metadata,
content,
},
))
},
)?))
}
}