use hbs;
use serde::Serialize;
use failure::Error;
use super::{
TemplateEngine,
TemplateEngineCanHandleData,
BodyTemplate,
AdditionalCIds,
serde_impl
};
pub struct Handlebars {
inner: hbs::Handlebars,
name_counter: usize
}
impl Handlebars {
pub fn new() -> Self {
Handlebars {
inner: hbs::Handlebars::new(),
name_counter: 0
}
}
pub fn inner(&self) -> &hbs::Handlebars {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut hbs::Handlebars {
&mut self.inner
}
fn next_body_template_name(&mut self) -> String {
let name = format!("body_{}", self.name_counter);
self.name_counter += 1;
name
}
}
impl TemplateEngine for Handlebars {
type Id = String;
type LazyBodyTemplate = serde_impl::StandardLazyBodyTemplate;
fn load_body_template(&mut self, tmpl: Self::LazyBodyTemplate)
-> Result<BodyTemplate<Self>, Error>
{
let serde_impl::StandardLazyBodyTemplate {
path, embeddings, media_type
} = tmpl;
let name = self.next_body_template_name();
self.inner.register_template_file(&name, &path)?;
const ERR_BAD_MEDIA_TYPE_DETECTION: &str =
"handlebars requires html/txt file extension or media type given in template spec";
let media_type =
if let Some(media_type) = media_type {
media_type
} else if let Some(extension) = path.extension().and_then(|osstr| osstr.to_str()) {
match extension {
"html" => "text/html; charset=utf-8".parse().unwrap(),
"txt" => "text/plain; charset=utf-8".parse().unwrap(),
_ => { return Err(failure::err_msg(ERR_BAD_MEDIA_TYPE_DETECTION)); }
}
} else {
return Err(failure::err_msg(ERR_BAD_MEDIA_TYPE_DETECTION));
};
Ok(BodyTemplate {
template_id: name,
media_type,
inline_embeddings: embeddings,
})
}
fn load_subject_template(&mut self, template_string: String)
-> Result<Self::Id, Error>
{
let id = "subject".to_owned();
self.inner.register_template_string(&id, template_string)?;
Ok(id)
}
}
impl<D> TemplateEngineCanHandleData<D> for Handlebars
where D: Serialize
{
fn render<'r, 'a>(
&'r self,
id: &'r Self::Id,
data: &'r D,
additional_cids: AdditionalCIds<'r>
) -> Result<String, Error> {
Ok(self.inner.render(id, &SerHelper { data, cids: additional_cids })?)
}
}
#[derive(Serialize)]
struct SerHelper<'r, D: 'r> {
data: &'r D,
cids: AdditionalCIds<'r>
}