Repository navigation
Expand file tree
/
Copy pathrand_source.go
More file actions
84 lines (69 loc) · 1.71 KB
/
Copy pathrand_source.go
File metadata and controls
84 lines (69 loc) · 1.71 KB
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
package dicescript
import (
cryptorand "crypto/rand"
"encoding"
"encoding/binary"
"errors"
"fmt"
"io"
"reflect"
"time"
exprand "golang.org/x/exp/rand"
)
// DiceSource is the minimum capability required by dice rolling.
type DiceSource interface {
Uint64() uint64
}
// StatefulDiceSource is a dice source whose current state can be saved and restored.
type StatefulDiceSource interface {
DiceSource
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
}
var ErrDiceSourceStateUnsupported = errors.New("random source does not support binary state")
var randSource = NewPCGDiceSource(uint64(time.Now().UnixMilli()))
func NewPCGDiceSource(seed uint64) StatefulDiceSource {
src := &exprand.PCGSource{}
src.Seed(seed)
return src
}
func NewPCGDiceSourceFromState(state []byte) (StatefulDiceSource, error) {
src := &exprand.PCGSource{}
err := src.UnmarshalBinary(state)
return src, err
}
func NewCryptoDiceSource() DiceSource {
return &cryptoDiceSource{reader: cryptorand.Reader}
}
type cryptoDiceSource struct {
reader io.Reader
}
func (src *cryptoDiceSource) Uint64() uint64 {
reader := src.reader
if reader == nil {
reader = cryptorand.Reader
}
var data [8]byte
if _, err := io.ReadFull(reader, data[:]); err != nil {
panic(fmt.Errorf("crypto dice source failed: %w", err))
}
return binary.BigEndian.Uint64(data[:])
}
func normalizeDiceSource(src DiceSource) DiceSource {
if isNilDiceSource(src) {
return randSource
}
return src
}
func isNilDiceSource(src DiceSource) bool {
if src == nil {
return true
}
v := reflect.ValueOf(src)
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
return v.IsNil()
default:
return false
}
}