Skip to content

docs(plan): in_place_sort, in_place_dedup, itertools_sort_dedup_collect#313

Draft
KSXGitHub wants to merge 4 commits into
masterfrom
claude/serene-hypatia-jx34ai
Draft

docs(plan): in_place_sort, in_place_dedup, itertools_sort_dedup_collect#313
KSXGitHub wants to merge 4 commits into
masterfrom
claude/serene-hypatia-jx34ai

Conversation

@KSXGitHub

@KSXGitHub KSXGitHub commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Planning docs (docs(plan), no Rust) for the lints proposed in the issue: prefer the into-sorted / into-deduped crates over in-place Vec mutation and over itertools' sorted* / dedup* adaptors.

Three new files under planned-rules/, plus a "Sorting and deduplication" section in the README index:

  • in_place_sort — an owned Vec binding whose very next statement sorts it in place (Vec::sort*) folds into the owning into_sorted*.
  • in_place_dedup — same shape for Vec::dedup*into_deduped*. Excludes itertools::unique (non-consecutive; no into-deduped equivalent).
  • itertools_sort_dedup_collect — an itertools sorted* / dedup* chain ending in a Vec collect() → collect-first owning form (the issue's opt-level = 3 codegen point).

Design notes (documented in the files, open to review):

  • Source-agnostic trigger. The two in-place rules fire on any by-value owned Vec binding immediately followed by an in-place sort/dedup — a collect(), a vec! literal, a Vec-returning call, a moved binding. The owning fold (x.into_sorted() / x.into_deduped()) is value-identical for every owned Vec, so the earlier collect-only scope was dropped — that is the in_place_*_after_collectin_place_* rename. A &Vec / &mut Vec binding stays out of scope (the into_* methods consume by value).
  • No mut analysis. in_place_sort / in_place_dedup deliberately do not analyse whether the mut is necessary — an in-place sort/dedup already requires mut, the fold is value-identical, and rustc's unused_mut removes the now-redundant mut. They read only the two adjacent statements.
  • They cascade. collect; sort; dedup collapses to one collect().into_sorted().into_deduped() over successive --fix iterations, source order preserved — so the combined case is handled rather than skipped. With the source-agnostic trigger it needs no special-casing: a chain already ending in into_sorted() is just another owned Vec.
  • All three use "Why restrict this?" (a correct-but-slower binary is treated as a preference per the catalogue convention). Method-name mappings come from the crates' own source.

The issue is still marked "under construction", so these files capture the design as currently framed; rule count, names, and scope can be revised here.

Resolves #308.

…ect`, `itertools_sort_dedup_collect`

Plan the three lint rules requested in #308, which
proposes preferring the `into-sorted` and `into-deduped` crates.

Problem 1 (`mut` elided by an owning transform) becomes two rules, as the
issue asks — one for sorting, one for deduping:

- `in_place_sort_after_collect`: an iterator collected into a `Vec` whose
  binding is `mut` only so a following `Vec::sort*` can run in place;
  prefer the owning `into_sorted*` method.
- `in_place_dedup_after_collect`: the same shape for `Vec::dedup*`;
  prefer `into_deduped*`. Excludes non-consecutive dedup
  (`itertools::unique`), which has no `into-deduped` equivalent.

Problem 2 (itertools codegen) becomes one rule, because the adaptors
compose in a single chain that must be rewritten as a unit:

- `itertools_sort_dedup_collect`: an `itertools` `sorted*` / `dedup*`
  adaptor chain terminated by a `Vec` `collect()`; prefer collecting
  first and applying the owning methods.

Method-name mappings were taken from the crates' own source
(`IntoSorted` / `IntoSortedUnstable` / `IntoDeduped`). README index gains
a "Sorting and deduplication" section.

The issue is still marked "under construction", so these files capture
the design as currently framed; rule count, names, and scope can be
revised in review.
@KSXGitHub KSXGitHub linked an issue Jun 22, 2026 that may be closed by this pull request
claude added 3 commits June 22, 2026 06:54
Addresses two design flaws in the first draft of
`in_place_sort_after_collect` / `in_place_dedup_after_collect`, raised in
review of #308:

1. Detecting whether the `mut` is necessary required a borrow walk over
   every later use of the binding — costly and the wrong anchor. An
   in-place `vec.sort()` only type-checks when `vec` is already `mut`, so
   `mut` is implied by the trigger, and folding the call into the
   initializer is value-identical regardless of later uses. The rules now
   read only the two adjacent statements (collect-rooted `let` + the
   immediately-following in-place call), keep the `mut` as written, and
   leave removal of the now-redundant `mut` to rustc's `unused_mut`.

2. `collect; sort; dedup` was silently skipped, because each rule's
   "is the mut needed for anything else" check was failed by the *other*
   operation. The rules now cascade: each accepts a collect-rooted owning
   chain as its initializer and folds the in-place operation that
   immediately follows, so the sequence collapses to one
   `collect().into_sorted().into_deduped()` over successive `--fix`
   iterations, source order preserved.

Updates the itertools rule's cross-reference and the README index entries
to match. The `itertools_sort_dedup_collect` rule is unchanged (it never
had the mut problem — it rewrites a single expression chain).
Sync this feature branch with master (now 0.0.0-rc.19). Notable
changes pulled in:

- Git hooks: commit-msg is split into per-check scripts under
  .githooks/commit-msg-hooks/ with shared helpers in .githooks/lib/.
  Installation is now just `git config core.hooksPath .githooks`
  (the redundant chmod was dropped, as the hook files carry the
  executable bit in git).
- A new commit-msg check rejects commit subject lines longer than
  72 characters, with a PERFECTIONIST_GIT_HOOK_ALLOW_LONG_SUBJECT
  tri-state opt-out.
- Doc conventions: a declare_tool_lint! rustdoc block must describe
  behaviour, not pass machinery; per-site self-suppression examples
  use #[expect(perfectionist::...)] over #[allow(...)].
- excessive_inline_tests no longer misclassifies cfg(any(test, ...))
  as test-only.

No conflicts: this branch only adds the in-place-sort-after-collect,
in-place-dedup-after-collect, and itertools-sort-dedup-collect
planning files (plus their README index entries), none of which
master touches.

Co-authored-by: Claude <noreply@anthropic.com>
The `_after_collect` suffix named a mechanic that did no correctness
work. Requiring the sorted/deduped `Vec` to come from an
`Iterator::collect` was pure issue-scoping: the owning fold
(`x.into_sorted()` / `x.into_deduped()`) is value-identical for *any*
owned `Vec` the binding holds — a `vec![…]` literal, a `Vec`-returning
call, a moved binding — as the old "Out of scope" bullet already
conceded. Collect is also the *hardest* source (its element type is
often fixed only by the `let` annotation the fix removes, forcing the
`::<Vec<_>>()` turbofish), while the excluded sources carry concrete
types and fold trivially.

So drop the restriction and the suffix:

- Rename `in_place_sort_after_collect` -> `in_place_sort` and
  `in_place_dedup_after_collect` -> `in_place_dedup` (files renamed to
  match).
- Broaden the trigger to any by-value owned `Vec<T>` binding immediately
  followed by an in-place `sort*` / `dedup*`; reject `&Vec` / `&mut Vec`
  receivers, which the `into_*` methods cannot consume.
- The cascade now falls out with no special "intervening owning calls"
  clause — a chain ending in `into_sorted()` is just another owned `Vec`.
- Make the turbofish conditional: only threaded for a type-inferred
  initializer (a bare `collect()`), not for already-typed sources.
- Update the README index entries and the `itertools_sort_dedup_collect`
  cross-references (the siblings are no longer "collect-rooted").

Source: #308.

Co-authored-by: Claude <noreply@anthropic.com>
@KSXGitHub KSXGitHub changed the title docs(plan): in_place_sort_after_collect, in_place_dedup_after_collect, itertools_sort_dedup_collect docs(plan): in_place_sort, in_place_dedup, itertools_sort_dedup_collect Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(plan): prefer into-sorted, into-deduped

2 participants