Skip to content

Extend hasher genericity to the remaining impls - #60

Open
tb158 wants to merge 1 commit into
coriolinus:masterfrom
tb158:feat/hasher-generic-leftovers
Open

tb158 wants to merge 1 commit into
coriolinus:masterfrom
tb158:feat/hasher-generic-leftovers

Conversation

@tb158

@tb158 tb158 commented Aug 9, 2026

Copy link
Copy Markdown

Problem

#51 made Counter generic over its hasher, but four items were left in impl blocks written as
Counter<T, N>, which resolves to `Countsimply do not exist on a
counter built with any other hasher:

  • Counter::into_map
  • Counter::total
  • impl FromIterator<(T, N)>
  • impl SubAssign<I>

So swapping in a faster hasher silently c, counter.total(), counter.into_map(), and collecting from (item, count)` pairs, with nothing to suggest the
restriction is unintended.

Changes

Generalize the three impl blocks which ho

  • into_map now returns HashMap<T, N, Ss own hasher rather than forcing RandomState`. For the default hasher the type is unchanged.
  • total's type parameter is renamed froow names the hasher of the
    enclosing impl. Call sites are unaffected.
  • FromIterator<(T, N)> gains S: BuildHe existing FromIterator` impl.
  • SubAssign<I> gains S: BuildHasher, ` impl.

Compatibility

Non-breaking for annotated code, which ised
(collect::<Counter<_>>(), let c: Counter<char> = ...).

One inference caveat, the same one std accepts: Counter::from_iter(pairs) with no annotation
used to resolve S to RandomState becad now needs S pinned by
context. std made the same trade-off for
impl<K, V, S: Default + BuildHasher> Fro<K, V, S>.

Relationship to the constructor PR

Independent of #59 — either can merge firsts next to each other in
tests/tests.rs, so whichever merges second needs a trivial conflict resolution there (keep
both tests).

To keep that true, FromIterator<(T, N)>ruct literal rather than a
constructor: Counter::new() would return Counter<T, N, RandomState> once #59 lands, and
Counter::with_hasher does not exist untis the only form which
compiles either way. Once both are in, that body can be simplified to
Counter::with_hasher(S::default()) and p` import dropped — happy
to fold that into whichever branch merges second.

cargo test --all-features (18 unit + 19 integration + 47 doctests) and cargo clippy --all-features --all-targets are clean. r locally also builds and
passes (21 + 20 + 51).

`Counter<T, N, S>` gained its hasher parameter in coriolinus#51, but four items
were left pinned to the default hasher and so silently disappeared from
counters built with any other one:

- `Counter::into_map`
- `Counter::total`
- `FromIterator<(T, N)>`
- `SubAssign<I>`

Generalize the three impl blocks which hold them. `into_map` now
returns `HashMap<T, N, S>`, handing back the counter's own hasher rather
than forcing `RandomState`; the type is unchanged for the default
hasher. The type parameter of `total` is renamed from `S` to `Total`,
since `S` now names the hasher of the enclosing impl.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

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.

1 participant