rs-format-rebind-hot — format! rebind accumulation in loop
Claim
Hot-loop s = format!("{s}…") / s = format!("{}{}", s, …) accumulation on Rust is substantially slower than String::with_capacity + write! / push_str, because each format! allocates a fresh String and copies the growing prefix (quadratic-ish).
How measured
Same harness and run as the former rs-string-plus-in-loop format! pair (not re-invented):
- Harness:
packages/rustperf/examples/bench/evidence_rs002.rs(Pair C) - Build:
rustc -C opt-level=3 evidence_rs002.rs -o out/evidence_rs002 - Timer:
std::time::Instantwall clock; warm=3; median of 9;std::hint::black_box - Pair C (matches fixtures
rustperf-lint/fixtures/bad/rs-format-rebind-hot_format_rebind.rs/ goodrs-format-rebind-hot_write.rs): N=20000- before:
s = format!("{s}{i}")in loop - after:
with_capacity+write!(s, "{i}")
- before:
- Raw lines:
rs-format-rebind-hot.jsonl— aliased from the 2026-10-22 rs-string-plus-in-loop G4 JSONL (rulefield set tors-format-rebind-hot;aliased_from=rs-string-plus-in-loop; samemedian_ms/ops/ts)
Runtime (this evidence file)
| Field | Value |
|---|---|
| When | 2026-10-22 Asia/Shanghai (machine clock; JSONL ts is UTC) |
| rustc | 1.99.1 |
| Opt | opt-level=3 (-C opt-level=3) |
Median before (digits_format_accum) | 28.652 ms |
Median after (digits_write) | 0.288 ms |
| ratio format! before/after | ~100× |
Direction: format! rebind accumulation is a large, stable win for the flagged smell. Absolute ms and ratios are N/machine/opt-sensitive.
Lint mapping
rustperf-lint rs-format-rebind-hot fires only when a loop line has ident = format!(…) (not let ident = format!(…)) and the format body/args reuse ident ({ident} or positional token). Bare format!(…) exprs and fresh let-bindings stay quiet. Default severity error under evidence-policy: the flagged smell itself is ~99×. Path skips mirror rs-string-plus-in-loop (shells / cold CLI formatters). Amortized += / push_str stays on rs-string-plus-in-loop (hint).
Limits
- Microbench; not an app profile.
- Line heuristic can still hit one-shot wraps that reuse the LHS once per outer iteration (see G3 residual note) — override with
--severity rs-format-rebind-hot=off/hintif needed. - Does not measure
Writetrait objects,itoa, or SSO. - Historical note: written before r4 redesign; kit is now corpus-ready (see docs/corpus.md).