-
Notifications
You must be signed in to change notification settings - Fork 0
/
uuid4.go
107 lines (88 loc) · 2.95 KB
/
uuid4.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
// Package uuid4 provides generation of version 4 Universally Unique IDentifiers (UUIDs), compliant with RFC 4122 (https://tools.ietf.org/html/rfc4122).
package uuid4
import (
"crypto/rand"
"fmt"
)
// New returns a new version 4 UUID in string representation.
//
// Example: "48c51d77-69be-a444-c12f-984f2db2c269"
//
// source: https://tools.ietf.org/html/rfc4122#section-3
func New() (string, error) {
uuid, err := NewBytes()
if err != nil {
return "", err
}
// 36-character uuid string
s := make([]byte, 36)
i := 0 // string index
for _, v := range uuid {
// Insert hyphens at appropriate indices
if i == 8 || i == 13 || i == 18 || i == 23 {
s[i] = byte(sep)
i++
}
// Convert byte to two chars
s[i] = hex[v>>4]
s[i+1] = hex[v&0x0f]
i += 2
}
return string(s), nil
}
// NewBytes returns a new version 4 UUID as a byte slice.
//
// source: https://tools.ietf.org/html/rfc4122#section-4.4
func NewBytes() ([]byte, error) {
uuid := make([]byte, uuidBytes)
// First we set all the bits to random values.
_, err := rand.Read(uuid)
if err != nil {
fmt.Println("error:", err)
return nil, err
}
// Then we apply two bitwise logical ops that, when applied in the correct
// sequence, will as a whole accomplish the following:
// a) set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively;
uuid[IdxClkSeqHiRes] &= 0xbf
uuid[IdxClkSeqHiRes] |= 0x80
// b) set the four most significant bits (bits 12 through 15) of the
// time_hi_and_version field to the 4-bit version number from
// Section 4.1.3 (the 4-bit version number for v4 is: 0100)
uuid[IdxTimeHiAndVersion] &= 0x0f
uuid[IdxTimeHiAndVersion] |= 0x40
return uuid, nil
}
// Byte indices for the location of fields within the uuid, and their byte length.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | time_low |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | time_mid | time_hi_and_version |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |clk_seq_hi_res | clk_seq_low | node (0-1) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | node (2-5) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// source: https://tools.ietf.org/html/rfc4122#section-4.1.2
const (
IdxTimeLow = 0
BytesTimeLow = 4
IdxTimeMid = 4
BytesTimeMid = 2
IdxTimeHiAndVersion = 6
BytesTimeHiAndVersion = 2
IdxClkSeqHiRes = 8
BytesClkSeqHiRes = 1
IdxClkSeqLow = 9
BytesClkSeqLow = 1
IdxNode = 10
BytesNode = 6
)
const uuidBytes = 16 // uuid is 128 bits
const hex = "0123456789abcdef"
const sep = '-'