use tron::{template, template_ref, assemble_templates, generate_code, template_builder};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Tron Compile-time Template Macros Example ===\n");
demonstrate_template_macro()?;
demonstrate_template_ref_macro()?;
demonstrate_assemble_templates_macro()?;
demonstrate_generate_code_macro();
demonstrate_template_builder_macro()?;
demonstrate_compile_time_benefits()?;
Ok(())
}
fn demonstrate_template_macro() -> Result<(), Box<dyn std::error::Error>> {
println!("1. Basic Template Macro:");
let mut function_template = template!("fn @[name]@(@[params]@) -> @[return_type]@ {\n @[body]@\n}");
println!(" - Template created at compile time");
println!(" - Placeholders: {:?}", function_template.placeholder_names());
function_template.set("name", "calculate_area")?;
function_template.set("params", "width: f64, height: f64")?;
function_template.set("return_type", "f64")?;
function_template.set("body", "width * height")?;
let result = function_template.render()?;
println!(" - Generated function:");
for (i, line) in result.lines().enumerate() {
println!(" {:2}: {}", i + 1, line);
}
println!();
Ok(())
}
fn demonstrate_template_ref_macro() -> Result<(), Box<dyn std::error::Error>> {
println!("2. Template Reference with Dependencies:");
let mut api_template = template_ref!(
r#"use serde::{Deserialize, Serialize};
use axum::Json;
#[derive(Debug, Serialize, Deserialize)]
pub struct @[request_type]@ {
@[request_fields]@
}
#[derive(Debug, Serialize, Deserialize)]
pub struct @[response_type]@ {
@[response_fields]@
}
pub async fn @[handler_name]@(Json(req): Json<@[request_type]@>) -> Json<@[response_type]@> {
@[handler_body]@
}"#,
dependencies = [
"serde = { version = \"1.0\", features = [\"derive\"] }",
"axum = \"0.7\"",
"tokio = { version = \"1.0\", features = [\"full\"] }"
]
);
println!(" - Template reference created with {} dependencies", api_template.dependencies().len());
api_template.set("request_type", "CreateUserRequest")?;
api_template.set("request_fields", "pub name: String,\n pub email: String")?;
api_template.set("response_type", "CreateUserResponse")?;
api_template.set("response_fields", "pub id: u64,\n pub message: String")?;
api_template.set("handler_name", "create_user")?;
api_template.set("handler_body", r#"// Implementation logic here
Json(CreateUserResponse {
id: 1,
message: "User created successfully".to_string(),
})"#)?;
let result = api_template.render()?;
println!(" - Generated API handler (first 10 lines):");
for (i, line) in result.lines().take(10).enumerate() {
println!(" {:2}: {}", i + 1, line);
}
println!(" ... (truncated)");
println!();
Ok(())
}
fn demonstrate_assemble_templates_macro() -> Result<(), Box<dyn std::error::Error>> {
println!("3. Template Assembly Macro:");
let mut assembler = assemble_templates![
separator = "\n\n",
"//! @[module_title]@\n//!\n//! @[module_description]@\n",
"use std::collections::HashMap;\nuse serde::{Deserialize, Serialize};\n",
"#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct @[struct_name]@ {\n @[struct_fields]@\n}",
"impl @[struct_name]@ {\n pub fn new(@[constructor_params]@) -> Self {\n @[constructor_body]@\n }\n\n @[additional_methods]@\n}"
];
println!(" - Assembler created with {} templates", assembler.len());
println!(" - Custom separator: \"\\n\\n\"");
assembler.set_global("module_title", "User Management Module")?;
assembler.set_global("module_description", "Handles user creation, updates, and queries.")?;
assembler.set_global("struct_name", "User")?;
assembler.set_global("struct_fields", "pub id: u64,\n pub name: String,\n pub email: String,\n pub created_at: String")?;
assembler.set_global("constructor_params", "name: String, email: String")?;
assembler.set_global("constructor_body", "Self {\n id: 0,\n name,\n email,\n created_at: chrono::Utc::now().to_rfc3339(),\n }")?;
assembler.set_global("additional_methods", "pub fn update_email(&mut self, email: String) {\n self.email = email;\n }")?;
let result = assembler.render_all()?;
println!(" - Generated module (first 15 lines):");
for (i, line) in result.lines().take(15).enumerate() {
println!(" {:2}: {}", i + 1, line);
}
println!(" ... (truncated)");
println!();
Ok(())
}
fn demonstrate_generate_code_macro() {
println!("4. Code Generation Macro:");
let constant_code = generate_code!(
template = "pub const @[name]@: @[type]@ = @[value]@;",
placeholders = {
"name" => "MAX_CONNECTIONS",
"type" => "usize",
"value" => "100"
}
);
let enum_code = generate_code!(
template = r#"#[derive(@[derives]@)]
pub enum @[enum_name]@ {
@[variants]@
}"#,
placeholders = {
"derives" => "Debug, Clone, PartialEq",
"enum_name" => "ConnectionStatus",
"variants" => "Connected,\n Disconnected,\n Reconnecting,\n Failed(String)"
}
);
println!(" - Generated constant:");
println!(" {}", constant_code);
println!(" - Generated enum:");
for (i, line) in enum_code.lines().enumerate() {
println!(" {:2}: {}", i + 1, line);
}
println!();
}
fn demonstrate_template_builder_macro() -> Result<(), Box<dyn std::error::Error>> {
println!("5. Template Builder Macro:");
let builder = template_builder!(
template = r#"#[derive(Debug)]
pub struct @[name]@ {
@[fields]@
}
impl @[name]@ {
pub fn @[getter_name]@(&self) -> &@[field_type]@ {
&self.@[field_name]@
}
}"#,
values = {
"name" => "Config",
"fields" => "pub database_url: String,\n pub port: u16,\n pub debug: bool"
}
);
let template = builder
.set("getter_name", "database_url")
.set("field_type", "str")
.set("field_name", "database_url")
.build()?;
let result = template.render()?;
println!(" - Generated struct with getter:");
for (i, line) in result.lines().enumerate() {
println!(" {:2}: {}", i + 1, line);
}
println!();
Ok(())
}
fn demonstrate_compile_time_benefits() -> Result<(), Box<dyn std::error::Error>> {
println!("6. Compile-time Benefits:");
println!(" - All template syntax validated at compile time ✓");
println!(" - Zero runtime parsing overhead ✓");
println!(" - Template errors caught during compilation ✓");
println!(" - Optimal performance for frequently used templates ✓");
let compile_time = template!("Hello @[name]@!");
let mut runtime = tron::TronTemplate::new("Hello @[name]@!")?;
let mut compile_time_clone = compile_time.clone();
compile_time_clone.set("name", "Compile-time")?;
runtime.set("name", "Runtime")?;
println!(" - Compile-time result: {}", compile_time_clone.render()?);
println!(" - Runtime result: {}", runtime.render()?);
println!(" - Same API, different performance characteristics!");
println!();
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use tron::TronTemplate;
#[test]
fn test_compile_time_macros_functionality() -> Result<(), Box<dyn std::error::Error>> {
let compile_time = template!("Test @[value]@");
let runtime = TronTemplate::new("Test @[value]@")?;
assert_eq!(compile_time.placeholder_names(), runtime.placeholder_names());
assert_eq!(compile_time.content(), runtime.content());
Ok(())
}
#[test]
fn test_template_ref_macro_with_deps() {
let template_ref = template_ref!(
"use @[crate]@; fn @[name]@() {}",
dependencies = ["tokio = \"1.0\""]
);
assert_eq!(template_ref.dependencies().len(), 1);
assert!(template_ref.dependencies()[0].contains("tokio"));
}
#[test]
fn test_code_generation_macro() {
let code = generate_code!(
template = "const @[name]@: @[type]@ = @[value]@;",
placeholders = {
"name" => "TEST_CONST",
"type" => "i32",
"value" => "42"
}
);
assert_eq!(code, "const TEST_CONST: i32 = 42;");
}
}