The STDLIB log

Eighteen crates, and what the standard library did instead.

The canonical file is STDLIB.md, and it carries the part that matters: an honest what I gave up paragraph on every entry. This page is the index — what was replaced, by what, and where the code is. It deliberately does not repeat the rationale, because two copies of an argument drift and one of them starts lying.

Download counts are what the crates.io API returned on 2026-08-28, quoted in the two forms it actually reports. It has no weekly figure, so none is invented.

Package Killer nomination

serde_json — 1,227,048,507 all-time · 288,758,389 in 90 days

rand is bigger — 1,605,926,795 — and it is deliberately not the nomination. The bonus asks for one crate nailed, and five lines of xorshift is not a case for anything. The nomination goes to the substitution with the most work behind it, not to the largest number in the table.

src/json.rs is a complete RFC 8259 reader: escapes, \uXXXX with surrogate-pair recombination, the number grammar checked by hand before f64::from_str sees the slice, a nesting limit, and line/column on every error derived from a byte offset.

The position tracking is the part worth defending. The parser keeps the original input alongside the unconsumed remainder and asks the standard library where one sits inside the other — str::substr_range, stable in 1.98. No cursor struct threaded through thirty functions, no line counter to keep in sync, because the cursor is the remainder.

The other seventeen

crateall-timereplaced bywhat did the work
rand1,605,926,795src/distance.rs, tests/five lines of xorshift64*, seeded from SystemTime
thiserror1,377,720,340src/error.rsone enum, hand-written Display and Error::source
itoa1,265,455,201src/report.rscore::fmt::NumBuffer + format_into (1.98)
once_cell1,187,857,958src/corpus.rsstd::sync::LazyLock (1.80)
clap1,083,204,108src/cli.rsa match over std::env::args
strsim1,024,185,642src/distance.rsunrestricted Damerau-Levenshtein, written out
semver945,451,453src/semver.rsthe precedence rules from the spec's section 11
anyhow909,556,524src/error.rsthe same enum, with ?
toml855,052,855src/toml.rsa documented subset that refuses what it cannot read
walkdir588,096,443src/walk.rsstd::fs::read_dir and an explicit stack
glob575,867,559src/walk.rsstr::ends_with against seven known names
crossbeam-channel565,386,665src/main.rsstd::sync::mpsc
rayon516,056,344src/main.rsstd::thread::scope
serde_yaml383,697,832src/yaml.rsan indentation-driven subset, two booleans only
is-terminal324,499,410src/term.rsstd::io::IsTerminal (1.70)
owo-colors156,700,441src/term.rssixteen-colour SGR, written out
comfy-table94,630,283src/term.rscolumn widths measured from content

13,459,345,853 all-time downloads across those seventeen, and 14,686,394,360 with the nomination. The bonus asks for ten entries.

Three of these were free, and saying so is the point

itoaNumBuffer::format_into and once_cellLazyLock are substitutions the toolchain made for me. LazyLock landed in 1.80 and format_into in 1.98, eight days before the window opened. Neither cost an hour, and claiming them as craft would be claiming a stable release as personal work.

is-terminal is the third and it is the interesting one, because avoiding it avoided unsafe. The usual replacement is an FFI call to libc::isatty, which needs an unsafe block and would have broken #![forbid(unsafe_code)] at both crate roots. std::io::IsTerminal has done it safely since 1.70.

What is not claimed

indicatif. Nothing here draws a progress bar: the largest fixture scans in under half a second, and a bar that finishes before it renders is a dependency bought for one frame. Writing a spinner so that a spinner crate could be crossed off is padding rather than substitution.

The rule the log enforces on itself is that an unwritten module gets no entry. That is why src/semver.rs is in the table. It has ten tests, and for one day it was also the one module nothing called — which the log said out loud rather than implying it was load-bearing. Version drift sorts with it now.

Data that is not code, disclosed anyway

corpus/ holds 160,066 package names across three registries, fetched once with curl at development time on 2026-08-28. fixtures/ holds fourteen real lockfiles from public projects plus two poisoned by hand.

Neither is code — the corpora are embedded with include_str! and read as text, and the fixtures are test input. The hackathon's rule is that anything not written during the window is disclosed in STDLIB.md or it scores against you, and a name list is exactly the sort of thing it would be convenient to forget. Full provenance is in corpus/PROVENANCE.md and fixtures/README.md.

$ wc -l corpus/*.txt
    5000 corpus/crates-io.txt
  140066 corpus/npm.txt
   15000 corpus/pypi.txt
  160066 total