use camino::Utf8PathBuf;
use serde::de::DeserializeOwned;
use thiserror::Error;
use crate::{
Blueprint, Environment,
error::HauchiwaError,
graph::Handle,
loader::{GlobAssetsTask, Input, Store},
};
#[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 Document<T> {
pub metadata: T,
pub path: Utf8PathBuf,
pub body: String,
}
impl<G> Blueprint<G>
where
G: Send + Sync + 'static,
{
pub fn load<R>(
&mut self,
path_glob: &'static str,
callback: impl Fn(&Environment<G>, &mut Store, Input) -> anyhow::Result<R>
+ Send
+ Sync
+ 'static,
) -> Result<Handle<super::Assets<R>>, HauchiwaError>
where
G: Send + Sync + 'static,
R: Send + Sync + 'static,
{
Ok(self.add_task_opaque(GlobAssetsTask::new(
vec![path_glob],
vec![],
move |ctx, store, input| {
let path = input.path.clone();
let data = callback(ctx.env, store, input)?;
Ok((path, data))
},
)?))
}
pub fn load_documents<R>(
&mut self,
path_glob: &'static str,
) -> Result<Handle<super::Assets<Document<R>>>, HauchiwaError>
where
G: Send + Sync + 'static,
R: DeserializeOwned + Send + Sync + 'static,
{
Ok(self.add_task_opaque(GlobAssetsTask::new(
vec![path_glob],
vec![path_glob],
move |_, _, input: Input| {
let bytes = input
.read()
.map_err(|e| FrontmatterError::Parse(e.into()))?;
let data = std::str::from_utf8(&bytes).map_err(FrontmatterError::Utf8)?;
let (metadata, content) =
super::parse_yaml::<R>(data).map_err(FrontmatterError::Parse)?;
Ok((
input.path.clone(),
Document {
path: input.path,
metadata,
body: content,
},
))
},
)?))
}
}