{"id":36982986,"url":"https://github.com/tdymel/dfmt","last_synced_at":"2026-01-13T22:54:48.988Z","repository":{"id":330168248,"uuid":"1117696213","full_name":"tdymel/dfmt","owner":"tdymel","description":"std::fmt like dynamic template formatting with drop in replacement macros and a fully featured API","archived":false,"fork":false,"pushed_at":"2025-12-29T10:42:12.000Z","size":111,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T22:54:41.538Z","etag":null,"topics":["dynamic","dynamic-templates","formatting","runtime","rust","string"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/dfmt","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tdymel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-16T17:22:50.000Z","updated_at":"2026-01-01T16:00:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tdymel/dfmt","commit_stats":null,"previous_names":["tdymel/dfmt"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tdymel/dfmt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdymel%2Fdfmt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdymel%2Fdfmt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdymel%2Fdfmt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdymel%2Fdfmt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdymel","download_url":"https://codeload.github.com/tdymel/dfmt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdymel%2Fdfmt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28405138,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dynamic","dynamic-templates","formatting","runtime","rust","string"],"created_at":"2026-01-13T22:54:48.300Z","updated_at":"2026-01-13T22:54:48.982Z","avatar_url":"https://github.com/tdymel.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dfmt - `d`ynamic `format!`\n\n`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!`.\n\n```rust\n// Check out the documentation for a complete overview.\nuse dfmt::*;\n\nlet str_template = \"Hello, {0} {{{world}}} {} {day:y\u003cwidth$}!\";\nlet precompiled_template = Template::parse(str_template).unwrap();\n\n// Parsing the str template on the fly\ndprintln!(str_template, \"what a nice\", world = \"world\", day = \"day\", width=20);\n\n// Using a precompiled template\ndprintln!(precompiled_template, \"what a nice\", world = \"world\", day = \"day\", width=20);\n\n// Uses println! under the hood\ndprintln!(\"Hello, {0} {{{world}}} {} {day:y\u003cwidth$}!\", \"what a nice\", \n    world = \"world\", day = \"day\", width=20);\n\n// Other APIs\nlet using_dformat = dformat!(precompiled_template, \"what a nice\", \n    world = \"world\", day = \"day\", width=20).unwrap();\nprintln!(\"{}\", using_dformat);\n\nlet using_manual_builder_api = precompiled_template\n    .arguments()\n    .builder()\n    .display(0, \u0026\"what a nice\")\n    .display(\"world\", \u0026\"world\")\n    .display(\"day\", \u0026\"day\")\n    .width_or_precision_amount(\"width\", \u002620)\n    .format()\n    .unwrap();\nprintln!(\"{}\", using_manual_builder_api);\n\nlet using_str_extension = \"Hello, {0} {{{world}}} {} {day:y\u003cwidth$}!\"\n    .format(vec![\n        (\u00260, ArgumentValue::Display(\u0026\"what a nice\")),\n        (\u0026\"world\", ArgumentValue::Display(\u0026\"world\")),\n        (\u0026\"day\", ArgumentValue::Display(\u0026\"day\")),\n        (\u0026\"width\", ArgumentValue::WidthOrPrecisionAmount(\u002620)),\n    ])\n    .unwrap();\nprintln!(\"{}\", using_str_extension);\n\nlet using_manual_template_builder = Template::new()\n    .literal(\"Hello, \")\n    .specified_argument(0, Specifier::default()\n        .alignment(Alignment::Center)\n        .width(Width::Fixed(20)))\n    .literal(\"!\")\n    .arguments()\n    .builder()\n    .display(0, \u0026\"World\")\n    .format()\n    .unwrap();\nprintln!(\"{}\", using_manual_template_builder);\n```\n\n## Features\n✅ **Support dynamic templates**  \n✅ **All formatting specifiers**  \n✅ **Indexed and named arguments**  \n✅ **Easy to use API and macros**  \n✅ **With safety in mind**  \n✅ **Blazingly fast**  \n✅ **No-std support (Using a global allocator, and only dformat! and write!)**\n\n### Formatting features\n| Name | Feature |\n| ---- | ------- |\n| Fill/Alignment | `\u003c`, `^`, `\u003e` |\n| Sign | `+`, `-` |\n| Alternate | `#` |\n| Zero-padding | `0` |\n| Width | `{:20}`, `{:width$}` |\n| Precision | `{:.5}`, `{:.precision$}`, `{:*}` |\n| Type | `?`, `x`, `X`, `o`, `b`, `e`, `E`, `p` |\n| Argument keys | `{}`, `{0}`, `{arg}` |\n\n## How it works\n* If the template is a literal, then the `format!` macro is used under the hood.\n* Uses the `core::fmt` machinery under the hood. Therefore, you can expect the same formatting behaviour.\n* It uses [black magic](https://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html) to provide a comfortable macro.\n\n## Safety\nThere are multiple runtime checks to prevent you from creating an invalid format string.\n* Check if the required argument value exists and implements the right formatter.\n* Check for duplicate arguments\n* Validate the template\n\n## Performance\nIn the best case `dfmt` is as fast as `format!`. In the worst case, its up to 60% - 100% slower.\n\nHowever, I believe with further optimization this gap could be closed. In fact, with the `formatting_options` feature we are even faster in some cases.\n\n### Considerations\n* While the template parsing is fast, you can just **create it once and then reuse it** for multiple arguments.\n* There is a **unchecked** version, which skips safety checks.\n* If the template is a literal, it will fall back to **format!** internally if you use the macro.\n\n### Overhead\n* When creating the `Arguments` structure, a vector is allocated for the arguments. This is barely noticeable for many arguments.\n* Right now padding a string with a fill character will cost some overhead.\n* If a pattern reuses an argument multiple times, it will push a typed version of this value multiple times right now. This allocates more memory, but is required to provide a convinient API.\n* The macros for convinience, incour some overhead due to auto-deref specialization. Its about 5-10 ns per value.\n\n### Nightly\nIf you are on nightly, you can opt in to the `nightly_formatting_options` feature to further improve the performance, \nespecially for the fill character case and to reduce compilation complexity.\n\n### Benchmarks\nThese benchmarks compare `dfmt` with `format!` with dynamic arguments only. Obviously, if `format!` makes use of const folding, it will be much faster.\n\n#### Without `formatting_options` feature\n\n| Benchmark | simple - 1 arg | simple - 7 args | complex |\n| --------- | -------------- | --------------- | ------- |\n| Template::parse | 67 ns | 249 ns | 684 ns |\n| **format!** | **30 ns** | 174 ns | **515 ns** |\n| Template unchecked | 46 ns | **173 ns** | 845 ns |\n| Template checked | 49 ns | 250 ns | 911 ns |\n| dformat! unchecked | 51 ns | 235 ns | 952 ns |\n| dformat! checked | 51 ns | 260 ns | 1040 ns |\n\n#### With `formatting_options` feature\n| Benchmark | simple - 1 arg | simple - 7 args | complex |\n| --------- | -------------- | --------------- | ------- |\n| Template::parse | 67 ns | 249 ns | 684 ns |\n| **format!** | **30 ns** | 174 ns | 515 ns |\n| Template unchecked | 46 ns | **169 ns** | **464 ns** |\n| Template checked | 49 ns | 238 ns | 527 ns |\n| dformat! unchecked | 51 ns | 232 ns | 576 ns |\n| dformat! checked | 51 ns | 257 ns | 658 ns |\n\n## Minimal rustc version\nRight now it compiles until 1.81, this is when `std::error` went into `core::Error`. \nYou can opt out of `error`-impl by disabling the feature `error`. Then you can go down until 1.56.\n\n## License\nThis project is dual licensed under the Apache 2.0 license and the MIT license.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdymel%2Fdfmt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftdymel%2Fdfmt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdymel%2Fdfmt/lists"}