upon

Crates.io Version Docs.rs Latest Build Status

A simple, powerful template engine with minimal dependencies and configurable delimiters.

Table of Contents

Overview

Syntax

Engine

Why another template engine?

It’s true there are already a lot of template engines for Rust!

I created upon because I required a template engine that had runtime compiled templates, configurable syntax delimiters and minimal dependencies. I also didn’t need support for arbitrary expressions in the template syntax but occasionally I needed something more flexible than outputting simple values (hence filters). Performance was also a concern for me, template engines like [Handlebars] and [Tera] have a lot of features but can be up to five to seven times slower to render than engines like [TinyTemplate].

Basically I wanted something like [TinyTemplate] with support for configurable delimiters and user defined filter functions. The syntax is inspired by template engines like [Liquid] and [Jinja].

MSRV

Currently the minimum supported version for upon is Rust 1.65. Disabling the filters feature reduces it to Rust 1.60. The MSRV will only ever be increased in a breaking release.

Getting started

First, add the crate to your Cargo manifest.

sh cargo add upon

Now construct an Engine. The engine stores the syntax config, filter functions, formatters, and compiled templates. Generally, you only need to construct one engine during the lifetime of a program.

rust let engine = upon::Engine::new();

Next, add_template is used to compile and store a template in the engine.

rust engine.add_template("hello", "Hello {{ user.name }}!")?;

Finally, the template is rendered by fetching it using get_template and calling render.

rust let template = engine.get_template("hello").unwrap(); let result = template.render(upon::value!{ user: { name: "John Smith" }}).to_string()?; assert_eq!(result, "Hello John Smith!");

If the lifetime of the template source is shorter than the engine lifetime or you don’t need to store the compiled template then you can also use the compile function to return the template directly.

rust let template = engine.compile("Hello {{ user.name }}!")?; let result = template.render(upon::value!{ user: { name: "John Smith" }}).to_string()?; assert_eq!(result, "Hello John Smith!");

Further reading

Features

The following crate features are available.

To disable all features or to use a subset you need to set default-features = false in your Cargo manifest and then enable the features that you would like. For example to use serde but disable filters and unicode you would do the following.

toml [dependencies] upon = { version = "...", default-features = false, features = ["serde"] }

Benchmarks

upon was benchmarked against several popular template rendering engines in the Rust ecosystem. Obviously, each of these engines has a completely different feature set so the benchmark just compares the performance of some of the features that they share.

Violin plot of compile results Violin plot of render results Violin plot of render with filters results

Benchmarking was done using criterion on a quiet cloud machine.

Host

License

Licensed under either of

at your option.