@ -104,6 +104,70 @@ import (
// by looking up the hash in a magical map that returns the set of entries
// for that given hash.
// SelfHasher is implemented by types that can compute their own hash
// by writing values through the provided [Hasher] parameter.
// Implementations must not leak the provided [Hasher].
//
// If the implementation of SelfHasher recursively calls [deephash.Hash],
// then infinite recursion is quite likely to occur.
// To avoid this, use a type definition to drop methods before calling [deephash.Hash]:
//
// func (v *MyType) Hash(h deephash.Hasher) {
// v.hashMu.Lock()
// defer v.hashMu.Unlock()
// if v.dirtyHash {
// type MyTypeWithoutMethods MyType // type define MyType to drop Hash method
// v.dirtyHash = false // clear out dirty bit to avoid hashing over it
// v.hashSum = deephash.Sum{} // clear out hashSum to avoid hashing over it
// v.hashSum = deephash.Hash((*MyTypeWithoutMethods)(v))
// }
// h.HashSum(v.hashSum)
// }
//
// In the above example, we acquire a lock since it is possible that deephash
// is called in a concurrent manner, which implies that MyType.Hash may also
// be called in a concurrent manner. Whether this lock is necessary is
// application-dependent and left as an exercise to the reader.
// Also, the example assumes that dirtyHash is set elsewhere by application
// logic whenever a mutation is made to MyType that would alter the hash.
type SelfHasher interface {
Hash ( Hasher )
}
// Hasher is a value passed to [SelfHasher.Hash] that allow implementations
// to hash themselves in a structured manner.
type Hasher struct { h * hashx . Block512 }
// HashBytes hashes a sequence of bytes b.
// The length of b is not explicitly hashed.
func ( h Hasher ) HashBytes ( b [ ] byte ) { h . h . HashBytes ( b ) }
// HashString hashes the string data of s
// The length of s is not explicitly hashed.
func ( h Hasher ) HashString ( s string ) { h . h . HashString ( s ) }
// HashUint8 hashes a uint8.
func ( h Hasher ) HashUint8 ( n uint8 ) { h . h . HashUint8 ( n ) }
// HashUint16 hashes a uint16.
func ( h Hasher ) HashUint16 ( n uint16 ) { h . h . HashUint16 ( n ) }
// HashUint32 hashes a uint32.
func ( h Hasher ) HashUint32 ( n uint32 ) { h . h . HashUint32 ( n ) }
// HashUint64 hashes a uint64.
func ( h Hasher ) HashUint64 ( n uint64 ) { h . h . HashUint64 ( n ) }
// HashSum hashes a [Sum].
func ( h Hasher ) HashSum ( s Sum ) {
// NOTE: Avoid calling h.HashBytes since it escapes b,
// which would force s to be heap allocated.
h . h . HashUint64 ( binary . LittleEndian . Uint64 ( s . sum [ 0 : 8 ] ) )
h . h . HashUint64 ( binary . LittleEndian . Uint64 ( s . sum [ 8 : 16 ] ) )
h . h . HashUint64 ( binary . LittleEndian . Uint64 ( s . sum [ 16 : 24 ] ) )
h . h . HashUint64 ( binary . LittleEndian . Uint64 ( s . sum [ 24 : 32 ] ) )
}
// hasher is reusable state for hashing a value.
// Get one via hasherPool.
type hasher struct {
@ -339,7 +403,7 @@ func makeTypeHasher(t reflect.Type) typeHasherFunc {
if t . Kind ( ) != reflect . Pointer && t . Kind ( ) != reflect . Interface {
// A method can be implemented on either the value receiver or pointer receiver.
if t . Implements ( selfHasherType ) || reflect . PointerTo ( t ) . Implements ( selfHasherType ) {
return makeSelfHasher Impl ( t )
return makeSelfHasher ( t )
}
}
@ -401,10 +465,9 @@ func hashAddr(h *hasher, p pointer) {
}
}
func makeSelfHasher Impl ( t reflect . Type ) typeHasherFunc {
func makeSelfHasher ( t reflect . Type ) typeHasherFunc {
return func ( h * hasher , p pointer ) {
e := p . asValue ( t )
e . Interface ( ) . ( SelfHasher ) . Hash ( & h . Block512 )
p . asValue ( t ) . Interface ( ) . ( SelfHasher ) . Hash ( Hasher { & h . Block512 } )
}
}