ires 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ // Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining
4
+ // a copy of this software and associated documentation files (the
5
+ // "Software"), to deal in the Software without restriction, including
6
+ // without limitation the rights to use, copy, modify, merge, publish,
7
+ // distribute, sublicense, and/or sell copies of the Software, and to
8
+ // permit persons to whom the Software is furnished to do so, subject to
9
+ // the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be
12
+ // included in all copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ package uuid
23
+
24
+ import (
25
+ "testing"
26
+ )
27
+
28
+ func BenchmarkFromBytes(b *testing.B) {
29
+ bytes := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
30
+ for i := 0; i < b.N; i++ {
31
+ FromBytes(bytes)
32
+ }
33
+ }
34
+
35
+ func BenchmarkFromString(b *testing.B) {
36
+ s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
37
+ for i := 0; i < b.N; i++ {
38
+ FromString(s)
39
+ }
40
+ }
41
+
42
+ func BenchmarkFromStringUrn(b *testing.B) {
43
+ s := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
44
+ for i := 0; i < b.N; i++ {
45
+ FromString(s)
46
+ }
47
+ }
48
+
49
+ func BenchmarkFromStringWithBrackets(b *testing.B) {
50
+ s := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}"
51
+ for i := 0; i < b.N; i++ {
52
+ FromString(s)
53
+ }
54
+ }
55
+
56
+ func BenchmarkNewV1(b *testing.B) {
57
+ for i := 0; i < b.N; i++ {
58
+ NewV1()
59
+ }
60
+ }
61
+
62
+ func BenchmarkNewV2(b *testing.B) {
63
+ for i := 0; i < b.N; i++ {
64
+ NewV2(DomainPerson)
65
+ }
66
+ }
67
+
68
+ func BenchmarkNewV3(b *testing.B) {
69
+ for i := 0; i < b.N; i++ {
70
+ NewV3(NamespaceDNS, "www.example.com")
71
+ }
72
+ }
73
+
74
+ func BenchmarkNewV4(b *testing.B) {
75
+ for i := 0; i < b.N; i++ {
76
+ NewV4()
77
+ }
78
+ }
79
+
80
+ func BenchmarkNewV5(b *testing.B) {
81
+ for i := 0; i < b.N; i++ {
82
+ NewV5(NamespaceDNS, "www.example.com")
83
+ }
84
+ }
85
+
86
+ func BenchmarkMarshalBinary(b *testing.B) {
87
+ u := NewV4()
88
+ for i := 0; i < b.N; i++ {
89
+ u.MarshalBinary()
90
+ }
91
+ }
92
+
93
+ func BenchmarkMarshalText(b *testing.B) {
94
+ u := NewV4()
95
+ for i := 0; i < b.N; i++ {
96
+ u.MarshalText()
97
+ }
98
+ }
99
+
100
+ func BenchmarkUnmarshalBinary(b *testing.B) {
101
+ bytes := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
102
+ u := UUID{}
103
+ for i := 0; i < b.N; i++ {
104
+ u.UnmarshalBinary(bytes)
105
+ }
106
+ }
107
+
108
+ func BenchmarkUnmarshalText(b *testing.B) {
109
+ bytes := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
110
+ u := UUID{}
111
+ for i := 0; i < b.N; i++ {
112
+ u.UnmarshalText(bytes)
113
+ }
114
+ }
115
+
116
+ func BenchmarkMarshalToString(b *testing.B) {
117
+ u := NewV4()
118
+ for i := 0; i < b.N; i++ {
119
+ u.String()
120
+ }
121
+ }
@@ -0,0 +1,488 @@
1
+ // Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining
4
+ // a copy of this software and associated documentation files (the
5
+ // "Software"), to deal in the Software without restriction, including
6
+ // without limitation the rights to use, copy, modify, merge, publish,
7
+ // distribute, sublicense, and/or sell copies of the Software, and to
8
+ // permit persons to whom the Software is furnished to do so, subject to
9
+ // the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be
12
+ // included in all copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ // Package uuid provides implementation of Universally Unique Identifier (UUID).
23
+ // Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
24
+ // version 2 (as specified in DCE 1.1).
25
+ package uuid
26
+
27
+ import (
28
+ "bytes"
29
+ "crypto/md5"
30
+ "crypto/rand"
31
+ "crypto/sha1"
32
+ "database/sql/driver"
33
+ "encoding/binary"
34
+ "encoding/hex"
35
+ "fmt"
36
+ "hash"
37
+ "net"
38
+ "os"
39
+ "sync"
40
+ "time"
41
+ )
42
+
43
+ // UUID layout variants.
44
+ const (
45
+ VariantNCS = iota
46
+ VariantRFC4122
47
+ VariantMicrosoft
48
+ VariantFuture
49
+ )
50
+
51
+ // UUID DCE domains.
52
+ const (
53
+ DomainPerson = iota
54
+ DomainGroup
55
+ DomainOrg
56
+ )
57
+
58
+ // Difference in 100-nanosecond intervals between
59
+ // UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
60
+ const epochStart = 122192928000000000
61
+
62
+ // Used in string method conversion
63
+ const dash byte = '-'
64
+
65
+ // UUID v1/v2 storage.
66
+ var (
67
+ storageMutex sync.Mutex
68
+ storageOnce sync.Once
69
+ epochFunc = unixTimeFunc
70
+ clockSequence uint16
71
+ lastTime uint64
72
+ hardwareAddr [6]byte
73
+ posixUID = uint32(os.Getuid())
74
+ posixGID = uint32(os.Getgid())
75
+ )
76
+
77
+ // String parse helpers.
78
+ var (
79
+ urnPrefix = []byte("urn:uuid:")
80
+ byteGroups = []int{8, 4, 4, 4, 12}
81
+ )
82
+
83
+ func initClockSequence() {
84
+ buf := make([]byte, 2)
85
+ safeRandom(buf)
86
+ clockSequence = binary.BigEndian.Uint16(buf)
87
+ }
88
+
89
+ func initHardwareAddr() {
90
+ interfaces, err := net.Interfaces()
91
+ if err == nil {
92
+ for _, iface := range interfaces {
93
+ if len(iface.HardwareAddr) >= 6 {
94
+ copy(hardwareAddr[:], iface.HardwareAddr)
95
+ return
96
+ }
97
+ }
98
+ }
99
+
100
+ // Initialize hardwareAddr randomly in case
101
+ // of real network interfaces absence
102
+ safeRandom(hardwareAddr[:])
103
+
104
+ // Set multicast bit as recommended in RFC 4122
105
+ hardwareAddr[0] |= 0x01
106
+ }
107
+
108
+ func initStorage() {
109
+ initClockSequence()
110
+ initHardwareAddr()
111
+ }
112
+
113
+ func safeRandom(dest []byte) {
114
+ if _, err := rand.Read(dest); err != nil {
115
+ panic(err)
116
+ }
117
+ }
118
+
119
+ // Returns difference in 100-nanosecond intervals between
120
+ // UUID epoch (October 15, 1582) and current time.
121
+ // This is default epoch calculation function.
122
+ func unixTimeFunc() uint64 {
123
+ return epochStart + uint64(time.Now().UnixNano()/100)
124
+ }
125
+
126
+ // UUID representation compliant with specification
127
+ // described in RFC 4122.
128
+ type UUID [16]byte
129
+
130
+ // NullUUID can be used with the standard sql package to represent a
131
+ // UUID value that can be NULL in the database
132
+ type NullUUID struct {
133
+ UUID UUID
134
+ Valid bool
135
+ }
136
+
137
+ // The nil UUID is special form of UUID that is specified to have all
138
+ // 128 bits set to zero.
139
+ var Nil = UUID{}
140
+
141
+ // Predefined namespace UUIDs.
142
+ var (
143
+ NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
144
+ NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
145
+ NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
146
+ NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
147
+ )
148
+
149
+ // And returns result of binary AND of two UUIDs.
150
+ func And(u1 UUID, u2 UUID) UUID {
151
+ u := UUID{}
152
+ for i := 0; i < 16; i++ {
153
+ u[i] = u1[i] & u2[i]
154
+ }
155
+ return u
156
+ }
157
+
158
+ // Or returns result of binary OR of two UUIDs.
159
+ func Or(u1 UUID, u2 UUID) UUID {
160
+ u := UUID{}
161
+ for i := 0; i < 16; i++ {
162
+ u[i] = u1[i] | u2[i]
163
+ }
164
+ return u
165
+ }
166
+
167
+ // Equal returns true if u1 and u2 equals, otherwise returns false.
168
+ func Equal(u1 UUID, u2 UUID) bool {
169
+ return bytes.Equal(u1[:], u2[:])
170
+ }
171
+
172
+ // Version returns algorithm version used to generate UUID.
173
+ func (u UUID) Version() uint {
174
+ return uint(u[6] >> 4)
175
+ }
176
+
177
+ // Variant returns UUID layout variant.
178
+ func (u UUID) Variant() uint {
179
+ switch {
180
+ case (u[8] & 0x80) == 0x00:
181
+ return VariantNCS
182
+ case (u[8]&0xc0)|0x80 == 0x80:
183
+ return VariantRFC4122
184
+ case (u[8]&0xe0)|0xc0 == 0xc0:
185
+ return VariantMicrosoft
186
+ }
187
+ return VariantFuture
188
+ }
189
+
190
+ // Bytes returns bytes slice representation of UUID.
191
+ func (u UUID) Bytes() []byte {
192
+ return u[:]
193
+ }
194
+
195
+ // Returns canonical string representation of UUID:
196
+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
197
+ func (u UUID) String() string {
198
+ buf := make([]byte, 36)
199
+
200
+ hex.Encode(buf[0:8], u[0:4])
201
+ buf[8] = dash
202
+ hex.Encode(buf[9:13], u[4:6])
203
+ buf[13] = dash
204
+ hex.Encode(buf[14:18], u[6:8])
205
+ buf[18] = dash
206
+ hex.Encode(buf[19:23], u[8:10])
207
+ buf[23] = dash
208
+ hex.Encode(buf[24:], u[10:])
209
+
210
+ return string(buf)
211
+ }
212
+
213
+ // SetVersion sets version bits.
214
+ func (u *UUID) SetVersion(v byte) {
215
+ u[6] = (u[6] & 0x0f) | (v << 4)
216
+ }
217
+
218
+ // SetVariant sets variant bits as described in RFC 4122.
219
+ func (u *UUID) SetVariant() {
220
+ u[8] = (u[8] & 0xbf) | 0x80
221
+ }
222
+
223
+ // MarshalText implements the encoding.TextMarshaler interface.
224
+ // The encoding is the same as returned by String.
225
+ func (u UUID) MarshalText() (text []byte, err error) {
226
+ text = []byte(u.String())
227
+ return
228
+ }
229
+
230
+ // UnmarshalText implements the encoding.TextUnmarshaler interface.
231
+ // Following formats are supported:
232
+ // "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
233
+ // "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
234
+ // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
235
+ func (u *UUID) UnmarshalText(text []byte) (err error) {
236
+ if len(text) < 32 {
237
+ err = fmt.Errorf("uuid: UUID string too short: %s", text)
238
+ return
239
+ }
240
+
241
+ t := text[:]
242
+ braced := false
243
+
244
+ if bytes.Equal(t[:9], urnPrefix) {
245
+ t = t[9:]
246
+ } else if t[0] == '{' {
247
+ braced = true
248
+ t = t[1:]
249
+ }
250
+
251
+ b := u[:]
252
+
253
+ for i, byteGroup := range byteGroups {
254
+ if i > 0 && t[0] == '-' {
255
+ t = t[1:]
256
+ } else if i > 0 && t[0] != '-' {
257
+ err = fmt.Errorf("uuid: invalid string format")
258
+ return
259
+ }
260
+
261
+ if i == 2 {
262
+ if !bytes.Contains([]byte("012345"), []byte{t[0]}) {
263
+ err = fmt.Errorf("uuid: invalid version number: %s", t[0])
264
+ return
265
+ }
266
+ }
267
+
268
+ if len(t) < byteGroup {
269
+ err = fmt.Errorf("uuid: UUID string too short: %s", text)
270
+ return
271
+ }
272
+
273
+ if i == 4 && len(t) > byteGroup &&
274
+ ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) {
275
+ err = fmt.Errorf("uuid: UUID string too long: %s", t)
276
+ return
277
+ }
278
+
279
+ _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup])
280
+
281
+ if err != nil {
282
+ return
283
+ }
284
+
285
+ t = t[byteGroup:]
286
+ b = b[byteGroup/2:]
287
+ }
288
+
289
+ return
290
+ }
291
+
292
+ // MarshalBinary implements the encoding.BinaryMarshaler interface.
293
+ func (u UUID) MarshalBinary() (data []byte, err error) {
294
+ data = u.Bytes()
295
+ return
296
+ }
297
+
298
+ // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
299
+ // It will return error if the slice isn't 16 bytes long.
300
+ func (u *UUID) UnmarshalBinary(data []byte) (err error) {
301
+ if len(data) != 16 {
302
+ err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
303
+ return
304
+ }
305
+ copy(u[:], data)
306
+
307
+ return
308
+ }
309
+
310
+ // Value implements the driver.Valuer interface.
311
+ func (u UUID) Value() (driver.Value, error) {
312
+ return u.String(), nil
313
+ }
314
+
315
+ // Scan implements the sql.Scanner interface.
316
+ // A 16-byte slice is handled by UnmarshalBinary, while
317
+ // a longer byte slice or a string is handled by UnmarshalText.
318
+ func (u *UUID) Scan(src interface{}) error {
319
+ switch src := src.(type) {
320
+ case []byte:
321
+ if len(src) == 16 {
322
+ return u.UnmarshalBinary(src)
323
+ }
324
+ return u.UnmarshalText(src)
325
+
326
+ case string:
327
+ return u.UnmarshalText([]byte(src))
328
+ }
329
+
330
+ return fmt.Errorf("uuid: cannot convert %T to UUID", src)
331
+ }
332
+
333
+ // Value implements the driver.Valuer interface.
334
+ func (u NullUUID) Value() (driver.Value, error) {
335
+ if !u.Valid {
336
+ return nil, nil
337
+ }
338
+ // Delegate to UUID Value function
339
+ return u.UUID.Value()
340
+ }
341
+
342
+ // Scan implements the sql.Scanner interface.
343
+ func (u *NullUUID) Scan(src interface{}) error {
344
+ if src == nil {
345
+ u.UUID, u.Valid = Nil, false
346
+ return nil
347
+ }
348
+
349
+ // Delegate to UUID Scan function
350
+ u.Valid = true
351
+ return u.UUID.Scan(src)
352
+ }
353
+
354
+ // FromBytes returns UUID converted from raw byte slice input.
355
+ // It will return error if the slice isn't 16 bytes long.
356
+ func FromBytes(input []byte) (u UUID, err error) {
357
+ err = u.UnmarshalBinary(input)
358
+ return
359
+ }
360
+
361
+ // FromBytesOrNil returns UUID converted from raw byte slice input.
362
+ // Same behavior as FromBytes, but returns a Nil UUID on error.
363
+ func FromBytesOrNil(input []byte) UUID {
364
+ uuid, err := FromBytes(input)
365
+ if err != nil {
366
+ return Nil
367
+ }
368
+ return uuid
369
+ }
370
+
371
+ // FromString returns UUID parsed from string input.
372
+ // Input is expected in a form accepted by UnmarshalText.
373
+ func FromString(input string) (u UUID, err error) {
374
+ err = u.UnmarshalText([]byte(input))
375
+ return
376
+ }
377
+
378
+ // FromStringOrNil returns UUID parsed from string input.
379
+ // Same behavior as FromString, but returns a Nil UUID on error.
380
+ func FromStringOrNil(input string) UUID {
381
+ uuid, err := FromString(input)
382
+ if err != nil {
383
+ return Nil
384
+ }
385
+ return uuid
386
+ }
387
+
388
+ // Returns UUID v1/v2 storage state.
389
+ // Returns epoch timestamp, clock sequence, and hardware address.
390
+ func getStorage() (uint64, uint16, []byte) {
391
+ storageOnce.Do(initStorage)
392
+
393
+ storageMutex.Lock()
394
+ defer storageMutex.Unlock()
395
+
396
+ timeNow := epochFunc()
397
+ // Clock changed backwards since last UUID generation.
398
+ // Should increase clock sequence.
399
+ if timeNow <= lastTime {
400
+ clockSequence++
401
+ }
402
+ lastTime = timeNow
403
+
404
+ return timeNow, clockSequence, hardwareAddr[:]
405
+ }
406
+
407
+ // NewV1 returns UUID based on current timestamp and MAC address.
408
+ func NewV1() UUID {
409
+ u := UUID{}
410
+
411
+ timeNow, clockSeq, hardwareAddr := getStorage()
412
+
413
+ binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
414
+ binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
415
+ binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
416
+ binary.BigEndian.PutUint16(u[8:], clockSeq)
417
+
418
+ copy(u[10:], hardwareAddr)
419
+
420
+ u.SetVersion(1)
421
+ u.SetVariant()
422
+
423
+ return u
424
+ }
425
+
426
+ // NewV2 returns DCE Security UUID based on POSIX UID/GID.
427
+ func NewV2(domain byte) UUID {
428
+ u := UUID{}
429
+
430
+ timeNow, clockSeq, hardwareAddr := getStorage()
431
+
432
+ switch domain {
433
+ case DomainPerson:
434
+ binary.BigEndian.PutUint32(u[0:], posixUID)
435
+ case DomainGroup:
436
+ binary.BigEndian.PutUint32(u[0:], posixGID)
437
+ }
438
+
439
+ binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
440
+ binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
441
+ binary.BigEndian.PutUint16(u[8:], clockSeq)
442
+ u[9] = domain
443
+
444
+ copy(u[10:], hardwareAddr)
445
+
446
+ u.SetVersion(2)
447
+ u.SetVariant()
448
+
449
+ return u
450
+ }
451
+
452
+ // NewV3 returns UUID based on MD5 hash of namespace UUID and name.
453
+ func NewV3(ns UUID, name string) UUID {
454
+ u := newFromHash(md5.New(), ns, name)
455
+ u.SetVersion(3)
456
+ u.SetVariant()
457
+
458
+ return u
459
+ }
460
+
461
+ // NewV4 returns random generated UUID.
462
+ func NewV4() UUID {
463
+ u := UUID{}
464
+ safeRandom(u[:])
465
+ u.SetVersion(4)
466
+ u.SetVariant()
467
+
468
+ return u
469
+ }
470
+
471
+ // NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
472
+ func NewV5(ns UUID, name string) UUID {
473
+ u := newFromHash(sha1.New(), ns, name)
474
+ u.SetVersion(5)
475
+ u.SetVariant()
476
+
477
+ return u
478
+ }
479
+
480
+ // Returns UUID based on hashing of namespace UUID and name.
481
+ func newFromHash(h hash.Hash, ns UUID, name string) UUID {
482
+ u := UUID{}
483
+ h.Write(ns[:])
484
+ h.Write([]byte(name))
485
+ copy(u[:], h.Sum(nil))
486
+
487
+ return u
488
+ }