diff options
| author | 2025-11-16 00:00:00 +0000 | |
|---|---|---|
| committer | 2025-11-16 00:00:00 +0000 | |
| commit | 5cfbd8863dfb7c6af92497d9a5eb6eb63a6bd589 (patch) | |
| tree | 42a871a72388bb6d40c479fbaa6eedde1cddc42e /hash.go | |
| parent | hash: Generic hash-algorithm API (diff) | |
| signature | ||
Revert "hash: Generic hash-algorithm API"
This reverts commit 94bfb1fa147f80e6ec39009d41fc2f853925e0a5.
Generics actually kinda suck for these purposes... once you look at it
from the user's perspective.
Diffstat (limited to 'hash.go')
| -rw-r--r-- | hash.go | 98 |
1 files changed, 35 insertions, 63 deletions
@@ -5,80 +5,52 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "unsafe" ) -// HashType is a constraint that enumerates the supported hash sizes. -type HashType interface { - [sha1.Size]byte | [sha256.Size]byte -} +const maxHashSize = 32 -type ( - // SHA1Hash represents a SHA-1 hash. - SHA1Hash = [sha1.Size]byte +// Hash represents a Git object identifier. +type Hash [maxHashSize]byte - // SHA256Hash represents a SHA-256 hash. - SHA256Hash = [sha256.Size]byte -) +// hashFunc is a function that computes a hash from input data. +type hashFunc func([]byte) [maxHashSize]byte -// Hash represents a Git object identifier with type-level hash size. -type Hash[T HashType] struct { - v T -} - -// hashLen returns the hash size for a given hash type. -func hashLen[T HashType]() int { - var zero T - return len(zero) -} - -// String returns the hash as a hex string. -func (h Hash[T]) String() string { - return hex.EncodeToString(unsafe.Slice((*byte)(unsafe.Pointer(&h.v)), hashLen[T]())) -} - -// Bytes returns a mutable copy of the underlying bytes. -func (h Hash[T]) Bytes() []byte { - s := unsafe.Slice((*byte)(unsafe.Pointer(&h.v)), hashLen[T]()) - return append([]byte(nil), s...) -} - -// Slice returns a read-only slice view of the underlying bytes. -func (h *Hash[T]) Slice() []byte { - return unsafe.Slice((*byte)(unsafe.Pointer(&h.v)), hashLen[T]()) +// hashFuncs maps hash size to hash function. +var hashFuncs = map[int]hashFunc{ + sha1.Size: func(data []byte) [maxHashSize]byte { + var result [maxHashSize]byte + sum := sha1.Sum(data) + copy(result[:], sum[:]) + return result + }, + sha256.Size: func(data []byte) [maxHashSize]byte { + var result [maxHashSize]byte + sum := sha256.Sum256(data) + copy(result[:], sum[:]) + return result + }, } -// ParseHash converts a hex string into a Hash for the given hash type. -func ParseHash[T HashType](s string) (Hash[T], error) { - var out Hash[T] - wantHex := hashLen[T]() * 2 - - if len(s) != wantHex { - return out, fmt.Errorf("furgit: invalid hash length %d, want %d", len(s), wantHex) +// ParseHashWithSize converts a hex string into a Hash for a given hash size. +func ParseHashWithSize(s string, hashSize int) (Hash, error) { + var id Hash + if len(s) != hashSize*2 { + return id, fmt.Errorf("furgit: invalid hash length %d", len(s)) } - raw, err := hex.DecodeString(s) + data, err := hex.DecodeString(s) if err != nil { - return out, fmt.Errorf("furgit: decode hash: %w", err) + return id, fmt.Errorf("furgit: decode hash: %w", err) } - slice := unsafe.Slice((*byte)(unsafe.Pointer(&out.v)), hashLen[T]()) - copy(slice, raw) - return out, nil + copy(id[:], data) + return id, nil } -// computeRawHash computes a hash from data. -func computeRawHash[T HashType](data []byte) Hash[T] { - var out Hash[T] - slice := unsafe.Slice((*byte)(unsafe.Pointer(&out.v)), hashLen[T]()) +// StringWithSize returns the ID as hex for a given hash size. +func (id Hash) StringWithSize(hashSize int) string { + return hex.EncodeToString(id[:hashSize]) +} - switch hashLen[T]() { - case sha1.Size: - sum := sha1.Sum(data) - copy(slice, sum[:]) - case sha256.Size: - sum := sha256.Sum256(data) - copy(slice, sum[:]) - default: - panic("furgit: unsupported hash length") - } - return out +// BytesWithSize returns a mutable copy of the underlying bytes for a given hash size. +func (id Hash) BytesWithSize(hashSize int) []byte { + return append([]byte(nil), id[:hashSize]...) } |
