-
Notifications
You must be signed in to change notification settings - Fork 0
/
invoke_shortcut.go
219 lines (179 loc) 路 6.75 KB
/
invoke_shortcut.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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package fo
import (
"context"
"time"
)
type invokeWithOptions struct {
contextTimeout time.Duration
contextTimeoutIsSet bool
}
type callInvokeWithOptionType int
const (
callInvokeWithOptionTypeContextDefault callInvokeWithOptionType = iota
callInvokeWithOptionTypeContextTimeout
)
type CallInvokeWithOption struct {
optionType callInvokeWithOptionType
options func() *invokeWithOptions
}
func WithContextTimeout(timeout time.Duration) CallInvokeWithOption {
return CallInvokeWithOption{
optionType: callInvokeWithOptionTypeContextTimeout,
options: func() *invokeWithOptions {
return &invokeWithOptions{
contextTimeout: timeout,
contextTimeoutIsSet: true,
}
},
}
}
func invokeWithCallOptions[R any](fn func() (R, error), callOpts ...CallInvokeWithOption) (R, error) {
ctx := context.Background()
cancelFuncs := make([]context.CancelFunc, 0, len(callOpts))
for _, callOpt := range callOpts {
options := callOpt.options()
if options.contextTimeoutIsSet {
timeout := options.contextTimeout
if timeout <= 0 {
continue
}
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, timeout)
cancelFuncs = append(cancelFuncs, cancel)
}
}
defer func() {
for _, cancel := range cancelFuncs {
cancel()
}
}()
return invoke(ctx, fn)
}
// InvokeWith0 has the same behavior as InvokeWith but without return value.
func InvokeWith0(fn func() error, opts ...CallInvokeWithOption) error {
_, err := invokeWithCallOptions(func() (any, error) {
return nil, fn()
}, opts...)
return err
}
// InvokeWithTimeout0 has the same behavior as InvokeWithTimeout but without return value.
func InvokeWithTimeout0(fn func() error, timeout time.Duration) error {
return InvokeWith0(fn, WithContextTimeout(timeout))
}
// InvokeWith invokes the callback function with the CallInvokeWithOption passed in and set for
// context.Background() as parent context and enables to control the context of the callback
// function with 1 return value and an error.
func InvokeWith[R1 any](fn func() (R1, error), opts ...CallInvokeWithOption) (R1, error) {
return InvokeWith1(fn, opts...)
}
// InvokeWithTimeout invokes the callback function with the timeout passed in and set for
// context.Background() as parent context with context.WithTimeout(...) and enables to
// control the timeout context of the callback function with 1 return value and an error.
func InvokeWithTimeout[R1 any](fn func() (R1, error), timeout time.Duration) (R1, error) {
return InvokeWithTimeout1(fn, timeout)
}
// InvokeWith1 is an alias of InvokeWith.
func InvokeWith1[R1 any](fn func() (R1, error), opts ...CallInvokeWithOption) (R1, error) {
type result struct {
r1 R1
}
res, err := invokeWithCallOptions(func() (result, error) {
r1, err := fn()
return result{r1: r1}, err
}, opts...)
return res.r1, err
}
// InvokeWithTimeout1 is an alias of InvokeWithTimeout.
func InvokeWithTimeout1[R1 any](fn func() (R1, error), timeout time.Duration) (R1, error) {
return InvokeWith1(fn, WithContextTimeout(timeout))
}
// InvokeWith2 has the same behavior as InvokeWith but with 2 return values.
func InvokeWith2[R1 any, R2 any](fn func() (R1, R2, error), opts ...CallInvokeWithOption) (R1, R2, error) {
type result struct {
r1 R1
r2 R2
}
res, err := invokeWithCallOptions(func() (result, error) {
r1, r2, err := fn()
return result{r1: r1, r2: r2}, err
}, opts...)
return res.r1, res.r2, err
}
// InvokeWithTimeout2 has the same behavior as InvokeWithTimeout but with 2 return values.
func InvokeWithTimeout2[R1 any, R2 any](fn func() (R1, R2, error), timeout time.Duration) (R1, R2, error) {
return InvokeWith2(fn, WithContextTimeout(timeout))
}
// InvokeWith3 has the same behavior as InvokeWith but with 3 return values.
func InvokeWith3[R1 any, R2 any, R3 any](fn func() (R1, R2, R3, error), opts ...CallInvokeWithOption) (R1, R2, R3, error) {
type result struct {
r1 R1
r2 R2
r3 R3
}
res, err := invokeWithCallOptions(func() (result, error) {
r1, r2, r3, err := fn()
return result{r1: r1, r2: r2, r3: r3}, err
}, opts...)
return res.r1, res.r2, res.r3, err
}
// InvokeWithTimeout3 has the same behavior as InvokeWithTimeout but with 3 return values.
func InvokeWithTimeout3[R1 any, R2 any, R3 any](fn func() (R1, R2, R3, error), timeout time.Duration) (R1, R2, R3, error) {
return InvokeWith3(fn, WithContextTimeout(timeout))
}
// InvokeWith4 has the same behavior as InvokeWith but with 4 return values.
func InvokeWith4[R1 any, R2 any, R3 any, R4 any](fn func() (R1, R2, R3, R4, error), opts ...CallInvokeWithOption) (R1, R2, R3, R4, error) {
type result struct {
r1 R1
r2 R2
r3 R3
r4 R4
}
res, err := invokeWithCallOptions(func() (result, error) {
r1, r2, r3, r4, err := fn()
return result{r1: r1, r2: r2, r3: r3, r4: r4}, err
}, opts...)
return res.r1, res.r2, res.r3, res.r4, err
}
// InvokeWithTimeout4 has the same behavior as InvokeWithTimeout but with 4 return values.
func InvokeWithTimeout4[R1 any, R2 any, R3 any, R4 any](fn func() (R1, R2, R3, R4, error), timeout time.Duration) (R1, R2, R3, R4, error) {
return InvokeWith4(fn, WithContextTimeout(timeout))
}
// InvokeWith5 has the same behavior as InvokeWith but with 5 return values.
func InvokeWith5[R1 any, R2 any, R3 any, R4 any, R5 any](fn func() (R1, R2, R3, R4, R5, error), opts ...CallInvokeWithOption) (R1, R2, R3, R4, R5, error) {
type result struct {
r1 R1
r2 R2
r3 R3
r4 R4
r5 R5
}
res, err := invokeWithCallOptions(func() (result, error) {
r1, r2, r3, r4, r5, err := fn()
return result{r1: r1, r2: r2, r3: r3, r4: r4, r5: r5}, err
}, opts...)
return res.r1, res.r2, res.r3, res.r4, res.r5, err
}
// InvokeWithTimeout5 has the same behavior as InvokeWithTimeout but with 5 return values.
func InvokeWithTimeout5[R1 any, R2 any, R3 any, R4 any, R5 any](fn func() (R1, R2, R3, R4, R5, error), timeout time.Duration) (R1, R2, R3, R4, R5, error) {
return InvokeWith5(fn, WithContextTimeout(timeout))
}
// InvokeWith6 has the same behavior as InvokeWith but with 6 return values.
func InvokeWith6[R1 any, R2 any, R3 any, R4 any, R5 any, R6 any](fn func() (R1, R2, R3, R4, R5, R6, error), opts ...CallInvokeWithOption) (R1, R2, R3, R4, R5, R6, error) {
type result struct {
r1 R1
r2 R2
r3 R3
r4 R4
r5 R5
r6 R6
}
res, err := invokeWithCallOptions(func() (result, error) {
r1, r2, r3, r4, r5, r6, err := fn()
return result{r1: r1, r2: r2, r3: r3, r4: r4, r5: r5, r6: r6}, err
}, opts...)
return res.r1, res.r2, res.r3, res.r4, res.r5, res.r6, err
}
// InvokeWithTimeout6 has the same behavior as InvokeWithTimeout but with 6 return values.
func InvokeWithTimeout6[R1 any, R2 any, R3 any, R4 any, R5 any, R6 any](fn func() (R1, R2, R3, R4, R5, R6, error), timeout time.Duration) (R1, R2, R3, R4, R5, R6, error) {
return InvokeWith6(fn, WithContextTimeout(timeout))
}