syn-canon
Canonical form of a syn file. Two files that differ only in formatting, in style rustfmt or a reviewer would not call a difference, or in the names of their local binders print the same canonical tokens, so their hashes match.
let canonical = ;
assert_eq!;
assert_ne!;
no_std with alloc. It powers cargo-dejadoc, which finds duplicated doctests.
Folds
Every binder becomes a positional name in visit order: let and closure patterns, function names and parameters, generics, lifetimes, labels, local items, use aliases and macro_rules! names. Item names of a file, block or inline module are bound before the list is visited, so a use may precede its definition. Free names, fields, methods and attribute paths stay, and so do string literals. Self in type position expands to the impl self type. Macro arguments that parse as an expression list or elem; count are renamed as expressions, otherwise token by token.
Style folds, each applied only where it keeps the meaning:
useitems flatten to one sorted item per leaf path at the front of their list.{ expr }arm and closure bodies becomeexpr, and no arm keeps its comma.else { if … }becomeselse if ….- A tail
return vbecomesv, also in the arms of a tailmatch, and a trailing unitreturngoes. - Redundant parentheses around expressions, patterns and types go, and so do
-> ()and empty statements. - Inline generic bounds move into
where,&'_ Tbecomes&T,Foo<'_>becomesFoooutside an impl header, and&'staticbecomes&in aconstorstatictype. - Identifier arguments of the std formatting macros move into the format string,
println!("{}", x)becomingprintln!("{x}"). - Macro calls take parentheses, and every statement macro but the tail one takes a semicolon.
derivelists of std derives merge into one sorted list.doc, lint level andrustfmt::attributes go.- Literals take one spelling,
0x10and16alike, and no group keeps a trailing comma.
Stability
The canonical tokens are the contract. Any change to them, a new fold included, is a new major version, so hashes stored by one version stay comparable within it.