aboutsummaryrefslogtreecommitdiff
path: root/object/id/objectid.go
diff options
context:
space:
mode:
Diffstat (limited to 'object/id/objectid.go')
-rw-r--r--object/id/objectid.go113
1 files changed, 113 insertions, 0 deletions
diff --git a/object/id/objectid.go b/object/id/objectid.go
new file mode 100644
index 00000000..8eb82969
--- /dev/null
+++ b/object/id/objectid.go
@@ -0,0 +1,113 @@
+// 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
+}