rand.go

 1package retry
 2
 3import (
 4	"math/rand"
 5	"sync"
 6)
 7
 8type lockedSource struct {
 9	src *rand.Rand
10	mu  sync.Mutex
11}
12
13var _ rand.Source64 = (*lockedSource)(nil)
14
15func newLockedRandom(seed int64) *lockedSource {
16	return &lockedSource{src: rand.New(rand.NewSource(seed))}
17}
18
19// Int63 mimics math/rand.(*Rand).Int63 with mutex locked.
20func (r *lockedSource) Int63() int64 {
21	r.mu.Lock()
22	defer r.mu.Unlock()
23	return r.src.Int63()
24}
25
26// Seed mimics math/rand.(*Rand).Seed with mutex locked.
27func (r *lockedSource) Seed(seed int64) {
28	r.mu.Lock()
29	defer r.mu.Unlock()
30	r.src.Seed(seed)
31}
32
33// Uint64 mimics math/rand.(*Rand).Uint64 with mutex locked.
34func (r *lockedSource) Uint64() uint64 {
35	r.mu.Lock()
36	defer r.mu.Unlock()
37	return r.src.Uint64()
38}
39
40// Int63n mimics math/rand.(*Rand).Int63n with mutex locked.
41func (r *lockedSource) Int63n(n int64) int64 {
42	if n <= 0 {
43		panic("invalid argument to Int63n")
44	}
45	if n&(n-1) == 0 { // n is power of two, can mask
46		return r.Int63() & (n - 1)
47	}
48	max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
49	v := r.Int63()
50	for v > max {
51		v = r.Int63()
52	}
53	return v % n
54}