| Crates.io | dfmt |
| lib.rs | dfmt |
| version | 0.3.1 |
| created_at | 2025-12-22 12:21:40.212762+00 |
| updated_at | 2025-12-29 10:42:16.5155+00 |
| description | A fully featured dynamic template drop in replacement for the format! macro. |
| homepage | |
| repository | https://github.com/tdymel/dfmt |
| max_upload_size | |
| id | 1999635 |
| size | 100,055 |
dynamic format!dfmt provides core::fmt-like formatting for dynamic templates and is a fully featured dynamic drop in replacment for the macros: format!, print!, println!, eprint!, eprintln!, write!, writeln!.
// Check out the documentation for a complete overview.
use dfmt::*;
let str_template = "Hello, {0} {{{world}}} {} {day:y<width$}!";
let precompiled_template = Template::parse(str_template).unwrap();
// Parsing the str template on the fly
dprintln!(str_template, "what a nice", world = "world", day = "day", width=20);
// Using a precompiled template
dprintln!(precompiled_template, "what a nice", world = "world", day = "day", width=20);
// Uses println! under the hood
dprintln!("Hello, {0} {{{world}}} {} {day:y<width$}!", "what a nice",
world = "world", day = "day", width=20);
// Other APIs
let using_dformat = dformat!(precompiled_template, "what a nice",
world = "world", day = "day", width=20).unwrap();
println!("{}", using_dformat);
let using_manual_builder_api = precompiled_template
.arguments()
.builder()
.display(0, &"what a nice")
.display("world", &"world")
.display("day", &"day")
.width_or_precision_amount("width", &20)
.format()
.unwrap();
println!("{}", using_manual_builder_api);
let using_str_extension = "Hello, {0} {{{world}}} {} {day:y<width$}!"
.format(vec![
(&0, ArgumentValue::Display(&"what a nice")),
(&"world", ArgumentValue::Display(&"world")),
(&"day", ArgumentValue::Display(&"day")),
(&"width", ArgumentValue::WidthOrPrecisionAmount(&20)),
])
.unwrap();
println!("{}", using_str_extension);
let using_manual_template_builder = Template::new()
.literal("Hello, ")
.specified_argument(0, Specifier::default()
.alignment(Alignment::Center)
.width(Width::Fixed(20)))
.literal("!")
.arguments()
.builder()
.display(0, &"World")
.format()
.unwrap();
println!("{}", using_manual_template_builder);
✅ Support dynamic templates
✅ All formatting specifiers
✅ Indexed and named arguments
✅ Easy to use API and macros
✅ With safety in mind
✅ Blazingly fast
✅ No-std support (Using a global allocator, and only dformat! and write!)
| Name | Feature |
|---|---|
| Fill/Alignment | <, ^, > |
| Sign | +, - |
| Alternate | # |
| Zero-padding | 0 |
| Width | {:20}, {:width$} |
| Precision | {:.5}, {:.precision$}, {:*} |
| Type | ?, x, X, o, b, e, E, p |
| Argument keys | {}, {0}, {arg} |
format! macro is used under the hood.core::fmt machinery under the hood. Therefore, you can expect the same formatting behaviour.There are multiple runtime checks to prevent you from creating an invalid format string.
In the best case dfmt is as fast as format!. In the worst case, its up to 60% - 100% slower.
However, I believe with further optimization this gap could be closed. In fact, with the formatting_options feature we are even faster in some cases.
Arguments structure, a vector is allocated for the arguments. This is barely noticeable for many arguments.If you are on nightly, you can opt in to the nightly_formatting_options feature to further improve the performance,
especially for the fill character case and to reduce compilation complexity.
These benchmarks compare dfmt with format! with dynamic arguments only. Obviously, if format! makes use of const folding, it will be much faster.
formatting_options feature| Benchmark | simple - 1 arg | simple - 7 args | complex |
|---|---|---|---|
| Template::parse | 67 ns | 249 ns | 684 ns |
| format! | 30 ns | 174 ns | 515 ns |
| Template unchecked | 46 ns | 173 ns | 845 ns |
| Template checked | 49 ns | 250 ns | 911 ns |
| dformat! unchecked | 51 ns | 235 ns | 952 ns |
| dformat! checked | 51 ns | 260 ns | 1040 ns |
formatting_options feature| Benchmark | simple - 1 arg | simple - 7 args | complex |
|---|---|---|---|
| Template::parse | 67 ns | 249 ns | 684 ns |
| format! | 30 ns | 174 ns | 515 ns |
| Template unchecked | 46 ns | 169 ns | 464 ns |
| Template checked | 49 ns | 238 ns | 527 ns |
| dformat! unchecked | 51 ns | 232 ns | 576 ns |
| dformat! checked | 51 ns | 257 ns | 658 ns |
Right now it compiles until 1.81, this is when std::error went into core::Error.
You can opt out of error-impl by disabling the feature error. Then you can go down until 1.56.
This project is dual licensed under the Apache 2.0 license and the MIT license.