[](https://crates.io/crates/smart-format)


# Smart Format
Composable, zero-allocation `Display` formatting for Rust.
`smart-format` provides extension traits that add formatting operations to any type implementing
`Display`. Each operation returns a lightweight wrapper that itself implements `Display`, so
operations compose through `fmt::Formatter` without intermediate `String` allocations.
## Why this exists
Rust's `Display` trait is a streaming, zero-alloc formatting interface. But composing `Display`
values is awkward — there's no built-in vocabulary for "escape this, then truncate, then wrap in
tags." People end up calling `.to_string()` at every step, allocating intermediate `String`s that
only exist to be formatted again.
This crate makes the composition part zero-alloc too. Every operation is a struct wrapping
`T: Display` that implements `Display` with a transformation. Chain as many as you want.
## Features
Core functionality (always available):
| `SmartFormat` | `display_wrap()`, `display_prefix()`, `display_suffix()`, `display_if()`, `display_or_if()`, `display_truncate()`, `display_truncate_with()`, `display_pad_left()`, `display_pad_right()` |
| `SmartFormatCase` | `capitalize()`, `lowercase()`, `uppercase()` |
| `DisplayIterator` | `display_concat()`, `display_join(sep)` |
Feature-gated transforms:
| `html` | `SmartFormatHtml` | `html_escape()`, `html_escape_strict()`, `html_unescape_basic()`, `html_attribute(name)` |
| `url` | `SmartFormatUrl` | `url_escape()` |
| `xml` | `SmartFormatXml` | `xml_c_data()` |
| `full` | — | enables all of the above |
## Usage
```toml
[dependencies]
smart-format = { version = "0.1", features = ["html"] }
```
```rust
use smart_format::prelude::*;
// Combinators chain without allocation
let output = "hello world"
.display_truncate(5)
.display_pad_right(10, '.')
.display_wrap("[", "]")
.to_string();
assert_eq!(output, "[hello.....]");
// Case transforms
let title = "hello world".capitalize().to_string();
assert_eq!(title, "Hello world");
// Iterator formatting
let joined = ["a", "b", "c"].iter().display_join(", ").to_string();
assert_eq!(joined, "a, b, c");
// Left-pad (zero-alloc, two-pass)
assert_eq!("007", 7.display_pad_left(3, '0').to_string());
```
With the `html` feature:
```rust
use smart_format::prelude::*;
// Escape, truncate, wrap — all composed, zero intermediate allocations
let safe = "<script>alert('xss')</script>"
.html_escape()
.display_truncate(20)
.display_wrap("<span>", "</span>")
.to_string();
```
## Design decisions
**Zero-alloc by construction.** Every combinator is a struct wrapping `T: Display` that implements
`Display`. No heap allocation happens until someone calls `.to_string()` or writes to a sink.
This is the same pattern used by `Iterator` adapters.
**Feature flags for domain-specific transforms.** HTML/URL/XML escaping adds dependencies and code
that many users don't need. Core text operations (case, iteration) are always available because
they have no extra dependencies and are universally useful.
**Unicode scalar values for width.** Width-sensitive operations (future: pad, truncate) count
Unicode scalar values (`char`), not bytes or grapheme clusters. This is documented as a known
limitation. Grapheme-aware and terminal-width-aware variants may be added behind a feature flag.
**Streaming escaping via bitset.** HTML escape uses a `u128` bitmask for O(1) "needs escaping?"
per ASCII byte. The bitmask is computed at compile time. Non-ASCII bytes pass through unchanged.
## MSRV
**Rust 1.85.0** (edition 2024).
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
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.
## Development
Recommended (enable repo hooks once per clone):
```bash
git config core.hooksPath .githooks
```
Quality gates:
```bash
cargo +nightly fmt --all -- --check
cargo check --all-targets
cargo test --all-features
cargo clippy --all-targets -- -D warnings
```
See also: `CONTRIBUTING.md`.