Expand description
§Templatia
A powerful and easy-to-use library for converting Rust structs to and from text templates. Templatia lets you define templates with placeholders and automatically handles the serialization and deserialization, making configuration management and text processing effortless.
§Key Features
- 🚀 Simple: Just add
#[derive(Template)]to your struct - 🔧 Flexible: Use default templates or define custom ones
- 🛡️ Safe: Type-safe parsing with clear error reporting
- 🔄 Round-trip: Reliable conversion to/from strings
§Quick Start
Add templatia to your Cargo.toml:
[dependencies]
templatia = { version = "0.0.3", features = ["derive"] }§Related Crates
- templatia-derive: Procedural macro crate providing #[derive(Template)]. Docs: https://docs.rs/templatia-derive
§Using the Derive Macro (Recommended)
The easiest way to use templatia is with the derive macro for named structs:
use templatia::Template;
#[derive(Template)]
struct DatabaseConfig {
host: String,
port: u16,
database: String,
}
let config = DatabaseConfig {
host: "localhost".to_string(),
port: 5432,
database: "myapp".to_string(),
};
// Convert to template string (default format: field = {field})
let template = config.render_string();
assert_eq!(template, "host = localhost\nport = 5432\ndatabase = myapp");
// Parse back from template string
let parsed = DatabaseConfig::from_str(&template).unwrap();
assert_eq!(parsed.host, "localhost");
assert_eq!(parsed.port, 5432);§Custom Templates
Define your own template format using the templatia attribute:
use templatia::Template;
#[derive(Template)]
#[templatia(template = "postgresql://{host}:{port}/{database}")]
struct PostgresUrl {
host: String,
port: u16,
database: String,
}
let url = PostgresUrl {
host: "db.example.com".to_string(),
port: 5432,
database: "production".to_string(),
};
assert_eq!(url.render_string(), "postgresql://db.example.com:5432/production");
let parsed = PostgresUrl::from_str("postgresql://localhost:5432/test").unwrap();
assert_eq!(parsed.database, "test");§Advanced Features
§Duplicate Placeholders
Templatia supports duplicate placeholders as long as they have consistent values:
use templatia::Template;
#[derive(Template)]
#[templatia(template = "Welcome {name}! Your name is {name}.")]
struct Greeting {
name: String,
}
let greeting = Greeting { name: "Alice".to_string() };
assert_eq!(greeting.render_string(), "Welcome Alice! Your name is Alice.");
// Parsing with inconsistent values will result in an error
let result = Greeting::from_str("Welcome Alice! Your name is Bob.");
assert!(result.is_err());§Option<T> Support
Fields with Option<T> type automatically default to None when the placeholder is not in the template:
use templatia::Template;
#[derive(Template)]
#[templatia(template = "host={host}:{port}", allow_missing_placeholders)]
struct ServerConfig {
host: String,
port: u16,
username: Option<String>,
password: Option<String>,
}
let config = ServerConfig::from_str("host=localhost:8080").unwrap();
assert_eq!(config.host, "localhost");
assert_eq!(config.port, 8080);
assert_eq!(config.username, None); // Not in template, defaults to None
assert_eq!(config.password, None); // Not in template, defaults to NoneBy default, empty strings in Option<String> are parsed as None:
use templatia::Template;
#[derive(Template)]
#[templatia(template = "value={value}")]
struct OptionalValue {
value: Option<String>,
}
let parsed = OptionalValue::from_str("value=").unwrap();
assert_eq!(parsed.value, None); // Empty string becomes NoneTo treat empty strings as Some(""), use the empty_str_option_not_none attribute:
use templatia::Template;
#[derive(Template)]
#[templatia(template = "value={value}", empty_str_option_not_none)]
struct OptionalValue {
value: Option<String>,
}
let parsed = OptionalValue::from_str("value=").unwrap();
assert_eq!(parsed.value, Some("".to_string())); // Empty string becomes Some("")§Missing Placeholders
Use allow_missing_placeholders to allow fields not in the template:
use templatia::Template;
#[derive(Template)]
#[templatia(template = "id={id}", allow_missing_placeholders)]
struct Config {
id: u32,
name: String, // Not in template, uses Default::default()
optional: Option<u32>, // Not in template, becomes None
}
let config = Config::from_str("id=42").unwrap();
assert_eq!(config.id, 42);
assert_eq!(config.name, ""); // Default for String
assert_eq!(config.optional, None); // None for Option<T>§Manual Implementation (Advanced)
While the derive macro only supports named structs currently, you can manually implement
the Template trait for other types like tuple structs, enums, or complex custom logic:
use templatia::{Template, TemplateError};
// Example: Tuple struct (derive doesn't support this yet)
struct Point(i32, i32);
impl Template for Point {
type Error = TemplateError;
fn render_string(&self) -> String {
format!("({}, {})", self.0, self.1)
}
fn from_str(s: &str) -> Result<Self, Self::Error> {
if !s.starts_with('(') || !s.ends_with(')') {
return Err(TemplateError::Parse("Expected format: (x, y)".to_string()));
}
let inner = &s[1..s.len()-1];
let parts: Vec<&str> = inner.split(", ").collect();
if parts.len() != 2 {
return Err(TemplateError::Parse("Expected two comma-separated values".to_string()));
}
let x = parts[0].parse().map_err(|_|
TemplateError::Parse("Failed to parse x coordinate".to_string()))?;
let y = parts[1].parse().map_err(|_|
TemplateError::Parse("Failed to parse y coordinate".to_string()))?;
Ok(Point(x, y))
}
}
let point = Point(10, 20);
assert_eq!(point.render_string(), "(10, 20)");
let parsed = Point::from_str("(5, 15)").unwrap();
assert_eq!(parsed.0, 5);
assert_eq!(parsed.1, 15);§Load Map (Roadmap)
Templatia follows a clear development roadmap with planned features:
§✅ Version 0.0.2 (Completed)
#[templatia(allow_missing_placeholders)]attribute: Fields not in template useDefault::default()Option<T>support: Automatically defaults toNonewhen placeholder is absent- Empty string handling: By default, empty strings in
Option<String>are parsed asNone #[templatia(empty_str_option_not_none)]attribute: Treats empty strings asSome("")instead ofNone- Removed
type Structassociated type fromTemplatetrait (simplified toSelf) - Bug fixes for consistent placeholder handling and parsing edge cases
§🔮 Version 0.0.3
- Enriched error diagnostics and coverage
- More detailed parsing error messages
§🎯 Version 0.0.4
- Collections support:
Vec,HashMap,HashSet - Container attributes for flexible parent structure configuration
§🌟 Version 0.0.5
- Tuple struct support (derive macro)
- Union struct support
- Enum support
§Type Requirements
Fields used in templates must implement:
std::fmt::Displayfor serializationstd::str::FromStrfor deserializationstd::cmp::PartialEqfor consistency checks
Most common types (String, integers, floats, bool) implement these automatically.
§Error Handling
Templatia provides clear error types for different failure scenarios:
use templatia::{Template, TemplateError};
#[derive(Template)]
#[templatia(template = "port={port}")]
struct Config { port: u16 }
// Parse error example
match Config::from_str("port=not_a_number") {
Err(TemplateError::ParseToType { placeholder, value, type_name }) => println!("Parse failed: placeholder '{}' with value '{}' could not be parsed as type '{}'", placeholder, value, type_name),
_ => unreachable!(),
}
// Inconsistent values error (when same placeholder appears multiple times)
#[derive(Template)]
#[templatia(template = "id={id}-backup-{id}")]
struct BackupConfig { id: String }
match BackupConfig::from_str("id=prod-backup-dev") {
Err(TemplateError::InconsistentValues { placeholder, first_value, second_value }) => {
println!("Placeholder '{}' had conflicting values: '{}' vs '{}'",
placeholder, first_value, second_value);
},
_ => unreachable!(),
}§Features
§derive
The derive feature enables the #[derive(Template)] procedural macro for automatic
Template trait implementations on named structs.
When enabled, you can use:
[dependencies]
templatia = { version = "0.0.3", features = ["derive"] }This feature is recommended for most users as it significantly simplifies usage:
- Automatic trait implementation generation
- Custom template support via
#[templatia(template = "...")]attribute - Compile-time validation of templates and field references
- Zero-cost abstractions with full type safety
Limitations: Currently only supports named structs. Tuple structs, unit structs,
and enums require manual Template trait implementation.
For detailed usage examples, see the sections above.
Enums§
- Template
Error - Errors produced by templatia operations.
Traits§
- Template
- A trait for converting between a struct and its string template form.