···2929}
30303131/// An owned pair of [`Token`]s.
3232-#[derive(Copy, Clone, Debug)]
3232+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3333// Alignment repr necessary to allow LLVM to better output
3434-// optimized codegen for `to_bits`, `PartialEq`
3534// Prior art taken from my contribution to Bevy:
3635// https://github.com/bevyengine/bevy/blob/main/crates/bevy_ecs/src/entity/mod.rs#L309
3736#[repr(C, align(16))]
3837pub struct TokenPair {
3938 // Do not reorder the fields here. The ordering is explicitly used by repr(C)
4040- // to make this struct equivalent to a u64.
3939+ // to make this struct equivalent to a u128.
4140 #[cfg(target_endian = "little")]
4241 pub left: Token,
4342 pub right: Token,
···4544 pub left: Token,
4645}
47464848-// By not short-circuiting in comparisons, we get better codegen.
4949-// See <https://github.com/rust-lang/rust/issues/117800>
5050-impl PartialEq for TokenPair {
5151- #[inline(always)]
5252- fn eq(&self, other: &TokenPair) -> bool {
5353- // By using `to_bits`, the codegen can be optimized out even
5454- // further potentially. Relies on the correct alignment/field
5555- // order of `TokenPair`.
5656- self.to_bits() == other.to_bits()
5757- }
5858-}
5959-6060-impl Eq for TokenPair {}
6161-6247impl core::hash::Hash for TokenPair {
6363- #[inline(always)]
4848+ #[inline]
6449 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
6565- self.to_bits().hash(state);
5050+ self.double_hash().hash(state);
6651 }
6752}
6853···7358 }
74597560 #[inline(always)]
7676- fn to_bits(self) -> u128 {
7777- (self.left.0.digest().hash() as u128) | ((self.right.0.digest().hash() as u128) << 64)
6161+ fn double_hash(&self) -> u64 {
6262+ self.right
6363+ .0
6464+ .digest()
6565+ .hash()
6666+ .wrapping_add(self.left.0.digest().hash())
6767+ .rotate_left(5)
7868 }
7969}
8070