use std::collections::HashMap;
use std::path::Path;
use rkt::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;
#[cfg_attr(
not(any(feature = "tera", feature = "handlebars", feature = "minijinja")),
allow(dead_code)
)]
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>,
}
#[cfg_attr(
not(any(feature = "tera", feature = "handlebars", feature = "minijinja")),
allow(dead_code)
)]
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: inner::<Tera>(_templates)?,
#[cfg(feature = "handlebars")]
handlebars: inner::<Handlebars<'static>>(_templates)?,
#[cfg(feature = "minijinja")]
minijinja: inner::<Environment<'static>>(_templates)?,
})
}
#[cfg_attr(
not(any(feature = "tera", feature = "handlebars", feature = "minijinja")),
allow(unused_variables)
)]
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)
}
}