use std::path::Path;
use std::collections::HashMap;
use rocket::serde::Serialize;
use crate::template::TemplateInfo;
#[cfg(feature = "tera")]
mod tera;
#[cfg(feature = "tera")]
use ::tera::Tera;
#[cfg(feature = "handlebars")]
mod handlebars;
#[cfg(feature = "handlebars")]
use ::handlebars::Handlebars;
#[cfg(feature = "minijinja")]
mod minijinja;
#[cfg(feature = "minijinja")]
use ::minijinja::Environment;
pub(crate) trait Engine: Send + Sync + Sized + 'static {
const EXT: &'static str;
fn init<'a>(templates: impl Iterator<Item = (&'a str, &'a Path)>) -> Option<Self>;
fn render<C: Serialize>(&self, name: &str, context: C) -> Option<String>;
}
pub struct Engines {
#[cfg(feature = "tera")]
pub tera: Tera,
#[cfg(feature = "handlebars")]
pub handlebars: Handlebars<'static>,
#[cfg(feature = "minijinja")]
pub minijinja: Environment<'static>,
}
impl Engines {
pub(crate) const ENABLED_EXTENSIONS: &'static [&'static str] = &[
#[cfg(feature = "tera")] Tera::EXT,
#[cfg(feature = "handlebars")] Handlebars::EXT,
#[cfg(feature = "minijinja")] Environment::EXT,
];
pub(crate) fn init(templates: &HashMap<String, TemplateInfo>) -> Option<Engines> {
fn inner<E: Engine>(templates: &HashMap<String, TemplateInfo>) -> Option<E> {
let named_templates = templates.iter()
.filter(|&(_, i)| i.engine_ext == E::EXT)
.filter_map(|(k, i)| Some((k.as_str(), i.path.as_ref()?)))
.map(|(k, p)| (k, p.as_path()));
E::init(named_templates)
}
Some(Engines {
#[cfg(feature = "tera")]
tera: match inner::<Tera>(templates) {
Some(tera) => tera,
None => return None
},
#[cfg(feature = "handlebars")]
handlebars: match inner::<Handlebars<'static>>(templates) {
Some(hb) => hb,
None => return None
},
#[cfg(feature = "minijinja")]
minijinja: match inner::<Environment<'static>>(templates) {
Some(hb) => hb,
None => return None
},
})
}
pub(crate) fn render<C: Serialize>(
&self,
name: &str,
info: &TemplateInfo,
context: C,
) -> Option<String> {
#[cfg(feature = "tera")] {
if info.engine_ext == Tera::EXT {
return Engine::render(&self.tera, name, context);
}
}
#[cfg(feature = "handlebars")] {
if info.engine_ext == Handlebars::EXT {
return Engine::render(&self.handlebars, name, context);
}
}
#[cfg(feature = "minijinja")] {
if info.engine_ext == Environment::EXT {
return Engine::render(&self.minijinja, name, context);
}
}
None
}
pub(crate) fn templates(&self) -> impl Iterator<Item = (&str, &'static str)> {
#[cfg(feature = "tera")]
let tera = self.tera.get_template_names().map(|name| (name, Tera::EXT));
#[cfg(feature = "handlebars")]
let handlebars = self.handlebars.get_templates().keys()
.map(|name| (name.as_str(), Handlebars::EXT));
#[cfg(feature = "minijinja")]
let minijinja = self.minijinja.templates()
.map(|(name, _)| (name, Environment::EXT));
#[cfg(not(feature = "tera"))] let tera = std::iter::empty();
#[cfg(not(feature = "handlebars"))] let handlebars = std::iter::empty();
#[cfg(not(feature = "minijinja"))] let minijinja = std::iter::empty();
tera.chain(handlebars).chain(minijinja)
}
}