shithub: furgit

Download patch

ref: 98e5a64ce72e81dcede7dbebc74e22576a1f5ab8
parent: b3b2d5057a55baf88cbaaa31234edd3fe5d30e7f
author: Runxi Yu <me@runxiyu.org>
date: Fri Feb 20 17:22:56 EST 2026

object: Use objectheader

--- a/object/blob_serialize.go
+++ b/object/blob_serialize.go
@@ -1,15 +1,27 @@
 package object
 
-import "codeberg.org/lindenii/furgit/objecttype"
+import (
+	"codeberg.org/lindenii/furgit/internal/objectheader"
+	"codeberg.org/lindenii/furgit/objecttype"
+)
 
-// Serialize renders the raw object (header + body).
-func (blob *Blob) Serialize() ([]byte, error) {
-	header, err := headerForType(objecttype.TypeBlob, blob.Data)
+// 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
 	}
-	raw := make([]byte, len(header)+len(blob.Data))
+	header, ok := objectheader.Encode(objecttype.TypeBlob, int64(len(body)))
+	if !ok {
+		return nil, ErrInvalidObject
+	}
+	raw := make([]byte, len(header)+len(body))
 	copy(raw, header)
-	copy(raw[len(header):], blob.Data)
+	copy(raw[len(header):], body)
 	return raw, nil
 }
--- a/object/blob_serialize_test.go
+++ b/object/blob_serialize_test.go
@@ -15,9 +15,9 @@
 		wantID := repo.HashObject(t, "blob", body)
 
 		blob := &object.Blob{Data: body}
-		rawObj, err := blob.Serialize()
+		rawObj, err := blob.SerializeWithHeader()
 		if err != nil {
-			t.Fatalf("Serialize: %v", err)
+			t.Fatalf("SerializeWithHeader: %v", err)
 		}
 		gotID := algo.Sum(rawObj)
 		if gotID != wantID {
--- a/object/commit_serialize.go
+++ b/object/commit_serialize.go
@@ -4,10 +4,12 @@
 	"bytes"
 	"fmt"
 
+	"codeberg.org/lindenii/furgit/internal/objectheader"
 	"codeberg.org/lindenii/furgit/objecttype"
 )
 
