/
duration.go
141 lines (121 loc) · 3 KB
/
duration.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
package duration
import (
"encoding/json"
"fmt"
"strings"
"time"
uberatomic "go.uber.org/atomic"
"github.com/cybriq/p9/pkg/opts/meta"
"github.com/cybriq/p9/pkg/opts/opt"
"github.com/cybriq/p9/pkg/opts/sanitizers"
)
// Opt stores an time.Duration configuration value
type Opt struct {
meta.Data
hook []Hook
clamp func(input time.Duration) (result time.Duration)
Min, Max time.Duration
Value *uberatomic.Duration
Def time.Duration
}
type Hook func(d time.Duration) error
// New creates a new Opt with a given default value set
func New(
m meta.Data, def time.Duration, min, max time.Duration, hook ...Hook,
) *Opt {
return &Opt{
Value: uberatomic.NewDuration(def),
Data: m,
Def: def,
Min: min,
Max: max,
hook: hook,
clamp: sanitizers.ClampDuration(min, max),
}
}
// SetName sets the name for the generator
func (x *Opt) SetName(name string) {
x.Data.Option = strings.ToLower(name)
x.Data.Name = name
}
// Type returns the receiver wrapped in an interface for identifying its type
func (x *Opt) Type() interface{} {
return x
}
// GetMetadata returns the metadata of the opt type
func (x *Opt) GetMetadata() *meta.Data {
return &x.Data
}
// ReadInput sets the value from a string
func (x *Opt) ReadInput(input string) (o opt.Option, e error) {
if input == "" {
e = fmt.Errorf(
"duration opt %s %v may not be empty", x.Name(),
x.Data.Aliases,
)
return
}
if strings.HasPrefix(input, "=") {
// the following removes leading and trailing '='
input = strings.Join(strings.Split(input, "=")[1:], "=")
}
var v time.Duration
if v, e = time.ParseDuration(input); E.Chk(e) {
return
}
if e = x.Set(v); E.Chk(e) {
}
return
}
// LoadInput sets the value from a string (this is the same as the above but differs for Strings)
func (x *Opt) LoadInput(input string) (o opt.Option, e error) {
return x.ReadInput(input)
}
// Name returns the name of the opt
func (x *Opt) Name() string {
return x.Data.Option
}
// AddHooks appends callback hooks to be run when the value is changed
func (x *Opt) AddHooks(hook ...Hook) {
x.hook = append(x.hook, hook...)
}
// SetHooks sets a new slice of hooks
func (x *Opt) SetHooks(hook ...Hook) {
x.hook = hook
}
// V returns the value stored
func (x *Opt) V() time.Duration {
return x.Value.Load()
}
func (x *Opt) runHooks(d time.Duration) (e error) {
for i := range x.hook {
if e = x.hook[i](d); E.Chk(e) {
break
}
}
return
}
// Set the value stored
func (x *Opt) Set(d time.Duration) (e error) {
d = x.clamp(d)
if e = x.runHooks(d); !E.Chk(e) {
x.Value.Store(d)
}
return
}
// String returns a string representation of the value
func (x *Opt) String() string {
return fmt.Sprintf("%s: %v", x.Data.Option, x.V())
}
// MarshalJSON returns the json representation
func (x *Opt) MarshalJSON() (b []byte, e error) {
v := x.Value.Load()
return json.Marshal(&v)
}
// UnmarshalJSON decodes a JSON representation
func (x *Opt) UnmarshalJSON(data []byte) (e error) {
v := x.Value.Load()
e = json.Unmarshal(data, &v)
e = x.Set(v)
return
}