-
Notifications
You must be signed in to change notification settings - Fork 15
/
invoker_lazy.go
109 lines (94 loc) · 2.31 KB
/
invoker_lazy.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
package dingo
import (
"fmt"
"reflect"
)
/*
A less generic Invoker that can handle pointer with different level.
This Invoker can only work with GobMarshaller and JsonSafeMarshaller.
*/
type LazyInvoker struct{}
func (vk *LazyInvoker) Call(f interface{}, param []interface{}) ([]interface{}, error) {
var (
funcT = reflect.TypeOf(f)
v reflect.Value
t reflect.Type
)
// make sure parameter matched
if len(param) != funcT.NumIn() {
return nil, fmt.Errorf("Parameter Count mismatch: %v %v", len(param), funcT.NumIn())
}
// compose input parameter
var in = make([]reflect.Value, funcT.NumIn())
for i := 0; i < funcT.NumIn(); i++ {
v = reflect.ValueOf(param[i])
// special handle for pointer
if t = funcT.In(i); t.Kind() == reflect.Ptr {
in[i] = *vk.toPointer(t, v)
} else {
in[i] = v
}
}
// invoke the function
ret := reflect.ValueOf(f).Call(in)
out := make([]interface{}, 0, len(ret))
for k, v := range ret {
if v.CanInterface() {
out = append(out, v.Interface())
} else {
return nil, fmt.Errorf("Unable to convert to interface{} for %d, %v", k, v)
}
}
return out, nil
}
func (vk *LazyInvoker) Return(f interface{}, returns []interface{}) ([]interface{}, error) {
var (
funcT = reflect.TypeOf(f)
t reflect.Type
r reflect.Value
)
if len(returns) != funcT.NumOut() {
return nil, fmt.Errorf("Parameter Count mismatch: %v %v", len(returns), funcT.NumOut())
}
for k, v := range returns {
t = funcT.Out(k)
// special handle for pointer
if t.Kind() == reflect.Ptr {
if r = *vk.toPointer(t, reflect.ValueOf(v)); r.CanInterface() {
returns[k] = r.Interface()
} else {
return nil, fmt.Errorf("can't interface of %v from %d:%v", r, k, v)
}
}
}
return returns, nil
}
func (vk *LazyInvoker) toPointer(t reflect.Type, v reflect.Value) *reflect.Value {
if t.Kind() != reflect.Ptr {
return &v
}
vO := reflect.New(t)
rO := vO.Elem()
if v.IsValid() {
for t.Kind() == reflect.Ptr {
if t = t.Elem(); t.Kind() == reflect.Ptr {
vO.Elem().Set(reflect.New(t))
vO = vO.Elem()
} else {
if v.Kind() != reflect.Ptr {
vO.Elem().Set(reflect.New(t))
vO = vO.Elem()
}
}
}
for v.Kind() == reflect.Ptr {
if v.Elem().Kind() == reflect.Ptr {
v = v.Elem()
} else {
break
}
}
vO.Elem().Set(v)
}
return &rO
}