Fast implementation of Git in pure Go
at master 140 lines 2.9 kB view raw
1package objectid 2 3import ( 4 "crypto/sha1" //#nosec gosec 5 "crypto/sha256" 6 "hash" 7) 8 9// maxObjectIDSize MUST be >= the largest supported algorithm size. 10const maxObjectIDSize = sha256.Size 11 12// Algorithm identifies the hash algorithm used for Git object IDs. 13type Algorithm uint8 14 15const ( 16 AlgorithmUnknown Algorithm = iota 17 AlgorithmSHA1 18 AlgorithmSHA256 19) 20 21type algorithmDetails struct { 22 name string 23 size int 24 packHashID uint32 25 sum func([]byte) ObjectID 26 new func() hash.Hash 27} 28 29//nolint:gochecknoglobals 30var algorithmTable = [...]algorithmDetails{ 31 AlgorithmUnknown: {}, 32 AlgorithmSHA1: { 33 name: "sha1", 34 size: sha1.Size, 35 packHashID: 1, 36 sum: func(data []byte) ObjectID { 37 sum := sha1.Sum(data) //#nosec G401 38 39 var id ObjectID 40 copy(id.data[:], sum[:]) 41 id.algo = AlgorithmSHA1 42 43 return id 44 }, 45 new: sha1.New, 46 }, 47 AlgorithmSHA256: { 48 name: "sha256", 49 size: sha256.Size, 50 packHashID: 2, 51 sum: func(data []byte) ObjectID { 52 sum := sha256.Sum256(data) 53 54 var id ObjectID 55 copy(id.data[:], sum[:]) 56 id.algo = AlgorithmSHA256 57 58 return id 59 }, 60 new: sha256.New, 61 }, 62} 63 64var ( 65 //nolint:gochecknoglobals 66 algorithmByName = map[string]Algorithm{} 67 //nolint:gochecknoglobals 68 supportedAlgorithms []Algorithm 69) 70 71func init() { //nolint:gochecknoinits 72 for algo := Algorithm(0); int(algo) < len(algorithmTable); algo++ { 73 info := algorithmTable[algo] 74 if info.name == "" { 75 continue 76 } 77 78 algorithmByName[info.name] = algo 79 supportedAlgorithms = append(supportedAlgorithms, algo) 80 } 81} 82 83// SupportedAlgorithms returns all object ID algorithms supported by furgit. 84// Do not mutate. 85func SupportedAlgorithms() []Algorithm { 86 return supportedAlgorithms 87} 88 89// ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256"). 90func ParseAlgorithm(s string) (Algorithm, bool) { 91 algo, ok := algorithmByName[s] 92 93 return algo, ok 94} 95 96// Size returns the hash size in bytes. 97func (algo Algorithm) Size() int { 98 return algo.info().size 99} 100 101// String returns the canonical algorithm name. 102func (algo Algorithm) String() string { 103 inf := algo.info() 104 if inf.name == "" { 105 return "unknown" 106 } 107 108 return inf.name 109} 110 111// HexLen returns the encoded hexadecimal length. 112func (algo Algorithm) HexLen() int { 113 return algo.Size() * 2 114} 115 116// PackHashID returns the Git pack/rev hash-id encoding for this algorithm. 117// 118// Unknown algorithms return 0. 119func (algo Algorithm) PackHashID() uint32 { 120 return algo.info().packHashID 121} 122 123// Sum computes an object ID from raw data using the selected algorithm. 124func (algo Algorithm) Sum(data []byte) ObjectID { 125 return algo.info().sum(data) 126} 127 128// New returns a new hash.Hash for this algorithm. 129func (algo Algorithm) New() (hash.Hash, error) { 130 newFn := algo.info().new 131 if newFn == nil { 132 return nil, ErrInvalidAlgorithm 133 } 134 135 return newFn(), nil 136} 137 138func (algo Algorithm) info() algorithmDetails { 139 return algorithmTable[algo] 140}