2014-09-23 20:39:12 +00:00
|
|
|
package backend
|
2014-04-21 21:25:31 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2014-09-21 14:33:20 +00:00
|
|
|
"crypto/sha256"
|
2014-04-21 21:25:31 +00:00
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
2014-09-23 20:39:12 +00:00
|
|
|
"errors"
|
2014-12-21 14:57:41 +00:00
|
|
|
"sync"
|
2014-04-21 21:25:31 +00:00
|
|
|
)
|
|
|
|
|
2014-11-23 15:48:00 +00:00
|
|
|
// IDSize contains the size of an ID, in bytes.
|
|
|
|
const IDSize = sha256.Size
|
2014-09-23 20:39:12 +00:00
|
|
|
|
2014-04-21 21:25:31 +00:00
|
|
|
// References content within a repository.
|
|
|
|
type ID []byte
|
|
|
|
|
2014-12-21 14:57:41 +00:00
|
|
|
var idPool = sync.Pool{New: func() interface{} { return ID(make([]byte, IDSize)) }}
|
|
|
|
|
2014-04-21 21:25:31 +00:00
|
|
|
// ParseID converts the given string to an ID.
|
|
|
|
func ParseID(s string) (ID, error) {
|
|
|
|
b, err := hex.DecodeString(s)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:48:00 +00:00
|
|
|
if len(b) != IDSize {
|
2014-09-23 20:39:12 +00:00
|
|
|
return nil, errors.New("invalid length for sha256 hash")
|
|
|
|
}
|
|
|
|
|
2014-04-21 21:25:31 +00:00
|
|
|
return ID(b), nil
|
|
|
|
}
|
2014-07-28 18:20:32 +00:00
|
|
|
|
2014-04-21 21:25:31 +00:00
|
|
|
func (id ID) String() string {
|
|
|
|
return hex.EncodeToString(id)
|
|
|
|
}
|
|
|
|
|
2015-01-10 22:40:10 +00:00
|
|
|
const shortStr = 4
|
|
|
|
|
|
|
|
func (id ID) Str() string {
|
|
|
|
return hex.EncodeToString(id[:shortStr])
|
|
|
|
}
|
|
|
|
|
2014-04-21 21:25:31 +00:00
|
|
|
// Equal compares an ID to another other.
|
|
|
|
func (id ID) Equal(other ID) bool {
|
|
|
|
return bytes.Equal(id, other)
|
|
|
|
}
|
|
|
|
|
|
|
|
// EqualString compares this ID to another one, given as a string.
|
|
|
|
func (id ID) EqualString(other string) (bool, error) {
|
|
|
|
s, err := hex.DecodeString(other)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return id.Equal(ID(s)), nil
|
|
|
|
}
|
|
|
|
|
2014-11-21 20:21:44 +00:00
|
|
|
// Compare compares this ID to another one, returning -1, 0, or 1.
|
|
|
|
func (id ID) Compare(other ID) int {
|
|
|
|
return bytes.Compare(other, id)
|
|
|
|
}
|
|
|
|
|
2014-04-21 21:25:31 +00:00
|
|
|
func (id ID) MarshalJSON() ([]byte, error) {
|
|
|
|
return json.Marshal(id.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (id *ID) UnmarshalJSON(b []byte) error {
|
|
|
|
var s string
|
|
|
|
err := json.Unmarshal(b, &s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:48:00 +00:00
|
|
|
*id = idPool.Get().(ID)
|
2014-04-21 21:25:31 +00:00
|
|
|
_, err = hex.Decode(*id, []byte(s))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2014-09-21 14:33:20 +00:00
|
|
|
|
|
|
|
func IDFromData(d []byte) ID {
|
|
|
|
hash := sha256.Sum256(d)
|
2014-11-23 15:48:00 +00:00
|
|
|
id := idPool.Get().(ID)
|
2014-09-21 14:33:20 +00:00
|
|
|
copy(id, hash[:])
|
|
|
|
return id
|
|
|
|
}
|
2014-09-23 20:39:12 +00:00
|
|
|
|
2014-11-23 15:48:00 +00:00
|
|
|
// Free returns the ID byte slice back to the allocation pool.
|
|
|
|
func (id ID) Free() {
|
|
|
|
idPool.Put(id)
|
|
|
|
}
|
|
|
|
|
2014-09-23 20:39:12 +00:00
|
|
|
type IDs []ID
|
|
|
|
|
|
|
|
func (ids IDs) Len() int {
|
|
|
|
return len(ids)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ids IDs) Less(i, j int) bool {
|
|
|
|
if len(ids[i]) < len(ids[j]) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, b := range ids[i] {
|
|
|
|
if b == ids[j][k] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if b < ids[j][k] {
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ids IDs) Swap(i, j int) {
|
|
|
|
ids[i], ids[j] = ids[j], ids[i]
|
|
|
|
}
|