use std::collections::HashMap;
use serde::Serialize;
use std::fmt;
use crate::{
output::Output,
parser::{ast::Node, Parser, ParserOptions},
render::{CallSite, Render},
Registry, RenderResult, SyntaxResult,
};
use self_cell::self_cell;
pub type Templates = HashMap<String, Template>;
self_cell!(
struct Ast {
owner: String,
#[covariant]
dependent: Node,
}
impl {Debug}
);
#[derive(Debug)]
pub struct Template {
file_name: Option<String>,
ast: Ast,
}
impl Template {
pub fn compile(
source: String,
options: ParserOptions,
) -> SyntaxResult<Self> {
let mut err = None;
let file_name = if options.file_name != crate::parser::UNKNOWN {
Some(options.file_name.clone())
} else {
None
};
let ast = Ast::new(source, |s: &String| {
match Parser::new(s, options).parse() {
Ok(ast) => ast,
Err(e) => {
err = Some(e);
Default::default()
}
}
});
if let Some(e) = err {
Err(e)
} else {
Ok(Self { file_name, ast })
}
}
pub fn node(&self) -> &Node<'_> {
self.ast.borrow_dependent()
}
pub fn file_name(&self) -> Option<&str> {
self.file_name.as_ref().map(|s| s.as_str())
}
pub fn render<'a, T>(
&self,
registry: &'a Registry<'a>,
name: &str,
data: &T,
writer: &'a mut impl Output,
stack: Vec<CallSite>,
) -> RenderResult<()>
where
T: Serialize,
{
let mut rc =
Render::new(registry, name, data, Box::new(writer), stack)?;
rc.render(self.node())
}
}
impl fmt::Display for Template {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.node().fmt(f)
}
}