-
Notifications
You must be signed in to change notification settings - Fork 0
/
uuid.go
127 lines (102 loc) · 2.17 KB
/
uuid.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
122
123
124
125
126
127
package uuid
import (
"crypto/rand"
"database/sql/driver"
"encoding/hex"
"errors"
"fmt"
"io"
)
// UUID is 128bits = 16bytes
type UUID [16]byte
func NewMust() *UUID {
id, err := New()
if err != nil {
return NewMust()
}
return id
}
// New generates new unique UUID v4
func New() (*UUID, error) {
uuid := new(UUID)
n, err := io.ReadFull(rand.Reader, uuid[:])
if err != nil {
return nil, err
}
if n != len(uuid) {
return nil, errors.New(fmt.Sprintf("insufficient random data (expected: %d, read: %d)", len(uuid), n))
}
// variant bits; for more info
// see https://www.ietf.org/rfc/rfc4122.txt section 4.1.1
uuid[8] = uuid[8]&0x3f | 0x80
// version 4 (pseudo-random); for more info
// see https://www.ietf.org/rfc/rfc4122.txt section 4.1.3
uuid[6] = uuid[6]&0x0f | 0x40
return uuid, nil
}
// String stringify UUID to 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' format
func (uuid UUID) String() string {
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
}
func (uuid UUID) RawString() string {
return fmt.Sprintf("%x", uuid[:])
}
func (uuid UUID) IsZero() bool {
var zeroUuid UUID
return Equal(zeroUuid, uuid)
}
func (uuid UUID) MarshalJSON() ([]byte, error) {
return []byte(`"` + uuid.String() + `"`), nil
}
func (uuid *UUID) UnmarshalJSON(b []byte) error {
if u, err := Parse(string(b)); err != nil {
return err
} else {
copy(uuid[:], u[:])
return nil
}
}
// Equal compares uuid by bytes
func Equal(uuid1 UUID, uuid2 UUID) bool {
for i, v := range uuid1 {
if v != uuid2[i] {
return false
}
}
return true
}
func (uuid UUID) Value() (driver.Value, error) {
return uuid[:], nil
}
func (uuid *UUID) Scan(value interface{}) error {
b, ok := value.([]byte)
if !ok {
// return Error.New("unexpected type %T for uuid", src)
*uuid = UUID{}
return nil
}
switch len(b) {
case 32:
dst := make([]byte, 16)
_, err := hex.Decode(dst, b)
if err != nil {
return err
}
b = dst
fallthrough
case 16:
toUUID, err := FromBytes(b)
if err != nil {
return err
}
*uuid = toUUID
return nil
default:
id, err := Parse(string(b))
if err != nil {
return err
}
*uuid = *id
return nil
}
}