Use version-sorting for all sorting

Add a description of a version-sorting algorithm. (This algorithm does
not precisely match `strverscmp`; it's intentionally simpler in its
handling of leading zeroes, and produces a result easier for humans to
easily understand and do by hand.)

Change all references to sorting to use version-sorting.

Change all references to "ASCIIbetically" to instead say "sort
non-lowercase before lowercase".
This commit is contained in:
Josh Triplett 2023-08-21 00:37:06 -07:00
parent c60ff10ffd
commit 98d3012ed9
4 changed files with 56 additions and 11 deletions

View file

@ -99,6 +99,42 @@ fn bar() {}
fn baz() {}
```
### Sorting
In various cases, the default Rust style specifies to sort things. If not
otherwise specified, such sorting should be "version sorting", which ensures
that (for instance) `x8` comes before `x16` even though the character `1` comes
before the character `8`. (If not otherwise specified, version-sorting is
lexicographical.)
For the purposes of the Rust style, to compare two strings for version-sorting:
- Compare the strings by (Unicode) character as normal, finding the index of
the first differing character. (If the two strings do not have the same
length, this may be the end of the shorter string.)
- For both strings, determine the sequence of ASCII digits containing either
that character or the character before. (If either string doesn't have such a
sequence of ASCII digits, fall back to comparing the strings as normal.)
- Compare the numeric values of the number specified by the sequence of digits.
(Note that an implementation of this algorithm can easily check this without
accumulating copies of the digits or converting to a number: longer sequences
of digits are larger numbers, equal-length sequences can be sorted
lexicographically.)
- If the numbers have the same numeric value, the one with more leading zeroes
comes first.
Note that there exist various algorithms called "version sorting", which differ
most commonly in their handling of numbers with leading zeroes. This algorithm
does not purport to precisely match the behavior of any particular other
algorithm, only to produce a simple and satisfying result for Rust formatting.
(In particular, this algorithm aims to produce a satisfying result for a set of
symbols that have the same number of leading zeroes, and an acceptable and
easily understandable result for a set of symbols that has varying numbers of
leading zeroes.)
As an example, version-sorting will sort the following symbols in the order
given: `x000`, `x00`, `x0`, `x01`, `x1`, `x09`, `x9`, `x010`, `x10`.
### [Module-level items](items.md)
### [Statements](statements.md)

View file

@ -8,11 +8,11 @@ Put a blank line between the last key-value pair in a section and the header of
the next section. Do not place a blank line between section headers and the
key-value pairs in that section, or between key-value pairs in a section.
Sort key names alphabetically within each section, with the exception of the
Version-sort key names within each section, with the exception of the
`[package]` section. Put the `[package]` section at the top of the file; put
the `name` and `version` keys in that order at the top of that section,
followed by the remaining keys other than `description` in alphabetical order,
followed by the `description` at the end of that section.
followed by the remaining keys other than `description` in order, followed by
the `description` at the end of that section.
Don't use quotes around any standard key names; use bare keys. Only use quoted
keys for non-standard keys whose names require them, and avoid introducing such

View file

@ -37,6 +37,8 @@ history of the style guide. Notable changes in the Rust 2024 style edition
include:
- Miscellaneous `rustfmt` bugfixes.
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
## Rust 2015/2018/2021 style edition

View file

@ -9,8 +9,8 @@ an item appears at module level or within another item.
alphabetically.
`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
must come before other items. Put imports before module declarations. Sort each
alphabetically, except that `self` and `super` must come before any other
must come before other items. Put imports before module declarations.
Version-sort each, except that `self` and `super` must come before any other
names.
Don't automatically move module declarations annotated with `#[macro_use]`,
@ -441,8 +441,10 @@ foo::{
A *group* of imports is a set of imports on the same or sequential lines. One or
more blank lines or other items (e.g., a function) separate groups of imports.
Within a group of imports, imports must be sorted ASCIIbetically (uppercase
before lowercase). Groups of imports must not be merged or re-ordered.
Within a group of imports, imports must be version-sorted, except that
non-lowercase characters (characters that can start an `UpperCamelCase`
identifier) must be sorted before lowercase characters. Groups of imports must
not be merged or re-ordered.
E.g., input:
@ -469,10 +471,15 @@ re-ordering.
### Ordering list import
Names in a list import must be sorted ASCIIbetically, but with `self` and
`super` first, and groups and glob imports last. This applies recursively. For
example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
Names in a list import must be version-sorted, except that:
- `self` and `super` always come first if present,
- non-lowercase characters (characters that can start an `UpperCamelCase`
identifier) must be sorted before lowercase characters, and
- groups and glob imports always come last if present.
This applies recursively. For example, `a::*` comes before `b::a` but `a::b`
comes before `a::*`. E.g., `use foo::bar::{a, b::c, b::d, b::d::{x, y, z},
b::{self, r, s}};`.
### Normalisation