rand.go 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. package core
  2. import (
  3. "math/big"
  4. "math/rand"
  5. cryptorand "crypto/rand"
  6. )
  7. func Rand(h RuntimeHandle, k func(*rand.Rand)(Object)) Observable {
  8. return Observable(func(pub DataPublisher) {
  9. randWorker <- func() {
  10. var r = rand.New(randSource { h })
  11. pub.AsyncReturn(k(r))
  12. }
  13. })
  14. }
  15. func RandBigInt(supremum *big.Int, h RuntimeHandle) Observable {
  16. if supremum.Sign() <= 0 {
  17. Crash(h, InvalidArgument, "non-positive random supremum")
  18. }
  19. return Observable(func(pub DataPublisher) {
  20. randWorker <- func() {
  21. pub.AsyncReturn(ObjIntFromBigInt(randBigInt(supremum, h)))
  22. }
  23. })
  24. }
  25. var randWorker = make(chan func(), 256)
  26. var _ = (func() struct{} {
  27. go (func() {
  28. for k := range randWorker {
  29. k()
  30. }
  31. })()
  32. return struct{}{}
  33. })()
  34. type randSource struct {
  35. h RuntimeHandle
  36. }
  37. func (src randSource) Seed(_ int64) {
  38. panic("dummy method")
  39. }
  40. func (src randSource) Int63() int64 {
  41. var n big.Int
  42. return randBigInt(n.Lsh(big.NewInt(1), 63), src.h).Int64()
  43. }
  44. func (src randSource) Uint64() uint64 {
  45. var n big.Int
  46. return randBigInt(n.Lsh(big.NewInt(1), 64), src.h).Uint64()
  47. }
  48. func randBigInt(supremum *big.Int, h RuntimeHandle) *big.Int {
  49. if supremum.Sign() <= 0 {
  50. panic("invalid argument")
  51. }
  52. var n, err = cryptorand.Int(cryptorand.Reader, supremum)
  53. if err != nil {
  54. Crash(h, FailedToGenerateRandomNumber, err.Error())
  55. }
  56. return n
  57. }