aboutsummaryrefslogtreecommitdiff
path: root/hash.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2025-11-16 00:00:00 +0000
committerGravatar Runxi Yu2025-11-16 00:00:00 +0000
commit5cfbd8863dfb7c6af92497d9a5eb6eb63a6bd589 (patch)
tree42a871a72388bb6d40c479fbaa6eedde1cddc42e /hash.go
parenthash: 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.go98
1 files changed, 35 insertions, 63 deletions
diff --git a/hash.go b/hash.go
index 53dff11b..336d5322 100644
--- a/hash.go
+++ b/hash.go
@@ -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]...)
}