From e4373a7e553f8523db3e99ea316e1c25d30cc059 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Wed, 25 Mar 2026 14:21:50 +0000 Subject: *: objectid -> object/id --- objectid/algorithms.go | 140 ----------------------------------- objectid/errors.go | 10 --- objectid/objectid.go | 113 ---------------------------- objectid/objectid_test.go | 184 ---------------------------------------------- 4 files changed, 447 deletions(-) delete mode 100644 objectid/algorithms.go delete mode 100644 objectid/errors.go delete mode 100644 objectid/objectid.go delete mode 100644 objectid/objectid_test.go (limited to 'objectid') diff --git a/objectid/algorithms.go b/objectid/algorithms.go deleted file mode 100644 index 404d3bbf..00000000 --- a/objectid/algorithms.go +++ /dev/null @@ -1,140 +0,0 @@ -package objectid - -import ( - "crypto/sha1" //#nosec gosec - "crypto/sha256" - "hash" -) - -// maxObjectIDSize MUST be >= the largest supported algorithm size. -const maxObjectIDSize = sha256.Size - -// Algorithm identifies the hash algorithm used for Git object IDs. -type Algorithm uint8 - -const ( - AlgorithmUnknown Algorithm = iota - AlgorithmSHA1 - AlgorithmSHA256 -) - -type algorithmDetails struct { - name string - size int - packHashID uint32 - sum func([]byte) ObjectID - new func() hash.Hash -} - -//nolint:gochecknoglobals -var algorithmTable = [...]algorithmDetails{ - AlgorithmUnknown: {}, - AlgorithmSHA1: { - name: "sha1", - size: sha1.Size, - packHashID: 1, - sum: func(data []byte) ObjectID { - sum := sha1.Sum(data) //#nosec G401 - - var id ObjectID - copy(id.data[:], sum[:]) - id.algo = AlgorithmSHA1 - - return id - }, - new: sha1.New, - }, - AlgorithmSHA256: { - name: "sha256", - size: sha256.Size, - packHashID: 2, - sum: func(data []byte) ObjectID { - sum := sha256.Sum256(data) - - var id ObjectID - copy(id.data[:], sum[:]) - id.algo = AlgorithmSHA256 - - return id - }, - new: sha256.New, - }, -} - -var ( - //nolint:gochecknoglobals - algorithmByName = map[string]Algorithm{} - //nolint:gochecknoglobals - supportedAlgorithms []Algorithm -) - -func init() { //nolint:gochecknoinits - for algo := Algorithm(0); int(algo) < len(algorithmTable); algo++ { - info := algorithmTable[algo] - if info.name == "" { - continue - } - - algorithmByName[info.name] = algo - supportedAlgorithms = append(supportedAlgorithms, algo) - } -} - -// SupportedAlgorithms returns all object ID algorithms supported by furgit. -// Do not mutate. -func SupportedAlgorithms() []Algorithm { - return supportedAlgorithms -} - -// ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256"). -func ParseAlgorithm(s string) (Algorithm, bool) { - algo, ok := algorithmByName[s] - - return algo, ok -} - -// Size returns the hash size in bytes. -func (algo Algorithm) Size() int { - return algo.info().size -} - -// String returns the canonical algorithm name. -func (algo Algorithm) String() string { - inf := algo.info() - if inf.name == "" { - return "unknown" - } - - return inf.name -} - -// HexLen returns the encoded hexadecimal length. -func (algo Algorithm) HexLen() int { - return algo.Size() * 2 -} - -// PackHashID returns the Git pack/rev hash-id encoding for this algorithm. -// -// Unknown algorithms return 0. -func (algo Algorithm) PackHashID() uint32 { - return algo.info().packHashID -} - -// Sum computes an object ID from raw data using the selected algorithm. -func (algo Algorithm) Sum(data []byte) ObjectID { - return algo.info().sum(data) -} - -// New returns a new hash.Hash for this algorithm. -func (algo Algorithm) New() (hash.Hash, error) { - newFn := algo.info().new - if newFn == nil { - return nil, ErrInvalidAlgorithm - } - - return newFn(), nil -} - -func (algo Algorithm) info() algorithmDetails { - return algorithmTable[algo] -} diff --git a/objectid/errors.go b/objectid/errors.go deleted file mode 100644 index 8e604c44..00000000 --- a/objectid/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package objectid - -import "errors" - -var ( - // ErrInvalidAlgorithm indicates an unsupported object ID algorithm. - ErrInvalidAlgorithm = errors.New("objectid: invalid algorithm") - // ErrInvalidObjectID indicates malformed object ID data. - ErrInvalidObjectID = errors.New("objectid: invalid object id") -) diff --git a/objectid/objectid.go b/objectid/objectid.go deleted file mode 100644 index 8eb82969..00000000 --- a/objectid/objectid.go +++ /dev/null @@ -1,113 +0,0 @@ -// Package objectid provides utilities around object IDs and hash algorithms. -package objectid - -import ( - //#nosec G505 - - "bytes" - "encoding/hex" - "fmt" -) - -// ObjectID represents a Git object ID. -// -//nolint:recvcheck -type ObjectID struct { - algo Algorithm - data [maxObjectIDSize]byte -} - -// Algorithm returns the object ID's hash algorithm. -func (id ObjectID) Algorithm() Algorithm { - return id.algo -} - -// Size returns the object ID size in bytes. -func (id ObjectID) Size() int { - return id.algo.Size() -} - -// String returns the canonical hex representation. -func (id ObjectID) String() string { - size := id.Size() - - return hex.EncodeToString(id.data[:size]) -} - -// Bytes returns a copy of the object ID bytes. -func (id ObjectID) Bytes() []byte { - size := id.Size() - - return append([]byte(nil), id.data[:size]...) -} - -// RawBytes returns a direct byte slice view of the object ID bytes. -// -// The returned slice aliases the object ID's internal storage. Callers MUST -// treat it as read-only and MUST NOT modify its contents. -// -// Use Bytes when an independent copy is required. -func (id *ObjectID) RawBytes() []byte { - size := id.Size() - - return id.data[:size:size] -} - -// Compare lexicographically compares two object IDs by their canonical byte -// representation. -func Compare(left, right ObjectID) int { - return bytes.Compare(left.RawBytes(), right.RawBytes()) -} - -// Zero returns the all-zero object ID for the specified algorithm. -func Zero(algo Algorithm) ObjectID { - id, err := FromBytes(algo, make([]byte, algo.Size())) - if err != nil { - panic(err) - } - - return id -} - -// ParseHex parses an object ID from hex for the specified algorithm. -func ParseHex(algo Algorithm, s string) (ObjectID, error) { - var id ObjectID - if algo.Size() == 0 { - return id, ErrInvalidAlgorithm - } - - if len(s)%2 != 0 { - return id, fmt.Errorf("%w: odd hex length %d", ErrInvalidObjectID, len(s)) - } - - if len(s) != algo.HexLen() { - return id, fmt.Errorf("%w: got %d chars, expected %d", ErrInvalidObjectID, len(s), algo.HexLen()) - } - - decoded, err := hex.DecodeString(s) - if err != nil { - return id, fmt.Errorf("%w: decode: %w", ErrInvalidObjectID, err) - } - - copy(id.data[:], decoded) - id.algo = algo - - return id, nil -} - -// FromBytes builds an object ID from raw bytes for the specified algorithm. -func FromBytes(algo Algorithm, b []byte) (ObjectID, error) { - var id ObjectID - if algo.Size() == 0 { - return id, ErrInvalidAlgorithm - } - - if len(b) != algo.Size() { - return id, fmt.Errorf("%w: got %d bytes, expected %d", ErrInvalidObjectID, len(b), algo.Size()) - } - - copy(id.data[:], b) - id.algo = algo - - return id, nil -} diff --git a/objectid/objectid_test.go b/objectid/objectid_test.go deleted file mode 100644 index d053aca3..00000000 --- a/objectid/objectid_test.go +++ /dev/null @@ -1,184 +0,0 @@ -package objectid_test - -import ( - "bytes" - "strings" - "testing" - - "codeberg.org/lindenii/furgit/objectid" -) - -func TestParseAlgorithm(t *testing.T) { - t.Parallel() - - algo, ok := objectid.ParseAlgorithm("sha1") - if !ok || algo != objectid.AlgorithmSHA1 { - t.Fatalf("ParseAlgorithm(sha1) = (%v,%v)", algo, ok) - } - - algo, ok = objectid.ParseAlgorithm("sha256") - if !ok || algo != objectid.AlgorithmSHA256 { - t.Fatalf("ParseAlgorithm(sha256) = (%v,%v)", algo, ok) - } - - if _, ok := objectid.ParseAlgorithm("md5"); ok { - t.Fatalf("ParseAlgorithm(md5) should fail") - } -} - -func TestParseHexRoundtrip(t *testing.T) { - t.Parallel() - - for _, algo := range objectid.SupportedAlgorithms() { - t.Run(algo.String(), func(t *testing.T) { - t.Parallel() - - hex := strings.Repeat("01", algo.Size()) - - id, err := objectid.ParseHex(algo, hex) - if err != nil { - t.Fatalf("ParseHex failed: %v", err) - } - - if got := id.String(); got != hex { - t.Fatalf("String() = %q, want %q", got, hex) - } - - if got := id.Size(); got != algo.Size() { - t.Fatalf("Size() = %d, want %d", got, algo.Size()) - } - - raw := id.Bytes() - if len(raw) != algo.Size() { - t.Fatalf("Bytes len = %d, want %d", len(raw), algo.Size()) - } - - id2, err := objectid.FromBytes(algo, raw) - if err != nil { - t.Fatalf("FromBytes failed: %v", err) - } - - if id2.String() != hex { - t.Fatalf("FromBytes roundtrip = %q, want %q", id2.String(), hex) - } - }) - } -} - -func TestParseHexErrors(t *testing.T) { - t.Parallel() - - t.Run("unknown algo", func(t *testing.T) { - t.Parallel() - - _, err := objectid.ParseHex(objectid.AlgorithmUnknown, "00") - if err == nil { - t.Fatalf("expected ParseHex error") - } - }) - - for _, algo := range objectid.SupportedAlgorithms() { - t.Run(algo.String(), func(t *testing.T) { - t.Parallel() - - _, err := objectid.ParseHex(algo, strings.Repeat("0", algo.HexLen()-1)) - if err == nil { - t.Fatalf("expected ParseHex odd-len error") - } - - _, err = objectid.ParseHex(algo, strings.Repeat("0", algo.HexLen()-2)) - if err == nil { - t.Fatalf("expected ParseHex wrong-len error") - } - - _, err = objectid.ParseHex(algo, "z"+strings.Repeat("0", algo.HexLen()-1)) - if err == nil { - t.Fatalf("expected ParseHex invalid-hex error") - } - }) - } -} - -func TestFromBytesErrors(t *testing.T) { - t.Parallel() - - _, err := objectid.FromBytes(objectid.AlgorithmUnknown, []byte{1, 2}) - if err == nil { - t.Fatalf("expected FromBytes unknown algo error") - } - - for _, algo := range objectid.SupportedAlgorithms() { - _, err = objectid.FromBytes(algo, []byte{1, 2}) - if err == nil { - t.Fatalf("expected FromBytes wrong size error") - } - } -} - -func TestBytesReturnsCopy(t *testing.T) { - t.Parallel() - - for _, algo := range objectid.SupportedAlgorithms() { - id, err := objectid.ParseHex(algo, strings.Repeat("01", algo.Size())) - if err != nil { - t.Fatalf("ParseHex failed: %v", err) - } - - b1 := id.Bytes() - - b2 := id.Bytes() - if !bytes.Equal(b1, b2) { - t.Fatalf("Bytes mismatch") - } - - b1[0] ^= 0xff - if bytes.Equal(b1, b2) { - t.Fatalf("Bytes should return independent copies") - } - } -} - -func TestRawBytesAliasesStorage(t *testing.T) { - t.Parallel() - - for _, algo := range objectid.SupportedAlgorithms() { - id, err := objectid.ParseHex(algo, strings.Repeat("01", algo.Size())) - if err != nil { - t.Fatalf("ParseHex failed: %v", err) - } - - b := id.RawBytes() - if len(b) != id.Size() { - t.Fatalf("RawBytes len = %d, want %d", len(b), id.Size()) - } - - if cap(b) != len(b) { - t.Fatalf("RawBytes cap = %d, want %d", cap(b), len(b)) - } - - orig := id.String() - b[0] ^= 0xff - - if id.String() == orig { - t.Fatalf("RawBytes should alias object ID storage") - } - } -} - -func TestAlgorithmSum(t *testing.T) { - t.Parallel() - - id1 := objectid.AlgorithmSHA1.Sum([]byte("hello")) - if id1.Algorithm() != objectid.AlgorithmSHA1 || id1.Size() != objectid.AlgorithmSHA1.Size() { - t.Fatalf("sha1 sum produced invalid object id") - } - - id2 := objectid.AlgorithmSHA256.Sum([]byte("hello")) - if id2.Algorithm() != objectid.AlgorithmSHA256 || id2.Size() != objectid.AlgorithmSHA256.Size() { - t.Fatalf("sha256 sum produced invalid object id") - } - - if id1.String() == id2.String() { - t.Fatalf("sha1 and sha256 should differ") - } -} -- cgit v1.3.1-10-gc9f91