-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwhile.go
80 lines (68 loc) · 1.84 KB
/
while.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
package async
import (
"context"
"reflect"
)
// While repeatedly calls the function while the test function returns true. A valid test function
// must match the following requirements.
//
// - The first return value of the test function must be a boolean value.
// - It should have no parameters or accept a context only.
//
// c := 0
// async.While(func() bool {
// return c == 5
// }, func() {
// c++
// })
func While(testFn, fn AsyncFn) ([]any, error) {
return while(context.Background(), testFn, fn)
}
// WhileWithContext repeatedly calls the function with the specified context while the test
// function returns true.
func WhileWithContext(ctx context.Context, testFn, fn AsyncFn) ([]any, error) {
return while(ctx, testFn, fn)
}
// while repeatedly calls the function while the test function returns true.
func while(parent context.Context, testFn, fn AsyncFn) ([]any, error) {
validateWhileFuncs(testFn, fn)
ctx := getContext(parent)
var out []any
var err error
for {
testOut, testErr := invokeAsyncFn(testFn, ctx, nil)
if testErr != nil {
return out, testErr
}
isContinue := testOut[0].(bool)
if !isContinue {
return out, nil
}
out, err = invokeAsyncFn(fn, ctx, nil)
if err != nil {
break
}
}
return out, err
}
// validateWhileFuncs validates the test function and the execution function for while.
func validateWhileFuncs(testFn, fn AsyncFn) {
if testFn == nil || fn == nil {
panic(ErrNotFunction)
}
tft := reflect.TypeOf(testFn) // reflect.Type of the test function
if tft.Kind() != reflect.Func || reflect.TypeOf(fn).Kind() != reflect.Func {
panic(ErrNotFunction)
}
if tft.NumOut() <= 0 || tft.Out(0).Kind() != reflect.Bool {
panic(ErrInvalidTestFunc)
}
numIn := tft.NumIn()
isTakeContext, _ := isFuncTakesContexts(tft)
if isTakeContext {
numIn--
}
if numIn != 0 {
panic(ErrInvalidTestFunc)
}
}