September 9, 2021·5 min read·engineeringrustparsingcargo

Rust 1.55 replaces floating-point parsing and removes duplicate diagnostics

The Eisel-Lemire parser improves common-case speed and repairs difficult decimal inputs. Cargo also reports repeated compiler diagnostics without printing their full text twice.

Converting decimal text into a binary floating-point value is a rounding problem as well as a scanning problem. A parser has to identify the digits and exponent, then produce the appropriate representable result. Rust 1.55 changes that implementation in ways that improve common inputs and repair edge cases the previous code could reject.

The September 9 release announcement identifies the Eisel-Lemire algorithm as the basis of the new parser. It also introduces Cargo's deduplication of compiler errors and warnings. Both affect routine developer work, but the parser's correctness history is the more substantial technical story.

I am interested in Rust's handling of low-level correctness obligations, including ones that are easy to hide behind a familiar parse call. A standard conversion API lets callers delegate this complexity. The implementation still has to account for difficult decimal inputs that ordinary application examples rarely exercise.

The old intermediate had a capacity limit

The implementation pull request explains that the previous decimal-to-float code used a fixed-capacity Big32x40 representation in difficult cases. Some very small values with many decimal digits needed more intermediate precision to round correctly than that representation supplied. Valid decimal strings could consequently fail to parse.

The new implementation uses a custom decimal representation for those cases and describes support for valid decimal strings regardless of their digit count. This is a correctness change in the accepted input population. It should not be reduced to the claim that ordinary short numbers parse faster.

The pull request includes regression tests for long literals and very small values. One test checks the exact floating-point bit pattern produced from a long decimal representation of one third. Another checks a long significand paired with a large negative exponent. Checking the bit representation examines the conversion result itself, not merely whether parsing stopped returning an error.

This matters near rounding boundaries. A plausible printed decimal result can hide a different binary value. A test that asserts the intended bit pattern can distinguish neighboring representable values even when a short display would not make the difference obvious.

The fast path has explicit conditions

The implementation discussion also describes the inexpensive path for values whose significant digits and exponent fit exact machine operations. For f64, it discusses a significand fitting within 53 bits and a limited exponent range. Within those conditions, the parser can avoid more general conversion work.

Some inputs only appear to fall outside that path. A small significand with a larger decimal exponent can sometimes shift powers of ten into the significand while retaining the conditions needed for the fast operation. The pull request calls these disguised fast-path cases. The optimization changes the representation used internally without changing the number represented by the input.

Digit scanning improves too. The discussion describes processing eight digits together with fewer multiplications than a straightforward one-digit-at-a-time method. This addresses work before the final binary conversion. A faster algorithm for rounding would still leave unnecessary scanning overhead if every decimal digit required the older sequence of operations.

The pull request reports substantial benchmark differences for particular datasets and hardware, including an Apple M1 comparison. Those figures are evidence about the measured cases. They are not a prediction that an arbitrary program will become several times faster after upgrading. The application-level effect depends on how much time it spends parsing floats and which inputs it receives.

Library integration includes maintainability work

The contribution adapts code from fast-float-rust for Rust's core library. Its description emphasizes documentation for algorithmic constants and a reduction in unsafe operations. This is relevant because a mathematically justified algorithm still needs an implementation that maintainers can review and change.

One example replaces pointer arithmetic used to test a buffer length with a direct comparison against a slice length. Another makes unchecked advancement operations visibly unsafe and documents the conditions their callers establish. These changes clarify which facts the implementation relies on at each access boundary.

The pull request also repairs the float-parser testing tools and reports results from several comprehensive test collections. Such results support the implementation's validation. They do not turn a collection of passing cases into a proof of every future modification, which is why documentation and explicit unsafe boundaries remain useful.

I appreciate that the contribution treats integration as more than copying an algorithm into the standard library. The code needs repeatable correctness checks and explanations for operations that would otherwise look arbitrary. Both help the next maintainer distinguish an essential condition from an incidental implementation choice.

Cargo separates diagnostics from repeated builds

Cargo's other visible change addresses crates built in several configurations during one command. The release announcement gives cargo check with all targets as an example. A library and its test build can cause separate compiler invocations to emit the same warning, previously printing its full text twice.

Rust 1.55 deduplicates that diagnostic text and adds a summary identifying the duplicate. The announcement's example prints the unused-function warning once, then reports one warning for the library and one duplicate for the library test. The separate configurations remain visible through the summary.

This is a presentation change rather than evidence that Cargo has removed one of the compilations. Different configurations can still need their own builds. The improvement prevents identical diagnostic text from occupying repeated space while retaining information about which targets generated warnings.

The distinction makes output easier to interpret. A reader can focus on unique diagnostics without assuming that each repeated rendering represents a separate underlying issue. The final summaries still show that more than one configuration encountered the warning.

Error categories become more explicit

The release also moves uncategorized standard-library I/O errors away from ErrorKind::Other into an internal Uncategorized variant. ErrorKind is non-exhaustive. The announcement says callers should use a wildcard for error kinds they do not know, while Other remains appropriate for constructed errors that deliberately use that category.

This prepares for adding more categories without making Other an implied catalogue of operating-system error codes. A caller can handle a known portable category, then propagate or inspect an unknown error through the fallback. The release's parser and diagnostic changes similarly reward precise interpretation of what the API or output actually establishes.