-func (commit *Commit) serialize() ([]byte, error) {
+// SerializeWithoutHeader renders the raw commit body bytes.
+func (commit *Commit) SerializeWithoutHeader() ([]byte, error) {
 	var buf bytes.Buffer
 
 	if commit.Tree.Size() == 0 {
@@ -54,15 +56,15 @@
 	return buf.Bytes(), nil
 }
 
-// Serialize renders the raw object (header + body).
-func (commit *Commit) Serialize() ([]byte, error) {
-	body, err := commit.serialize()
+// SerializeWithHeader renders the raw object (header + body).
+func (commit *Commit) SerializeWithHeader() ([]byte, error) {
+	body, err := commit.SerializeWithoutHeader()
 	if err != nil {
 		return nil, err
 	}
-	header, err := headerForType(objecttype.TypeCommit, body)
-	if err != nil {
-		return nil, err
+	header, ok := objectheader.Encode(objecttype.TypeCommit, int64(len(body)))
+	if !ok {
+		return nil, ErrInvalidObject
 	}
 	raw := make([]byte, len(header)+len(body))
 	copy(raw, header)
--- a/object/commit_serialize_test.go
+++ b/object/commit_serialize_test.go
@@ -19,9 +19,9 @@
 			t.Fatalf("ParseCommit: %v", err)
 		}
 
-		rawObj, err := commit.Serialize()
+		rawObj, err := commit.SerializeWithHeader()
 		if err != nil {
-			t.Fatalf("Serialize: %v", err)
+			t.Fatalf("SerializeWithHeader: %v", err)
 		}
 		gotID := algo.Sum(rawObj)
 		if gotID != commitID {
--- a/object/object.go
+++ b/object/object.go
@@ -2,9 +2,7 @@
 package object
 
 import (
-	"bytes"
 	"errors"
-	"strconv"
 
 	"codeberg.org/lindenii/furgit/objecttype"
 )
@@ -19,20 +17,6 @@
 // Object is a Git object that can serialize itself.
 type Object interface {
 	ObjectType() objecttype.Type
-	Serialize() ([]byte, error)
-}
-
-func headerForType(ty objecttype.Type, body []byte) ([]byte, error) {
-	tyStr, ok := objecttype.Name(ty)
-	if !ok {
-		return nil, ErrInvalidObject
-	}
-	size := strconv.Itoa(len(body))
-	var buf bytes.Buffer
-	buf.Grow(len(tyStr) + len(size) + 2)
-	buf.WriteString(tyStr)
-	buf.WriteByte(' ')
-	buf.WriteString(size)
-	buf.WriteByte(0)
-	return buf.Bytes(), nil
+	SerializeWithoutHeader() ([]byte, error)
+	SerializeWithHeader() ([]byte, error)
 }
--- a/object/tag_serialize.go
+++ b/object/tag_serialize.go
@@ -4,10 +4,12 @@
 	"bytes"
 	"fmt"
 
+	"codeberg.org/lindenii/furgit/internal/objectheader"
 	"codeberg.org/lindenii/furgit/objecttype"
 )
 
-func (tag *Tag) serialize() ([]byte, error) {
+// SerializeWithoutHeader renders the raw tag body bytes.
+func (tag *Tag) SerializeWithoutHeader() ([]byte, error) {
 	if tag.Target.Size() == 0 {
 		return nil, ErrInvalidObject
 	}
@@ -42,15 +44,15 @@
 	return buf.Bytes(), nil
 }
 
-// Serialize renders the raw object (header + body).
-func (tag *Tag) Serialize() ([]byte, error) {
-	body, err := tag.serialize()
+// SerializeWithHeader renders the raw object (header + body).
+func (tag *Tag) SerializeWithHeader() ([]byte, error) {
+	body, err := tag.SerializeWithoutHeader()
 	if err != nil {
 		return nil, err
 	}
-	header, err := headerForType(objecttype.TypeTag, body)
-	if err != nil {
-		return nil, err
+	header, ok := objectheader.Encode(objecttype.TypeTag, int64(len(body)))
+	if !ok {
+		return nil, ErrInvalidObject
 	}
 	raw := make([]byte, len(header)+len(body))
 	copy(raw, header)
--- a/object/tag_serialize_test.go
+++ b/object/tag_serialize_test.go
@@ -20,9 +20,9 @@
 			t.Fatalf("ParseTag: %v", err)
 		}
 
-		rawObj, err := tag.Serialize()
+		rawObj, err := tag.SerializeWithHeader()
 		if err != nil {
-			t.Fatalf("Serialize: %v", err)
+			t.Fatalf("SerializeWithHeader: %v", err)
 		}
 		gotID := algo.Sum(rawObj)
 		if gotID != tagID {
--- a/object/tree_serialize.go
+++ b/object/tree_serialize.go
@@ -3,10 +3,12 @@
 import (
 	"strconv"
 
+	"codeberg.org/lindenii/furgit/internal/objectheader"
 	"codeberg.org/lindenii/furgit/objecttype"
 )
 
-func (tree *Tree) serialize() []byte {
+// SerializeWithoutHeader renders the raw tree body bytes.
+func (tree *Tree) SerializeWithoutHeader() ([]byte, error) {
 	var bodyLen int
 	for _, entry := range tree.Entries {
 		mode := strconv.FormatUint(uint64(entry.Mode), 8)
@@ -27,15 +29,18 @@
 		pos += copy(body[pos:], id)
 	}
 
-	return body
+	return body, nil
 }
 
-// Serialize renders the raw object (header + body).
-func (tree *Tree) Serialize() ([]byte, error) {
-	body := tree.serialize()
-	header, err := headerForType(objecttype.TypeTree, body)
+// SerializeWithHeader renders the raw object (header + body).
+func (tree *Tree) SerializeWithHeader() ([]byte, error) {
+	body, err := tree.SerializeWithoutHeader()
 	if err != nil {
 		return nil, err
+	}
+	header, ok := objectheader.Encode(objecttype.TypeTree, int64(len(body)))
+	if !ok {
+		return nil, ErrInvalidObject
 	}
 	raw := make([]byte, len(header)+len(body))
 	copy(raw, header)
--- a/object/tree_serialize_test.go
+++ b/object/tree_serialize_test.go
@@ -48,9 +48,9 @@
 
 		wantTreeID := repo.Mktree(t, buildGitMktreeInput(tree.Entries))
 
-		rawObj, err := tree.Serialize()
+		rawObj, err := tree.SerializeWithHeader()
 		if err != nil {
-			t.Fatalf("Serialize: %v", err)
+			t.Fatalf("SerializeWithHeader: %v", err)
 		}
 		gotTreeID := algo.Sum(rawObj)
 		if gotTreeID != wantTreeID {
--