aboutsummaryrefslogtreecommitdiff
path: root/objectid
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-25 14:21:50 +0000
committerGravatar Runxi Yu2026-03-25 14:22:01 +0000
commite4373a7e553f8523db3e99ea316e1c25d30cc059 (patch)
treec21d0b20b1c4743619a05fdfcfa676ab2642da9e /objectid
parent*: objecttype, objectheader -> object/type, object/header (diff)
signatureNo signature
*: objectid -> object/id
Diffstat (limited to 'objectid')
-rw-r--r--objectid/algorithms.go140
-rw-r--r--objectid/errors.go10
-rw-r--r--objectid/objectid.go113
-rw-r--r--objectid/objectid_test.go184
4 files changed, 0 insertions, 447 deletions
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")
- }
-}