This repository has been archived by the owner on May 9, 2020. It is now read-only.
forked from bakanis/uuid
-
Notifications
You must be signed in to change notification settings - Fork 13
/
uuid.go
267 lines (225 loc) · 6.99 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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
// Package uuid provides RFC4122 and DCE 1.1 UUIDs.
//
// Use NewV1, NewV2, NewV3, NewV4, NewV5, for generating new UUIDs.
//
// Use New([]byte), NewHex(string), and Parse(string) for
// creating UUIDs from existing data.
//
// The original version was from Krzysztof Kowalik <chris@nu7hat.ch>
// Unfortunately, that version was non compliant with RFC4122.
//
// The package has since been redesigned.
//
// The example code in the specification was also used as reference for design.
//
// Copyright (C) 2016 myesui@github.com 2016 MIT licence
package uuid
import (
"bytes"
"encoding/binary"
"encoding/hex"
"errors"
"hash"
"regexp"
)
// Nil represents an empty UUID.
const Nil Immutable = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
// The following Immutable UUIDs are for use with V3 or V5 UUIDs.
const (
NameSpaceDNS Immutable = "k\xa7\xb8\x10\x9d\xad\x11р\xb4\x00\xc0O\xd40\xc8"
NameSpaceURL Immutable = "k\xa7\xb8\x11\x9d\xad\x11р\xb4\x00\xc0O\xd40\xc8"
NameSpaceOID Immutable = "k\xa7\xb8\x12\x9d\xad\x11р\xb4\x00\xc0O\xd40\xc8"
NameSpaceX500 Immutable = "k\xa7\xb8\x14\x9d\xad\x11р\xb4\x00\xc0O\xd40\xc8"
)
// SystemId denotes the type of id to retrieve from the operating system.
// That id is then used to create an identifier UUID.
type SystemId uint8
// The following SystemId's are for use with V2 UUIDs.
const (
SystemIdUser SystemId = iota + 1
SystemIdEffectiveUser
SystemIdGroup
SystemIdEffectiveGroup
SystemIdCallerProcess
SystemIdCallerProcessParent
)
// Implementation is the common interface implemented by all UUIDs.
type Implementation interface {
// Bytes retrieves the bytes from the underlying UUID
Bytes() []byte
// Size is the length of the underlying UUID implementation
Size() int
// String should return the canonical UUID representation, or the a
// given uuid.Format
String() string
// Variant returns the UUID implementation variant
Variant() uint8
// Version returns the version number of the algorithm used to generate
// the UUID.
Version() Version
}
// New creates a UUID from a slice of bytes.
func New(data []byte) UUID {
o := UUID{}
o.unmarshal(data)
return o
}
// NewHex creates a UUID from a hex string.
// Will panic if hex string is invalid use Parse otherwise.
func NewHex(uuid string) UUID {
o := UUID{}
o.unmarshal(fromHex(uuid))
return o
}
const (
// Pattern used to parse string representation of the UUID.
// Current one allows to parse string where only one opening
// or closing bracket or any of the hyphens are optional.
// It is only used to extract the main bytes to create a UUID,
// so these imperfections are of no consequence.
hexPattern = `^(urn\:uuid\:)?[\{\(\[]?([[:xdigit:]]{8})-?([[:xdigit:]]{4})-?([1-5][[:xdigit:]]{3})-?([[:xdigit:]]{4})-?([[:xdigit:]]{12})[\]\}\)]?$`
)
var (
parseUUIDRegex = regexp.MustCompile(hexPattern)
)
// Parse creates a UUID from a valid string representation.
// Accepts UUID string in following formats:
// 6ba7b8149dad11d180b400c04fd430c8
// 6ba7b814-9dad-11d1-80b4-00c04fd430c8
// {6ba7b814-9dad-11d1-80b4-00c04fd430c8}
// urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8
// [6ba7b814-9dad-11d1-80b4-00c04fd430c8]
// (6ba7b814-9dad-11d1-80b4-00c04fd430c8)
//
func Parse(uuid string) (*UUID, error) {
id, err := parse(uuid)
if err != nil {
return nil, err
}
a := UUID{}
a.unmarshal(id)
return &a, nil
}
func parse(uuid string) ([]byte, error) {
md := parseUUIDRegex.FindStringSubmatch(uuid)
if md == nil {
return nil, errors.New("uuid: invalid string format this is probably not a UUID")
}
return fromHex(md[2] + md[3] + md[4] + md[5] + md[6]), nil
}
func fromHex(uuid string) []byte {
bytes, err := hex.DecodeString(uuid)
if err != nil {
panic(err)
}
return bytes
}
// NewV1 generates a new RFC4122 version 1 UUID based on a 60 bit timestamp and
// node ID.
func NewV1() UUID {
return generator.NewV1()
}
// BulkV1 will return a slice of V1 UUIDs. Be careful with the set amount.
func BulkV1(amount int) []UUID {
return generator.BulkV1(amount)
}
// ReadV1 will read a slice of UUIDs. Be careful with the set amount.
func ReadV1(ids []UUID) {
generator.ReadV1(ids)
}
// NewV2 generates a new DCE Security version UUID based on a 60 bit timestamp,
// node id and POSIX UID.
func NewV2(pDomain SystemId) UUID {
return generator.NewV2(pDomain)
}
// NewV3 generates a new RFC4122 version 3 UUID based on the MD5 hash of a
// namespace UUID namespace Implementation UUID and one or more unique names.
func NewV3(namespace Implementation, names ...interface{}) UUID {
return generator.NewV3(namespace, names...)
}
// NewV4 generates a new RFC4122 version 4 UUID a cryptographically secure
// random UUID.
func NewV4() UUID {
return generator.NewV4()
}
// ReadV4 will read into a slice of UUIDs. Be careful with the set amount.
// Note: V4 UUIDs require sufficient entropy from the generator.
// If n == len(ids) err will be nil.
func ReadV4(ids []UUID) {
generator.ReadV4(ids)
}
// BulkV4 will return a slice of V4 UUIDs. Be careful with the set amount.
// Note: V4 UUIDs require sufficient entropy from the generator.
// If n == len(ids) err will be nil.
func BulkV4(amount int) []UUID {
return generator.BulkV4(amount)
}
// NewV5 generates an RFC4122 version 5 UUID based on the SHA-1 hash of a
// namespace Implementation UUID and one or more unique names.
func NewV5(namespace Implementation, names ...interface{}) UUID {
return generator.NewV5(namespace, names...)
}
// NewHash generate a UUID based on the given hash implementation. The hash will
// be of the given names. The version will be set to 0 for Unknown and the
// variant will be set to VariantFuture.
func NewHash(hash hash.Hash, names ...interface{}) UUID {
return generator.NewHash(hash, names...)
}
// Compare returns an integer comparing two Implementation UUIDs
// lexicographically.
// The result will be 0 if pId==pId2, -1 if pId < pId2, and +1 if pId > pId2.
// A nil argument is equivalent to the Nil Immutable UUID.
func Compare(pId, pId2 Implementation) int {
var b1, b2 = []byte(Nil), []byte(Nil)
if pId != nil {
b1 = pId.Bytes()
}
if pId2 != nil {
b2 = pId2.Bytes()
}
// Compare the time low bytes
tl1 := binary.BigEndian.Uint32(b1[:4])
tl2 := binary.BigEndian.Uint32(b2[:4])
if tl1 != tl2 {
if tl1 < tl2 {
return -1
}
return 1
}
// Compare the time hi and ver bytes
m1 := binary.BigEndian.Uint16(b1[4:6])
m2 := binary.BigEndian.Uint16(b2[4:6])
if m1 != m2 {
if m1 < m2 {
return -1
}
return 1
}
// Compare the sequence and version
m1 = binary.BigEndian.Uint16(b1[6:8])
m2 = binary.BigEndian.Uint16(b2[6:8])
if m1 != m2 {
if m1 < m2 {
return -1
}
return 1
}
// Compare the node id
return bytes.Compare(b1[8:], b2[8:])
}
// Equal compares whether each Implementation UUID is the same
func Equal(p1, p2 Implementation) bool {
return bytes.Equal(p1.Bytes(), p2.Bytes())
}
// IsNil returns true if Implementation UUID is all zeros?
func IsNil(uuid Implementation) bool {
if uuid == nil {
return true
}
for _, v := range uuid.Bytes() {
if v != 0 {
return false
}
}
return true
}