github.com/brahmaroutu/docker@v1.2.1-0.20160809185609-eb28dde01f16/pkg/random/random.go (about)

     1  package random
     2  
     3  import (
     4  	cryptorand "crypto/rand"
     5  	"io"
     6  	"math"
     7  	"math/big"
     8  	"math/rand"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  // Rand is a global *rand.Rand instance, which initialized with NewSource() source.
    14  var Rand = rand.New(NewSource())
    15  
    16  // Reader is a global, shared instance of a pseudorandom bytes generator.
    17  // It doesn't consume entropy.
    18  var Reader io.Reader = &reader{rnd: Rand}
    19  
    20  // copypaste from standard math/rand
    21  type lockedSource struct {
    22  	lk  sync.Mutex
    23  	src rand.Source
    24  }
    25  
    26  func (r *lockedSource) Int63() (n int64) {
    27  	r.lk.Lock()
    28  	n = r.src.Int63()
    29  	r.lk.Unlock()
    30  	return
    31  }
    32  
    33  func (r *lockedSource) Seed(seed int64) {
    34  	r.lk.Lock()
    35  	r.src.Seed(seed)
    36  	r.lk.Unlock()
    37  }
    38  
    39  // NewSource returns math/rand.Source safe for concurrent use and initialized
    40  // with current unix-nano timestamp
    41  func NewSource() rand.Source {
    42  	var seed int64
    43  	if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil {
    44  		// This should not happen, but worst-case fallback to time-based seed.
    45  		seed = time.Now().UnixNano()
    46  	} else {
    47  		seed = cryptoseed.Int64()
    48  	}
    49  	return &lockedSource{
    50  		src: rand.NewSource(seed),
    51  	}
    52  }
    53  
    54  type reader struct {
    55  	rnd *rand.Rand
    56  }
    57  
    58  func (r *reader) Read(b []byte) (int, error) {
    59  	i := 0
    60  	for {
    61  		val := r.rnd.Int63()
    62  		for val > 0 {
    63  			b[i] = byte(val)
    64  			i++
    65  			if i == len(b) {
    66  				return i, nil
    67  			}
    68  			val >>= 8
    69  		}
    70  	}
    71  }