forked from brianvoe/gofakeit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
faker.go
103 lines (83 loc) · 2.34 KB
/
faker.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
package gofakeit
import (
crand "crypto/rand"
"encoding/binary"
"math/rand"
"sync"
)
// Create global variable to deal with global function call.
var globalFaker *Faker = New(0)
// Faker struct is the primary struct for using localized.
type Faker struct {
Rand *rand.Rand
}
type lockedSource struct {
lk sync.Mutex
src rand.Source64
}
func (r *lockedSource) Int63() (n int64) {
r.lk.Lock()
n = r.src.Int63()
r.lk.Unlock()
return
}
func (r *lockedSource) Uint64() (n uint64) {
r.lk.Lock()
n = r.src.Uint64()
r.lk.Unlock()
return
}
func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.src.Seed(seed)
r.lk.Unlock()
}
type cryptoRand struct {
sync.Mutex
buf []byte
}
func (c *cryptoRand) Seed(seed int64) {}
func (c *cryptoRand) Uint64() uint64 {
// Lock to make reading thread safe
c.Lock()
defer c.Unlock()
crand.Read(c.buf)
return binary.BigEndian.Uint64(c.buf)
}
func (c *cryptoRand) Int63() int64 {
return int64(c.Uint64() & ^uint64(1<<63))
}
// New will utilize math/rand for concurrent random usage.
// Setting seed to 0 will use crypto/rand for the initial seed number.
func New(seed int64) *Faker {
// If passing 0 create crypto safe int64 for initial seed number
if seed == 0 {
binary.Read(crand.Reader, binary.BigEndian, &seed)
}
return &Faker{Rand: rand.New(&lockedSource{src: rand.NewSource(seed).(rand.Source64)})}
}
// NewUnlocked will utilize math/rand for non concurrent safe random usage.
// Setting seed to 0 will use crypto/rand for the initial seed number.
// NewUnlocked is more performant but not safe to run concurrently.
func NewUnlocked(seed int64) *Faker {
// If passing 0 create crypto safe int64 for initial seed number
if seed == 0 {
binary.Read(crand.Reader, binary.BigEndian, &seed)
}
return &Faker{Rand: rand.New(rand.NewSource(seed))}
}
// NewCrypto will utilize crypto/rand for concurrent random usage.
func NewCrypto() *Faker {
return &Faker{Rand: rand.New(&cryptoRand{
buf: make([]byte, 8),
})}
}
// NewCustom will utilize a custom rand.Source64 for concurrent random usage
// See https://golang.org/src/math/rand/rand.go for required interface methods
func NewCustom(source rand.Source64) *Faker {
return &Faker{Rand: rand.New(source)}
}
// SetGlobalFaker will allow you to set what type of faker is globally used. Defailt is math/rand
func SetGlobalFaker(faker *Faker) {
globalFaker = faker
}