#[macro_use]
extern crate serde_derive;
use std::collections::BTreeMap;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use handlebars::{to_json, Handlebars, Template};
use serde_json::value::Value as Json;
static SOURCE_HANDLEBARS: &str = "
{{year}}
CSL {{year}}
{{#each teams}}
-
{{name}}: {{score}}
{{/each}}
";
fn make_data_handlebars() -> BTreeMap {
let mut data = BTreeMap::new();
data.insert("year".to_string(), to_json("2015"));
let mut teams = Vec::new();
for v in [
("Jiangsu", 43u16),
("Beijing", 27u16),
("Guangzhou", 22u16),
("Shandong", 12u16),
]
.iter()
{
let (name, score) = *v;
let mut t = BTreeMap::new();
t.insert("name".to_string(), to_json(name));
t.insert("score".to_string(), to_json(score));
teams.push(t)
}
data.insert("teams".to_string(), to_json(&teams));
data
}
static SOURCE_LIQUID: &str = "
{{year}}
CSL {{year}}
{% for team in teams %}
-
{{team.name}}: {{team.score}}
{% endfor %}
";
static DATA_LIQUID: &str = "
year: 2015
teams:
- name: Jiangsu
score: 43
- name: Beijing
score: 27
- name: Guangzhou
score: 22
- name: Shandong
score: 12
";
fn bench_template(c: &mut Criterion) {
let mut group = c.benchmark_group("handlebars_bench_template");
group.bench_function(BenchmarkId::new("parse", "handlebars"), |b| {
b.iter(|| Template::compile(SOURCE_HANDLEBARS).unwrap());
});
group.bench_function(BenchmarkId::new("render", "handlebars"), |b| {
let mut handlebars = Handlebars::new();
handlebars
.register_template_string("table", SOURCE_HANDLEBARS)
.expect("Invalid template format");
let data = make_data_handlebars();
b.iter(|| handlebars.render("table", &data).unwrap())
});
group.bench_function(BenchmarkId::new("parse", "liquid"), |b| {
let parser = liquid::ParserBuilder::with_stdlib().build().unwrap();
b.iter(|| parser.parse(SOURCE_LIQUID));
});
group.bench_function(BenchmarkId::new("render", "liquid"), |b| {
let parser = liquid::ParserBuilder::with_stdlib().build().unwrap();
let template = parser
.parse(SOURCE_LIQUID)
.expect("Benchmark template parsing failed");
let data: liquid::Object =
serde_yaml::from_str(DATA_LIQUID).expect("Benchmark object parsing failed");
template.render(&data).unwrap();
b.iter(|| template.render(&data));
});
group.finish();
}
#[derive(Serialize)]
struct DataWrapper {
v: String,
}
#[derive(Serialize)]
struct RowWrapper {
real: Vec,
dummy: Vec,
}
fn bench_large_loop(c: &mut Criterion) {
let real: Vec = (1..1000)
.map(|i| DataWrapper {
v: format!("n={}", i),
})
.collect();
let dummy: Vec = (1..1000)
.map(|i| DataWrapper {
v: format!("n={}", i),
})
.collect();
let rows = RowWrapper { real, dummy };
let row_wrapper = liquid::to_object(&rows).unwrap();
let mut group = c.benchmark_group("handlebars_bench_large_loop");
group.bench_function(BenchmarkId::new("render", "handlebars"), |b| {
let mut handlebars = Handlebars::new();
handlebars
.register_template_string("test", "BEFORE\n{{#each real}}{{this.v}}{{/each}}AFTER")
.expect("Invalid template format");
b.iter(|| handlebars.render("test", &rows).unwrap());
});
group.bench_function(BenchmarkId::new("render", "liquid"), |b| {
let parser = liquid::ParserBuilder::with_stdlib().build().unwrap();
let template = parser
.parse("BEFORE\n{% for this in real%}{{this.v}}{%endfor%}AFTER")
.expect("Benchmark template parsing failed");
template.render(&row_wrapper).unwrap();
b.iter(|| template.render(&row_wrapper));
});
group.finish();
}
criterion_group!(benches, bench_template, bench_large_loop);
criterion_main!(benches);