-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathreflect.go
96 lines (84 loc) · 2.22 KB
/
reflect.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
package alice
import (
"fmt"
"reflect"
)
const _Tag = "alice"
const _IsModuleMethodName = "IsModule"
// reflectedModule contains the instance and dependency information of a Module. The information is extracted
// using reflection.
type reflectedModule struct {
m Module
name string
instances []*instanceMethod
namedDepends []*namedField
typedDepends []*typedField
}
type instanceMethod struct {
name string
tp reflect.Type
method reflect.Value
}
type namedField struct {
name string
field reflect.Value
}
type typedField struct {
tp reflect.Type
field reflect.Value
}
// reflectModule creates a reflectedModule from a Module. It returns error if the Module is not properly defined.
func reflectModule(m Module) (*reflectedModule, error) {
v := reflect.ValueOf(m)
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
return nil, fmt.Errorf("module %s is not a pointer of struct", v.String())
}
// get instances
ptrT := v.Type()
var instances []*instanceMethod
for i := 0; i < ptrT.NumMethod(); i++ {
method := ptrT.Method(i)
if method.Name == _IsModuleMethodName {
continue
}
if method.Type.NumIn() != 1 || method.Type.NumOut() != 1 { // receiver is the first parameter
return nil, fmt.Errorf("method %s.%s doesn't have 0 parameter and 1 return value",
v.Elem().Type().Name(), method.Name)
}
instances = append(instances, &instanceMethod{
name: method.Name,
tp: method.Type.Out(0),
method: v.MethodByName(method.Name),
})
}
// get dependencies
t := v.Elem().Type()
var namedDepends []*namedField
var typedDepends []*typedField
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if field.Anonymous {
continue
}
if dependName, exists := field.Tag.Lookup(_Tag); exists {
if dependName != "" {
namedDepends = append(namedDepends, &namedField{
name: dependName,
field: v.Elem().FieldByName(field.Name),
})
} else {
typedDepends = append(typedDepends, &typedField{
tp: field.Type,
field: v.Elem().FieldByName(field.Name),
})
}
}
}
return &reflectedModule{
m: m,
name: t.Name(),
instances: instances,
namedDepends: namedDepends,
typedDepends: typedDepends,
}, nil
}