#![feature(test)]
extern crate tera;
extern crate test;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use tera::{Context, Template, Tera, Value};
static VARIABLE_ONLY: &'static str = "{{product.name}}";
static SIMPLE_TEMPLATE: &'static str = "
<html>
<head>
<title>{{ product.name }}</title>
</head>
<body>
<h1>{{ product.name }} - {{ product.manufacturer | upper }}</h1>
<p>{{ product.summary }}</p>
<p>£{{ product.price * 1.20 }} (VAT inc.)</p>
<p>Look at reviews from your friends {{ username }}</p>
<button>Buy!</button>
</body>
</html>
";
static PARENT_TEMPLATE: &'static str = "
<html>
<head>
<title>{% block title %}Hello{% endblock title%}</title>
</head>
<body>
{% block body %}{% endblock body %}
</body>
</html>
";
static MACRO_TEMPLATE: &'static str = "
{% macro render_product(product) %}
<h1>{{ product.name }} - {{ product.manufacturer | upper }}</h1>
<p>{{ product.summary }}</p>
<p>£{{ product.price * 1.20 }} (VAT inc.)</p>
<button>Buy!</button>
{% endmacro render_product %}
";
static CHILD_TEMPLATE: &'static str = r#"{% extends "parent.html" %}
{% block title %}{{ super() }} - {{ username | lower }}{% endblock title %}
{% block body %}body{% endblock body %}
"#;
static CHILD_TEMPLATE_WITH_MACRO: &'static str = r#"{% extends "parent.html" %}
{% import "macros.html" as macros %}
{% block title %}{{ super() }} - {{ username | lower }}{% endblock title %}
{% block body %}
{{ macros::render_product(product=product) }}
{% endblock body %}
"#;
static USE_MACRO_TEMPLATE: &'static str = r#"
{% import "macros.html" as macros %}
{{ macros::render_product(product=product) }}
"#;
#[derive(Debug, Serialize)]
struct Product {
name: String,
manufacturer: String,
price: i32,
summary: String,
}
impl Product {
pub fn new() -> Product {
Product {
name: "Moto G".to_owned(),
manufacturer: "Motorala".to_owned(),
summary: "A phone".to_owned(),
price: 100,
}
}
}
#[bench]
fn bench_parsing_basic_template(b: &mut test::Bencher) {
b.iter(|| Template::new("bench", None, SIMPLE_TEMPLATE));
}
#[bench]
fn bench_parsing_with_inheritance_and_macros(b: &mut test::Bencher) {
let mut tera = Tera::default();
b.iter(|| {
tera.add_raw_templates(vec![
("parent.html", PARENT_TEMPLATE),
("child.html", CHILD_TEMPLATE),
("macros.html", MACRO_TEMPLATE),
])
});
}
#[bench]
fn bench_rendering_only_variable(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_template("test.html", VARIABLE_ONLY).unwrap();
let mut context = Context::new();
context.insert("product", &Product::new());
context.insert("username", &"bob");
b.iter(|| tera.render("test.html", context.clone()));
}
#[bench]
fn bench_rendering_basic_template(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_template("bench.html", SIMPLE_TEMPLATE).unwrap();
let mut context = Context::new();
context.insert("product", &Product::new());
context.insert("username", &"bob");
b.iter(|| tera.render("bench.html", context.clone()));
}
#[bench]
fn bench_rendering_only_parent(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("parent.html", PARENT_TEMPLATE)]).unwrap();
let mut context = Context::new();
context.insert("product", &Product::new());
context.insert("username", &"bob");
b.iter(|| tera.render("parent.html", context.clone()));
}
#[bench]
fn bench_rendering_only_macro_call(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("hey.html", USE_MACRO_TEMPLATE), ("macros.html", MACRO_TEMPLATE)])
.unwrap();
let mut context = Context::new();
context.insert("product", &Product::new());
context.insert("username", &"bob");
b.iter(|| tera.render("hey.html", context.clone()));
}
#[bench]
fn bench_rendering_only_inheritance(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("parent.html", PARENT_TEMPLATE), ("child.html", CHILD_TEMPLATE)])
.unwrap();
let mut context = Context::new();
context.insert("product", &Product::new());
context.insert("username", &"bob");
b.iter(|| tera.render("child.html", context.clone()));
}
#[bench]
fn bench_rendering_inheritance_and_macros(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_templates(vec![
("parent.html", PARENT_TEMPLATE),
("child.html", CHILD_TEMPLATE_WITH_MACRO),
("macros.html", MACRO_TEMPLATE),
])
.unwrap();
let mut context = Context::new();
context.insert("product", &Product::new());
context.insert("username", &"bob");
b.iter(|| tera.render("child.html", context.clone()));
}
#[bench]
fn bench_build_inheritance_chains(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_templates(vec![
("parent.html", PARENT_TEMPLATE),
("child.html", CHILD_TEMPLATE_WITH_MACRO),
("macros.html", MACRO_TEMPLATE),
])
.unwrap();
b.iter(|| tera.build_inheritance_chains());
}
#[bench]
fn bench_huge_loop(b: &mut test::Bencher) {
#[derive(Serialize)]
struct DataWrapper {
v: String,
}
#[derive(Serialize)]
struct RowWrapper {
real: Vec<DataWrapper>,
dummy: Vec<DataWrapper>,
}
let real: Vec<DataWrapper> =
(1..1000).into_iter().map(|i| DataWrapper { v: format!("n={}", i) }).collect();
let dummy: Vec<DataWrapper> =
(1..1000).into_iter().map(|i| DataWrapper { v: format!("n={}", i) }).collect();
let rows = RowWrapper { real, dummy };
let mut tera = Tera::default();
tera.add_raw_templates(vec![("huge.html", "{% for v in rows %}{{v}}{% endfor %}")]).unwrap();
let mut context = Context::new();
context.insert("rows", &rows);
b.iter(|| tera.render("huge.html", context.clone()));
}
fn deep_object() -> Value {
let data = r#"{
"foo": {
"bar": {
"goo": {
"moo": {
"cows": [
{
"name": "betsy",
"age" : 2,
"temperament": "calm"
},
{
"name": "elsie",
"age": 3,
"temperament": "calm"
},
{
"name": "veal",
"age": 1,
"temperament": "ornery"
}
]
}
}
}
}
}"#;
serde_json::from_str(data).unwrap()
}
#[bench]
fn access_deep_object(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_templates(vec![(
"deep_object.html",
"{% for cow in deep_object.foo.bar.goo.moo.cows %}{{cow.temperament}}{% endfor %}",
)])
.unwrap();
let mut context = Context::new();
println!("{:?}", deep_object());
context.insert("deep_object", &deep_object());
assert!(tera.render("deep_object.html", context.clone()).unwrap().contains("ornery"));
b.iter(|| tera.render("deep_object.html", context.clone()));
}
#[bench]
fn access_deep_object_with_literal(b: &mut test::Bencher) {
let mut tera = Tera::default();
tera.add_raw_templates(vec![(
"deep_object.html",
"
{% set goo = deep_object.foo['bar'][\"goo\"] %}
{% for cow in goo.moo.cows %}{{cow.temperament}}
{% endfor %}",
)])
.unwrap();
let mut context = Context::new();
context.insert("deep_object", &deep_object());
assert!(tera.render("deep_object.html", context.clone()).unwrap().contains("ornery"));
b.iter(|| tera.render("deep_object.html", context.clone()));
}