-
Notifications
You must be signed in to change notification settings - Fork 2
/
option.go
204 lines (179 loc) · 5.93 KB
/
option.go
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package reflecthelper
import (
"reflect"
"github.com/Popog/deepcopy"
"github.com/mitchellh/mapstructure"
)
// Option is a collection of argument options used in this package.
type Option struct {
// Affected by Default() method
FloatPrecision int
FloatFormat byte
BitSize int
ComplexBitSize int
BaseSystem int
TimeLayouts []string
hasCheckExtractValid bool // private field
DecoderConfig *mapstructure.DecoderConfig
// Not affected by Default() method
IgnoreError bool
RecoverPanic bool
BlockChannelIteration bool
ConcurrentMode bool
FnAssigner FuncAssigner
ContinueAssignOnError bool
}
// FuncAssigner is a custom function to assign from the val of reflect.Value to the assigner of reflect.Value.
// This function will be passed with one more argument, that is option.
// This function will return the error from inside the function.
type FuncAssigner func(assigner reflect.Value, val reflect.Value, o *Option) (err error)
// FuncOption is a function option to set the Option for function arguments.
type FuncOption func(o *Option)
// WithFloatConfiguration assign the float configuration to the option.
func WithFloatConfiguration(floatPrec int, floatFormat byte) FuncOption {
return func(o *Option) {
o.FloatPrecision = floatPrec
o.FloatFormat = floatFormat
}
}
// WithBitSize sets the bit size of integer and complex.
func WithBitSize(intFloat, complex int) FuncOption {
return func(o *Option) {
o.BitSize = intFloat
o.ComplexBitSize = complex
}
}
// WithBaseSystem sets the default base system of Option.
func WithBaseSystem(base int) FuncOption {
return func(o *Option) {
o.BaseSystem = base
}
}
// WithTimeLayouts sets the time layouts for the Option.
func WithTimeLayouts(timeLayouts ...string) FuncOption {
return func(o *Option) {
o.TimeLayouts = timeLayouts
}
}
// WithIgnoreError toggles for ignoring error in the struct, slice, array, and map iteration.
// The default behavior for this package is false.
func WithIgnoreError(input bool) FuncOption {
return func(o *Option) {
o.IgnoreError = input
}
}
// WithPanicRecoverer toggles the panic recoverer in all of the packages' functions.
// The default behavior for this package is false.
func WithPanicRecoverer(input bool) FuncOption {
return func(o *Option) {
o.RecoverPanic = input
}
}
// WithBlockChannel toggles the blocking operation of receive from reflect.Value with kind reflect.Chan.
// WithBlockChannel will use the Recv() method instead of TryRecv().
// The default behavior for this package is false.
func WithBlockChannel(input bool) FuncOption {
return func(o *Option) {
o.BlockChannelIteration = input
}
}
// WithConcurrency toggles the concurrency mode in this package, especially in the iteration.
// This toggles to iterate array, slice, map, or struct elements in concurrent mode.
// The default behavior for this package is false.
func WithConcurrency(input bool) FuncOption {
return func(o *Option) {
o.ConcurrentMode = input
}
}
// WithDecoderConfig assigns the mapstructure decoder config for map assignment.
// DecoderConfig will be assigned Result (output) in the process of assignment.
func WithDecoderConfig(cfg *mapstructure.DecoderConfig) FuncOption {
return func(o *Option) {
o.DecoderConfig = cfg
}
}
// WithCustomAssigner sets the custom function of assigning value to the Option.
// This function also accepts the continueAssignOnErr param to make sure that
// the assignment inside this package still continues even the custom assigner
// returns error.
// The custom assigner is only needed if the assignment process is complex.
func WithCustomAssigner(fn FuncAssigner, continueAssignOnErr bool) FuncOption {
return func(o *Option) {
o.ContinueAssignOnError = continueAssignOnErr
o.FnAssigner = fn
}
}
// NewDefaultOption initialize the new default option.
func NewDefaultOption() *Option {
return new(Option).Default()
}
// NewOption initialize the new empty option.
func NewOption() *Option {
return new(Option)
}
// Assign assigns the functional options to the Option.
func (o *Option) Assign(fnOpts ...FuncOption) *Option {
for _, fnOpt := range fnOpts {
fnOpt(o)
}
return o.Default()
}
// Clone clones the current option to the new memory address.
func (o *Option) Clone() *Option {
newOpt := deepcopy.DeepCopy(*o).(Option)
newOpt.hasCheckExtractValid = o.hasCheckExtractValid
return &newOpt
}
func (o *Option) isValidFloatFormat() bool {
switch o.FloatFormat {
case 'b', 'e', 'E', 'f', 'g', 'G', 'x', 'X':
return true
}
return false
}
const (
// DefaultFloatPrecision specifies the default precision used in this package.
// This is the default maximum precision.
DefaultFloatPrecision = -1
// DefaultBitSize is the default bit size used for the conversion in this package.
DefaultBitSize = 64
// DefaultComplexBitSize is the default bit size for the complex128 type.
DefaultComplexBitSize = 128
// DefaultBaseSystem is the default base system used for decimal in this package.
DefaultBaseSystem = 10
// DefaultFloatFormat is the default format used for formmating float value in string
DefaultFloatFormat = 'g'
)
// Default sets the default value of all variables in Option.
func (o *Option) Default() *Option {
if o.FloatPrecision <= 0 {
o.FloatPrecision = DefaultFloatPrecision
}
if o.BitSize != 32 && o.BitSize != 64 {
o.BitSize = DefaultBitSize
}
if o.ComplexBitSize != 64 && o.ComplexBitSize != 128 {
o.ComplexBitSize = DefaultComplexBitSize
}
if o.BaseSystem <= 0 {
o.BaseSystem = DefaultBaseSystem
}
if !o.isValidFloatFormat() {
o.FloatFormat = DefaultFloatFormat
}
if o.TimeLayouts == nil {
o.TimeLayouts = make([]string, 0)
}
if o.DecoderConfig == nil {
o.DecoderConfig = new(mapstructure.DecoderConfig)
}
return o.resetCheck()
}
func (o *Option) resetCheck() *Option {
o.hasCheckExtractValid = false
return o
}
func (o *Option) toggleOnCheckExtractValid() *Option {
o.hasCheckExtractValid = true
return o
}