Skip to content

Is the implementation of Borrow reasonable #2

@A4-Tacks

Description

@A4-Tacks

The behavior that needs to be guaranteed for equivalent instances is described in the document of std::hash::Hasher

This trait provides no guarantees about how the various write_* methods are
defined and implementations of [Hash] should not assume that they work one
way or another. You cannot assume, for example, that a [write_u32] call is
equivalent to four calls of [write_u8]. Nor can you assume that adjacent
write calls are merged, so it's possible, for example, that

# fn foo(hasher: &mut impl std::hash::Hasher) {
hasher.write(&[1, 2]);
hasher.write(&[3, 4, 5, 6]);
# }

and

# fn foo(hasher: &mut impl std::hash::Hasher) {
hasher.write(&[1, 2, 3, 4]);
hasher.write(&[5, 6]);
# }

end up producing different hashes.

Thus to produce the same hash value, [Hash] implementations must ensure
for equivalent items that exactly the same sequence of calls is made -- the
same methods with the same parameters in the same order.

Although CachedHash implements Borrow<T>, its hash behavior attempts to equate write_u64 with unknown write calls

This does not match the description in Borrow document

In particular Eq, Ord and Hash must be equivalent for
borrowed and owned values: x.borrow() == y.borrow() should give the
same result as x == y.

impl<T: Eq + Hash, BH: BuildHasher> Hash for CachedHash<T, BH> {
fn hash<H2: Hasher>(&self, state: &mut H2) {
if let Some(hash) = self.hash.get_raw() {
state.write_u64(hash);
} else {
let mut hasher = self.build_hasher.build_hasher();
self.value.hash(&mut hasher);
// AtomicOptionNonZeroU64 can only store non-zero values so we create a small collision by bumping up hash 0 to 1.
let hash = NonZeroU64::new(hasher.finish()).unwrap_or(NonZeroU64::new(1).unwrap());
self.hash.set(Some(hash));
state.write_u64(hash.into());
}
}
}

impl<T: Eq + Hash, BH: BuildHasher> Borrow<T> for CachedHash<T, BH> {
fn borrow(&self) -> &T {
Self::get(self)
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions