-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerator.go
More file actions
82 lines (69 loc) · 1.63 KB
/
generator.go
File metadata and controls
82 lines (69 loc) · 1.63 KB
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
package guid
import (
"crypto/rand"
"io"
"sync"
"sync/atomic"
"time"
)
func init() {
globalGen.Store(Generator(&stdGenerator{
Random: rand.Reader,
Now: func() time.Time {
return time.Now().UTC()
},
Fingerprint: defaultFingerprint(),
}))
}
// Generator defines the contract for generating GUIDs
type Generator interface {
Generate() (GUID, error)
}
// stdGenerator generates GUIDs
type stdGenerator struct {
Fingerprint int32
Random io.Reader
Now func() time.Time
Counter int32
mu sync.Mutex
}
var (
// globalGenerator is stored in an atomic.Value for safe concurrent access.
// nolint: gochecknoglobals
globalGen atomic.Value
setOnce sync.Once
)
// SetGlobalGenerator allows for the manual assignment of the GUID generator.
// The main usefulness of this function is primarily for testing, but
// this function can also be used to inject custom time and randomness
// providers.
// Note that this function can be called only once per runtime.
// Subsequent calls are no-ops.
func SetGlobalGenerator(g Generator) {
setOnce.Do(func() {
globalGen.Store(g)
})
}
func (g *stdGenerator) randomInt64() (int64, error) {
return randomInt64(g.Random)
}
// Generate will create a new GUID.
func (g *stdGenerator) Generate() (GUID, error) {
g.mu.Lock()
counter := g.Counter
g.Counter++
if g.Counter >= maxInt {
g.Counter = 0
}
g.mu.Unlock()
r, err := g.randomInt64()
if err != nil {
return GUID{}, err
}
v := (GUID{}).SetTime(g.Now()).SetCounter(counter).SetFingerprint(g.Fingerprint).SetRandom(r)
// set prefix bytes
pfx := globalPrefix.Load().([2]byte)
v[0] = pfx[0]
v[1] = pfx[1]
return v, nil
}