Python → Rust · behavioral parity

natsort, ported
to Rust — proven
to order alike.

A Rust reimplementation of Python's natsort library. Not just rewritten — every algorithm is checked against the original until they sort byte-for-byte identically.

0

Divergences

Across 21,000 comparisons spanning the full Unicode character set and all seven algorithms, the port and the original library never disagree on order.

01 By the numbers
100%
Unicode parity
all 7 algorithms
28
Original tests
unmodified · sha-256
44
Native tests
unit + property
5/5
Mutations killed
100% catch rate
91%
Core coverage
src/lib.rs
0
Unsafe blocks
compiler-forbidden
0
Clippy warnings
-D warnings in CI
2,209
Unicode chars
digit tables embedded
02 How parity is proven
/01
Original test suitenatsort's own tests, byte-identical, run against the Rust binary
28 pass
/02
Differential fuzzrandom inputs × 7 algorithms vs the live Python library
0 divergences
/03
Full-Unicode sweep21,000 comparisons across digits, romans, fractions, ligatures
0 divergences
/04
CLI differential2,800 sort + compare invocations, stdout compared
0 divergences
/05
Mutation testingdeliberate bugs injected to check the tests have teeth
5/5 killed
/06
Memory safetyunsafe forbidden at the crate level by the compiler
0 unsafe
03 A bug in the original

Differential testing surfaced a genuine issue in natsort itself. Under ns.REAL, numeric values above the float maximum (~1.8 × 10³⁰⁸) overflow to inf — so two distinct large numbers compare equal and their order is silently lost.

The Rust port reproduces this exactly, so parity holds. Filed upstream: natsort#192 ↗.

04 Unicode, in full

Three character classes are handled exactly as natsort does them: decimal digits (fullwidth 0-9, Arabic-Indic ٠-٩, Thai, Devanagari) concatenate into numbers; isolated digits (circled ①, superscript ²) each become a separate single-digit number; numeric non-digits (Roman Ⅷ, fraction ½) are numbers under REAL only.

Input is NFD-normalized and case-insensitive modes use casefolding (ß → ss, fi → fi), so accented and cased text orders identically to Python.

05 Performance, honestly
4.7x
Mean speedup
50k-item workload
4.7x
p99 speedup
not just hot-loop
4.1x
Less peak RSS
7.7MB vs 31.8MB
0
Python runtime needed
single binary

4.7x, not 10x — reported as measured. natsort's Python implementation is already reasonably optimized, which caps the ceiling for an algorithmic port. The clearer win is memory: 4.1x less peak RSS, and no Python runtime is required at all.