aboutsummaryrefslogtreecommitdiff
path: root/object/blob
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-25 14:49:17 +0000
committerGravatar Runxi Yu2026-03-25 15:02:22 +0000
commit7847657e0820af98120031f719b8ede635ad8c07 (patch)
tree8c4439c78f72f1382edc809b49be33115847b6e7 /object/blob
parentobject: Remove type.go (diff)
signatureNo signature
object: Split each object type into its own package v0.1.108
Diffstat (limited to 'object/blob')
-rw-r--r--object/blob/blob.go11
-rw-r--r--object/blob/parse.go6
-rw-r--r--object/blob/parse_test.go30
-rw-r--r--object/blob/serialize.go32
-rw-r--r--object/blob/serialize_test.go30
-rw-r--r--object/blob/test.go10
6 files changed, 119 insertions, 0 deletions
diff --git a/object/blob/blob.go b/object/blob/blob.go
new file mode 100644
index 00000000..977121fb
--- /dev/null
+++ b/object/blob/blob.go
@@ -0,0 +1,11 @@
+// Package blob provides representations, parsers, and serializers for blob objects.
+package blob
+
+// Blob represents a Git blob object.
+//
+// This Blob object is fully materialized in memory.
+// Consider using objectstorer/Store.ReadReaderContent,
+// or appropriate streaming write APIs.
+type Blob struct {
+ Data []byte
+}
diff --git a/object/blob/parse.go b/object/blob/parse.go
new file mode 100644
index 00000000..faee9e46
--- /dev/null
+++ b/object/blob/parse.go
@@ -0,0 +1,6 @@
+package blob
+
+// Parse decodes a blob object body.
+func Parse(body []byte) (*Blob, error) {
+ return &Blob{Data: append([]byte(nil), body...)}, nil
+}
diff --git a/object/blob/parse_test.go b/object/blob/parse_test.go
new file mode 100644
index 00000000..09d5d5d0
--- /dev/null
+++ b/object/blob/parse_test.go
@@ -0,0 +1,30 @@
+package blob_test
+
+import (
+ "bytes"
+ "testing"
+
+ "codeberg.org/lindenii/furgit/internal/testgit"
+ "codeberg.org/lindenii/furgit/object/blob"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+)
+
+func TestBlobParseFromGit(t *testing.T) {
+ t.Parallel()
+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
+ testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
+ body := []byte("hello\nblob\n")
+ blobID := testRepo.HashObject(t, "blob", body)
+
+ rawBody := testRepo.CatFile(t, "blob", blobID)
+
+ parsed, err := blob.Parse(rawBody)
+ if err != nil {
+ t.Fatalf("ParseBlob: %v", err)
+ }
+
+ if !bytes.Equal(parsed.Data, body) {
+ t.Fatalf("blob body mismatch")
+ }
+ })
+}
diff --git a/object/blob/serialize.go b/object/blob/serialize.go
new file mode 100644
index 00000000..80cce8dc
--- /dev/null
+++ b/object/blob/serialize.go
@@ -0,0 +1,32 @@
+package blob
+
+import (
+ "errors"
+
+ objectheader "codeberg.org/lindenii/furgit/object/header"
+ objecttype "codeberg.org/lindenii/furgit/object/type"
+)
+
+// SerializeWithoutHeader renders the raw blob body bytes.
+func (blob *Blob) SerializeWithoutHeader() ([]byte, error) {
+ return append([]byte(nil), blob.Data...), nil
+}
+
+// SerializeWithHeader renders the raw object (header + body).
+func (blob *Blob) SerializeWithHeader() ([]byte, error) {
+ body, err := blob.SerializeWithoutHeader()
+ if err != nil {
+ return nil, err
+ }
+
+ header, ok := objectheader.Encode(objecttype.TypeBlob, int64(len(body)))
+ if !ok {
+ return nil, errors.New("object: blob: failed to encode object header")
+ }
+
+ raw := make([]byte, len(header)+len(body))
+ copy(raw, header)
+ copy(raw[len(header):], body)
+
+ return raw, nil
+}
diff --git a/object/blob/serialize_test.go b/object/blob/serialize_test.go
new file mode 100644
index 00000000..4292abad
--- /dev/null
+++ b/object/blob/serialize_test.go
@@ -0,0 +1,30 @@
+package blob_test
+
+import (
+ "testing"
+
+ "codeberg.org/lindenii/furgit/internal/testgit"
+ "codeberg.org/lindenii/furgit/object/blob"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+)
+
+func TestBlobSerialize(t *testing.T) {
+ t.Parallel()
+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
+ testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
+ body := []byte("hello\nblob\n")
+ wantID := testRepo.HashObject(t, "blob", body)
+
+ obj := &blob.Blob{Data: body}
+
+ rawObj, err := obj.SerializeWithHeader()
+ if err != nil {
+ t.Fatalf("SerializeWithHeader: %v", err)
+ }
+
+ gotID := algo.Sum(rawObj)
+ if gotID != wantID {
+ t.Fatalf("object id mismatch: got %s want %s", gotID, wantID)
+ }
+ })
+}
diff --git a/object/blob/test.go b/object/blob/test.go
new file mode 100644
index 00000000..9e538219
--- /dev/null
+++ b/object/blob/test.go
@@ -0,0 +1,10 @@
+package blob
+
+import objecttype "codeberg.org/lindenii/furgit/object/type"
+
+// ObjectType returns TypeBlob.
+func (blob *Blob) ObjectType() objecttype.Type {
+ _ = blob
+
+ return objecttype.TypeBlob
+}