Rust 1.98 Gives Integer Formatting a Buffer-First Path
Rust 1.98 stabilizes `format_into`, letting integer values render into a caller-provided numeric buffer. For Rust services and ICP canisters that repeatedly serialize counters, IDs, or amounts, the API offers a standard-library alternative to allocation-heavy formatting paths.

Rust 1.98.0, released on August 20, adds a small but practical primitive to the standard library: every built-in integer type now exposes format_into.
The method accepts a mutable core::fmt::NumBuffer<Self> and returns a string slice borrowed from that buffer. The buffer is opaque, but Rust guarantees that it is large enough to hold the decimal representation of any value of the integer type. That design makes the storage decision explicit: the caller owns the reusable formatting space, while the returned &str remains tied to it.
A minimal pattern looks like this:
let value: u64 = 42_000;
let mut buffer = core::fmt::NumBuffer::<u64>::new();
let text = value.format_into(&mut buffer);
assert_eq!(text, "42000");
The important change is not a new formatting syntax. It is a new boundary between numeric conversion and allocation. Rust’s release announcement says format_into bypasses much of the dynamic dispatch associated with buffered write! formatting and can perform similarly to the itoa library in the project’s benchmark. The benchmark repository describes a workload covering random u32, u64, and u128 values grouped by decimal length.
That matters in code that emits many short numeric fields: telemetry lines, protocol messages, account identifiers, sequence numbers, and serialized transaction metadata. A reusable buffer can reduce temporary objects and make the lifetime of the formatted text visible in the type system. In an ICP canister or supporting Rust service, that can be useful when constructing repetitive responses or logs, although the API does not by itself remove the cost of the surrounding message or serialization format.
There are two review points for adopters. First, format_into is decimal formatting; it is not a general replacement for hexadecimal, binary, locale-aware, or structured serialization APIs. Second, the published benchmark is evidence of a measured comparison, not a universal performance guarantee: its repository records a particular workload, machine, and Rust version. Teams should benchmark their own hot path before removing an established dependency.
The practical migration path is conservative. Upgrade the toolchain to Rust 1.98, replace a narrowly scoped integer-to-string conversion with format_into, and measure allocations and latency under the real workload. Keep broader write! or serializer code where it expresses a more complex format. Rust 1.98 therefore turns a common micro-optimization into a standard-library choice, without making performance claims that every application must inherit.
Get the wire in your inbox
Every new signal, straight from the generator. No noise, unsubscribe anytime.


