From 94bfb1fa147f80e6ec39009d41fc2f853925e0a5 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sun, 16 Nov 2025 00:00:00 +0000 Subject: hash: Generic hash-algorithm API --- obj_tree.go | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'obj_tree.go') diff --git a/obj_tree.go b/obj_tree.go index 55a27a08..c025dfa3 100644 --- a/obj_tree.go +++ b/obj_tree.go @@ -8,26 +8,27 @@ import ( ) // Tree represents a Git tree object. -type Tree struct { - Hash Hash - Entries []TreeEntry +type Tree[T HashType] struct { + Hash Hash[T] + Entries []TreeEntry[T] } // TreeEntry represents a single entry in a Git tree. -type TreeEntry struct { +type TreeEntry[T HashType] struct { Mode uint32 Name []byte - ID Hash + ID Hash[T] } // ObjType allows Tree to satisfy the Object interface. -func (*Tree) ObjType() ObjType { +func (*Tree[T]) ObjType() ObjType { return ObjTree } // parseTree decodes a tree body. -func parseTree(id Hash, body []byte, hashSize int) (*Tree, error) { - var entries []TreeEntry +func parseTree[T HashType](id Hash[T], body []byte) (*Tree[T], error) { + var entries []TreeEntry[T] + hashSize := hashLen[T]() i := 0 for i < len(body) { space := bytes.IndexByte(body[i:], ' ') @@ -47,8 +48,8 @@ func parseTree(id Hash, body []byte, hashSize int) (*Tree, error) { if i+hashSize > len(body) { return nil, errors.New("furgit: tree: truncated child hash") } - var child Hash - copy(child[:], body[i:i+hashSize]) + var child Hash[T] + copy(child.Slice(), body[i:i+hashSize]) i += hashSize mode, err := strconv.ParseUint(string(modeBytes), 8, 32) @@ -56,7 +57,7 @@ func parseTree(id Hash, body []byte, hashSize int) (*Tree, error) { return nil, fmt.Errorf("furgit: tree: parse mode: %w", err) } - entry := TreeEntry{ + entry := TreeEntry[T]{ Mode: uint32(mode), Name: append([]byte(nil), nameBytes...), ID: child, @@ -64,14 +65,15 @@ func parseTree(id Hash, body []byte, hashSize int) (*Tree, error) { entries = append(entries, entry) } - return &Tree{ + return &Tree[T]{ Hash: id, Entries: entries, }, nil } // treeBody builds the entry list for a tree without the Git header. -func treeBody(t *Tree, hashSize int) []byte { +func treeBody[T HashType](t *Tree[T]) []byte { + hashSize := hashLen[T]() var bodyLen int for _, e := range t.Entries { mode := strconv.FormatUint(uint64(e.Mode), 8) @@ -88,15 +90,15 @@ func treeBody(t *Tree, hashSize int) []byte { pos += copy(body[pos:], e.Name) body[pos] = 0 pos++ - pos += copy(body[pos:], e.ID[:hashSize]) + pos += copy(body[pos:], e.ID.Slice()[:hashSize]) } return body } // Serialize renders a Tree into canonical Git format. -func (t *Tree) Serialize(hashSize int) ([]byte, error) { - body := treeBody(t, hashSize) +func (t *Tree[T]) Serialize() ([]byte, error) { + body := treeBody(t) header, err := headerForType(ObjTree, body) if err != nil { return nil, err @@ -109,7 +111,7 @@ func (t *Tree) Serialize(hashSize int) ([]byte, error) { } // Entry looks up a tree entry by name. -func (t *Tree) Entry(name []byte) *TreeEntry { +func (t *Tree[T]) Entry(name []byte) *TreeEntry[T] { low, high := 0, len(t.Entries)-1 for low <= high { mid := (low + high) / 2 -- cgit v1.3.1-10-gc9f91