| Crates.io | templatia-derive |
| lib.rs | templatia-derive |
| version | 0.0.4-alpha.1 |
| created_at | 2025-09-29 07:23:45.036194+00 |
| updated_at | 2025-11-02 15:28:16.146263+00 |
| description | A proc_macro for templatia derive |
| homepage | https://github.com/SHIMA0111/templatia |
| repository | https://github.com/SHIMA0111/templatia |
| max_upload_size | |
| id | 1859065 |
| size | 167,932 |
A template-based serialization/deserialization library that enables seamless bidirectional conversion between Rust structs and text according to user-defined templates. This library is realized through two crates:
Typically, these are not used individually but combined via the derive feature of templatia.
(However, since templatia-derive currently only supports named_struct, custom implementations are also possible for special types.)
Vec<T>, HashSet<T>, BTreeSet<T>). See "Collection support (alpha)" for details.{field_name} = {field_name}templatia attribute: #[templatia(template = "...")]String type data. Consecutive allows only: [char, bool]#[templatia(allow_missing_placeholders)] attribute.cargo add templatia --features derive
derive to features.[dependencies]
templatia = { version = "0.0.3", features = ["derive"] }
use templatia::Template;
#[derive(Template)]
struct Config {
host: String,
port: u16,
}
fn main() {
let cfg = Config { host: "localhost".into(), port: 5432 };
let s = cfg.render_string();
assert!(s.contains("host = localhost"));
assert!(s.contains("port = 5432"));
}
When no template is specified, each field is synthesized in the format field_name = {field_name}, one per line.
For example:
#[derive(Template)]
struct AwesomeStruct {
data1: String,
data2: u32,
}
fn main() {
let data = AwesomeStruct { data1: "data1".into(), data2: 100 };
}
In this case, the template is generated in the format:
data1 = {data1}
data2 = {data2}
When executing render_string(), you get the output:
data1 = data1
data2 = 100
By using placeholders enclosed in {} with struct field names in the template within the templatia attribute, you can define a custom template.
In the following case, since "{host}:{port}" is defined, you can obtain db.example.com:3306 from cfg.
use templatia::Template;
#[derive(Template)]
#[templatia(template = "{host}:{port}")]
struct DbCfg {
host: String,
port: u16,
}
fn main() {
let cfg = DbCfg { host: "db.example.com".into(), port: 3306 };
assert_eq!(cfg.render_string(), "db.example.com:3306");
let parsed = DbCfg::from_str("db.example.com:3306").unwrap();
assert_eq!(parsed.host, "db.example.com");
assert_eq!(parsed.port, 3306);
}
Fields with Option<T> type automatically default to None when the placeholder is not present 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>,
}
fn main() {
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 None
}
By default, empty strings in Option<String> are parsed as None. To 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>,
}
fn main() {
let parsed = OptionalValue::from_str("value=").unwrap();
assert_eq!(parsed.value, Some("".to_string())); // Empty string becomes Some("")
}
Use the allow_missing_placeholders attribute to allow fields that are not present 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
}
fn main() {
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>
}
{name} in the template must correspond to a named struct fieldallow_missing_placeholders is enabled, the Default trait implementation is also required."{first_name} (Full: {first_name} {family_name})", you cannot deserialize Taro (Full: Jiro Yamada) into the struct.The alpha pre-release 0.0.4-alpha.1 introduces limited collection support in templates:
Vec<T>, HashSet<T>, BTreeSet<T>items={items} matches inputs like items=a,b,citems=)TemplateError::ParseToType with type_name like Vec<u32>Example:
use templatia::Template;
use std::collections::{HashSet, BTreeSet};
#[derive(Template)]
#[templatia(template = "items={items}; tags={tags}; ord={ord}")]
struct Data {
items: Vec<u32>,
tags: HashSet<String>,
ord: BTreeSet<i32>,
}
fn main() {
let d = Data::from_str("items=1,2,3; tags=red,blue,red; ord=1,1,2").unwrap();
assert_eq!(d.items, vec![1,2,3]);
assert_eq!(d.tags.len(), 2); // red, blue
assert_eq!(d.ord.len(), 2); // 1, 2
}
Notes:
templatia defines a simple error type for parsing and validation:
templatia.
It defines two methods: render_string() and from_str(), and one associated type: Error.#[templatia(template = "...")] for custom templates#[templatia(allow_missing_placeholders)] to allow fields not in template#[templatia(empty_str_option_not_none)] to treat empty strings as Some("") for Option<String>templatia::Template.#[templatia(allow_missing_placeholders)] attribute allows fields not in template to use Default::default()None when the placeholder is absent (automatic support without requiring allow_missing_placeholders)type Struct from Template traitVec, HashMap, and HashSetcontainer attribute to increase flexibility at the parent structure level{name?} to make individual placeholders optional
Option<T> fields, treat the placeholder as empty string when value is NoneNone when the placeholder is absent[literal{placeholder}literal]? to make entire template sections optional
#[templatia(template = "[name={name}]?")] omits name= entirely from output when name is NoneThis repository follows AGENTS.md for documentation and testing conventions. In short:
Dual-licensed under either of:
You may use this software under the terms of either license.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.