Tomplate: TOML-Based Compile-Time Template Composition
Tomplate is a powerful compile-time template engine for Rust that processes templates at compile time, resulting in zero runtime overhead. Templates are defined in TOML files and can use various template engines including Handlebars, Tera, and MiniJinja.
Features
- Zero Runtime Overhead: All template processing happens at compile time
- Multiple Template Engines: Choose from Simple, Handlebars, Tera, or MiniJinja
- Composition Blocks: Build complex templates from reusable parts
- Inline Templates: Use template strings directly without registry
- Eager Evaluation: Solve macro expansion order issues with
tomplate_eager! - File-Based Organization: Store templates in
.tomplate.tomlfiles
Getting Started
Step 1: Add Dependencies
Add to your Cargo.toml:
[]
= "0.1"
[]
= "0.1"
# Optional: Enable additional template engines
# [dependencies.tomplate]
# version = "0.1"
# features = ["handlebars", "tera"] # Add the engines you need
Step 2: Create a Build Script
Create build.rs in your project root:
Step 3: Create Template Files
Create a file like templates/queries.tomplate.toml:
# Simple variable substitution (default engine)
[]
= "SELECT {fields} FROM users WHERE {condition}"
# Using Handlebars for logic
[]
= """
SELECT * FROM users
{{#if status}}
WHERE status = '{{status}}'
{{/if}}
"""
= "handlebars"
# Template with default values
[]
= "SELECT * FROM {table} LIMIT {limit} OFFSET {offset}"
Step 4: Use Templates in Your Code
# use tomplate;
#
Major Features Examples
1. File-Based vs Inline Templates
use tomplate;
// File-based: Looks for "user_query" in your .tomplate.toml files
const FROM_FILE: &str = tomplate!;
// Inline: If "Hello {name}!" isn't found in files, treats it as template
const INLINE: &str = tomplate!;
// How it works:
// 1. First checks if the string matches a template name in registry
// 2. If not found, uses the string itself as an inline template
2. Nested Template Composition
# use tomplate;
#
3. Composition Blocks with Scoped Variables
use tomplate;
tomplate!
// The constants are now available for use
// Output: "SELECT id, name, email FROM users WHERE status = 'active' LIMIT 10 OFFSET 0"
4. Multiple Template Engines
// In your .tomplate.toml file:
// [simple_template]
// template = "Hello {name}"
// engine = "simple" # Default - basic {var} substitution
//
// [handlebars_template]
// template = "{{#if logged_in}}Welcome {{user}}{{else}}Please login{{/if}}"
// engine = "handlebars"
//
// [tera_template]
// template = "{% for item in items %}{{ item|upper }}{% endfor %}"
// engine = "tera"
// Use them the same way
const SIMPLE: &str = tomplate!;
const LOGIC: &str = tomplate!;
5. Eager Evaluation for Nested Macros
use ;
// Problem: This won't work with macros that expect string literals
// sqlx::query!(tomplate!("select_user", id = "5")) // ❌ Fails
// Solution: Use tomplate_eager! to expand inner macros first
tomplate_eager!
Build Configuration
In your build.rs:
Template Files
Create .tomplate.toml files in your project:
[]
= "SELECT {fields} FROM {table} WHERE {condition}"
= "simple" # Optional, defaults to "simple"
[]
= "{{#if condition}}{{value}}{{else}}default{{/if}}"
= "handlebars"
Feature Flags
build: Enables the build-time template discovery (enabled by default)handlebars: Enables Handlebars template enginetera: Enables Tera template engineminijinja: Enables MiniJinja template engine