-
Notifications
You must be signed in to change notification settings - Fork 145
/
args.go
113 lines (82 loc) · 2.98 KB
/
args.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
package worker
import (
"context"
"fmt"
"reflect"
)
func decodeArgsToInterface(fnType reflect.Type) (results interface{}, err error) {
numIn := fnType.NumIn()
if numIn != 1 && numIn != 2 {
return nil, fmt.Errorf("fn must have exactly one or two arguments")
}
firstArg := fnType.In(0)
if firstArg.Kind() != reflect.Interface || !firstArg.Implements(reflect.TypeOf((*context.Context)(nil)).Elem()) {
return nil, fmt.Errorf("first argument must implement context.Context")
}
// second argument should be a pointer to a struct
if numIn == 2 {
secondArg := fnType.In(1)
if secondArg.Kind() != reflect.Ptr {
return nil, fmt.Errorf("second argument must be a pointer to a struct")
}
secondArgElem := secondArg.Elem()
if secondArgElem.Kind() != reflect.Struct {
return nil, fmt.Errorf("second argument must be a pointer to a struct")
}
return reflect.New(secondArgElem).Interface(), nil
}
return nil, nil
}
func decodeFnArgTypes(fnType reflect.Type) (result []reflect.Type, err error) {
if fnType.Kind() != reflect.Func {
return nil, fmt.Errorf("method must be a function")
}
numIn := fnType.NumIn()
// if not a function with one or two arguments, return an error
if numIn != 1 && numIn != 2 {
return nil, fmt.Errorf("method must have one or two arguments")
}
// if first argument is not a context, return error
firstArg := fnType.In(0)
if firstArg.Kind() != reflect.Interface || !firstArg.Implements(reflect.TypeOf((*context.Context)(nil)).Elem()) {
return nil, fmt.Errorf("first argument must be context.Context")
}
res := []reflect.Type{firstArg}
if numIn == 2 {
// if second argument is not a pointer to a struct, return error
secondArg := fnType.In(1)
if secondArg.Kind() != reflect.Ptr {
return nil, fmt.Errorf("second argument must be a pointer to a struct")
}
secondArgElem := secondArg.Elem()
if secondArgElem.Kind() != reflect.Struct {
return nil, fmt.Errorf("second argument must be a pointer to a struct")
}
res = append(res, secondArg)
}
return res, nil
}
func decodeFnReturnTypes(fnType reflect.Type) (result []reflect.Type, err error) {
if fnType.NumOut() > 2 {
return nil, fmt.Errorf("fn cannot have more than 2 return values")
}
firstOut := fnType.Out(0)
// if there are two args, the first one should be a pointer to a struct
if fnType.NumOut() == 2 {
if firstOut.Kind() != reflect.Ptr {
return nil, fmt.Errorf("first argument must be a pointer to a struct when there are two return values")
}
firstOutElem := firstOut.Elem()
if firstOutElem.Kind() != reflect.Struct {
return nil, fmt.Errorf("first argument must be a pointer to a struct when there are two return values")
}
}
lastOut := fnType.Out(fnType.NumOut() - 1)
if lastOut.Kind() != reflect.Interface || !lastOut.Implements(reflect.TypeOf((*error)(nil)).Elem()) {
return nil, fmt.Errorf("last return value must be error")
}
if fnType.NumOut() == 1 {
return []reflect.Type{firstOut}, nil
}
return []reflect.Type{firstOut, lastOut}, nil
}