-
Notifications
You must be signed in to change notification settings - Fork 641
/
short.go
121 lines (100 loc) · 3.12 KB
/
short.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package ids
import (
"bytes"
"encoding/hex"
"sort"
"github.com/ava-labs/gecko/utils"
"github.com/ava-labs/gecko/utils/formatting"
"github.com/ava-labs/gecko/utils/hashing"
)
// ShortEmpty is a useful all zero value
var ShortEmpty = ShortID{ID: &[20]byte{}}
// ShortID wraps a 20 byte hash as an identifier
type ShortID struct {
ID *[20]byte `serialize:"true"`
}
// NewShortID creates an identifer from a 20 byte hash
func NewShortID(id [20]byte) ShortID { return ShortID{ID: &id} }
// ToShortID attempt to convert a byte slice into an id
func ToShortID(bytes []byte) (ShortID, error) {
addrHash, err := hashing.ToHash160(bytes)
return NewShortID(addrHash), err
}
// ShortFromString is the inverse of ShortID.String()
func ShortFromString(idStr string) (ShortID, error) {
cb58 := formatting.CB58{}
err := cb58.FromString(idStr)
if err != nil {
return ShortID{}, err
}
return ToShortID(cb58.Bytes)
}
// MarshalJSON ...
func (id ShortID) MarshalJSON() ([]byte, error) {
if id.IsZero() {
return []byte("null"), nil
}
cb58 := formatting.CB58{Bytes: id.ID[:]}
return cb58.MarshalJSON()
}
// UnmarshalJSON ...
func (id *ShortID) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
return nil
}
cb58 := formatting.CB58{}
if err := cb58.UnmarshalJSON(b); err != nil {
return err
}
newID, err := ToShortID(cb58.Bytes)
if err != nil {
return err
}
*id = newID
return nil
}
// IsZero returns true if the value has not been initialized
func (id ShortID) IsZero() bool { return id.ID == nil }
// LongID returns a 32 byte identifier from this id
func (id ShortID) LongID() ID {
dest := [32]byte{}
copy(dest[:], id.ID[:])
return NewID(dest)
}
// Key returns a 20 byte hash that this id represents. This is useful to allow
// for this id to be used as keys in maps.
func (id ShortID) Key() [20]byte { return *id.ID }
// Equals returns true if the ids have the same byte representation
func (id ShortID) Equals(oID ShortID) bool {
return id.ID == oID.ID ||
(id.ID != nil && oID.ID != nil && bytes.Equal(id.Bytes(), oID.Bytes()))
}
// Bytes returns the 20 byte hash as a slice. It is assumed this slice is not
// modified.
func (id ShortID) Bytes() []byte { return id.ID[:] }
// Hex returns a hex encoded string of this id.
func (id ShortID) Hex() string { return hex.EncodeToString(id.Bytes()) }
func (id ShortID) String() string {
if id.IsZero() {
return "nil"
}
bytes := id.Bytes()
cb58 := formatting.CB58{Bytes: bytes}
return cb58.String()
}
type sortShortIDData []ShortID
func (ids sortShortIDData) Less(i, j int) bool {
return bytes.Compare(
ids[i].Bytes(),
ids[j].Bytes()) == -1
}
func (ids sortShortIDData) Len() int { return len(ids) }
func (ids sortShortIDData) Swap(i, j int) { ids[j], ids[i] = ids[i], ids[j] }
// SortShortIDs sorts the ids lexicographically
func SortShortIDs(ids []ShortID) { sort.Sort(sortShortIDData(ids)) }
// IsSortedAndUniqueShortIDs returns true if the ids are sorted and unique
func IsSortedAndUniqueShortIDs(ids []ShortID) bool {
return utils.IsSortedAndUnique(sortShortIDData(ids))
}