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}