-
Notifications
You must be signed in to change notification settings - Fork 0
/
cast_duration.go
145 lines (124 loc) · 3.92 KB
/
cast_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
142
143
144
145
package pick
import (
"encoding/json"
"fmt"
"math"
"time"
)
type DurationCastNumberFormat int
const (
DurationNumberNanoseconds DurationCastNumberFormat = iota // default value
DurationNumberMilliseconds
DurationNumberMicroseconds
DurationNumberSeconds
DurationNumberMinutes
DurationNumberHours
)
type DurationCastConfig struct {
DurationCastNumberFormat DurationCastNumberFormat
}
func (c DefaultCaster) AsDuration(input any) (time.Duration, error) {
return c.AsDurationWithConfig(DurationCastConfig{}, input)
}
func (c DefaultCaster) AsDurationWithConfig(config DurationCastConfig, input any) (time.Duration, error) {
switch origin := input.(type) {
case int:
return c.durationFromInt64(config, int64(origin))
case int8:
return c.durationFromInt64(config, int64(origin))
case int16:
return c.durationFromInt64(config, int64(origin))
case int32:
return c.durationFromInt64(config, int64(origin))
case int64:
return c.durationFromInt64(config, origin)
case uint:
return c.AsDurationWithConfig(config, uint64(origin))
case uint8:
return c.AsDurationWithConfig(config, uint64(origin))
case uint16:
return c.AsDurationWithConfig(config, uint64(origin))
case uint32:
return c.AsDurationWithConfig(config, uint64(origin))
case uint64:
asInt64, err := c.AsInt64(origin)
if err != nil {
d, _ := c.AsDurationWithConfig(config, asInt64) // best effort
return d, err
}
return c.AsDurationWithConfig(config, asInt64)
case float32:
return c.AsDurationWithConfig(config, float64(origin))
case float64:
casted, err := float64ToInt64(origin)
d, _ := c.AsDurationWithConfig(config, casted) // best effort
return d, err
case string:
d, err := time.ParseDuration(origin)
if err != nil {
return 0, newCastError(err, origin)
}
return d, nil
case json.Number:
n, err := origin.Int64()
if err != nil {
return time.Duration(0), newCastError(err, fmt.Errorf("error converting json number to number: %w", err))
}
return c.AsDurationWithConfig(config, n)
case []byte:
return c.AsDurationWithConfig(config, string(origin))
case bool:
return time.Duration(0), newCastError(ErrCastInvalidType, input)
case nil:
return time.Duration(0), nil
case time.Duration:
return origin, nil
default:
// try to cast to basic (in case input is ~basic)
if basic, err := tryCastToBasicType(input); err == nil {
return c.AsDurationWithConfig(config, basic)
}
return tryReflectConvert[time.Duration](input)
}
}
func (c DefaultCaster) durationFromInt64(config DurationCastConfig, origin int64) (time.Duration, error) {
limitCheck := func(d time.Duration) error {
if origin >= (math.MinInt64/int64(d)) && origin <= (math.MaxInt64/int64(d)) {
return nil
}
return newCastError(ErrCastOverFlow, origin)
}
var dr time.Duration
var err error
switch config.DurationCastNumberFormat {
case DurationNumberSeconds:
dr = time.Duration(origin) * time.Second
err = limitCheck(time.Second)
case DurationNumberMilliseconds:
dr = time.Duration(origin) * time.Millisecond
err = limitCheck(time.Millisecond)
case DurationNumberMicroseconds:
dr = time.Duration(origin) * time.Microsecond
err = limitCheck(time.Microsecond)
case DurationNumberNanoseconds:
dr = time.Duration(origin) * time.Nanosecond
err = limitCheck(time.Nanosecond)
case DurationNumberMinutes:
dr = time.Duration(origin) * time.Minute
err = limitCheck(time.Minute)
case DurationNumberHours:
dr = time.Duration(origin) * time.Hour
err = limitCheck(time.Hour)
default:
return dr, newCastError(ErrCastInvalidType, origin)
}
return dr, err
}
func (c DefaultCaster) AsDurationSlice(input any) ([]time.Duration, error) {
return c.AsDurationSliceWithConfig(DurationCastConfig{}, input)
}
func (c DefaultCaster) AsDurationSliceWithConfig(config DurationCastConfig, input any) ([]time.Duration, error) {
return mapTo(input, func(item any, _ iterationOpMeta) (time.Duration, error) {
return c.AsDurationWithConfig(config, item)
})
}