-
Notifications
You must be signed in to change notification settings - Fork 0
/
dep_node.go
120 lines (96 loc) · 2.27 KB
/
dep_node.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
package di
import (
"fmt"
"reflect"
"strings"
)
type depNode struct {
Constructor reflect.Value
DependsOn []reflect.Type
Edges map[reflect.Type]*depNode
Lifetime Lifetime
ReturnsErr bool
Type reflect.Type
TypeName string
}
func newDepNode(constructor reflect.Value, lifetime Lifetime, depMap map[reflect.Type]*depNode) *depNode {
var node depNode
node.Constructor = constructor
node.Lifetime = lifetime
constructorType := constructor.Type()
node.Type = constructorType.Out(0)
node.TypeName = node.Type.String()
if constructorType.NumOut() == 2 {
node.ReturnsErr = true
}
numIn := constructorType.NumIn()
deps := make([]reflect.Type, numIn)
edges := make(map[reflect.Type]*depNode, numIn)
for index := range deps {
inType := constructorType.In(index)
deps[index] = inType
edgeNode, hasNode := depMap[inType]
if hasNode {
edges[inType] = edgeNode
}
}
node.DependsOn = deps
node.Edges = edges
return &node
}
func (dn *depNode) AddEdge(node *depNode) {
for _, dependsOn := range dn.DependsOn {
if dependsOn == node.Type {
dn.Edges[dependsOn] = node
return
}
}
}
func (dn *depNode) CheckForCycle(seen []*depNode, checked map[*depNode]bool) error {
hasSeen := func(dn2 *depNode) bool {
for _, node := range seen {
if node == dn2 {
return true
}
}
return false
}
for _, node := range dn.Edges {
if checked[node] {
continue
}
if hasSeen(node) {
// print and return err
path := make([]string, len(seen), len(seen)+1)
for index, seenNode := range seen {
path[index] = seenNode.Type.String()
}
path = append(path, node.Type.String())
pathStr := strings.Join(path, "->")
return fmt.Errorf("di: circular dependency detected: %v", pathStr)
}
seenCopy := make([]*depNode, len(seen), len(seen)+1)
copy(seenCopy, seen)
seenCopy = append(seenCopy, node)
err := node.CheckForCycle(seenCopy, checked)
if err != nil {
return err
}
}
checked[dn] = true
return nil
}
func (dn *depNode) IsLeaf() bool {
return len(dn.DependsOn) == 0
}
func (dn *depNode) NewValue(ins []reflect.Value) (reflect.Value, error) {
outs := dn.Constructor.Call(ins)
var err error
if dn.ReturnsErr {
val := outs[1].Interface()
if val != nil {
err = val.(error)
}
}
return outs[0], err
}