-
Notifications
You must be signed in to change notification settings - Fork 13
/
schema.go
143 lines (131 loc) · 3.36 KB
/
schema.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package di
import (
"fmt"
"reflect"
)
// schema is a dependency injection schema.
type schema interface {
// find finds reflect.Type with matching Tags.
find(t reflect.Type, tags Tags) (*node, error)
// register cleanup
cleanup(cleanup func())
}
// schema is a dependency injection schema.
type defaultSchema struct {
parents []*defaultSchema
nodes map[reflect.Type][]*node
cleanups []func()
}
func (s *defaultSchema) cleanup(cleanup func()) {
s.cleanups = append(s.cleanups, cleanup)
}
// newDefaultSchema creates new dependency injection schema.
func newDefaultSchema() *defaultSchema {
return &defaultSchema{
nodes: map[reflect.Type][]*node{},
}
}
// register registers reflect.Type provide function with optional Tags. Also, its registers
// type []<type> for group.
func (s *defaultSchema) register(n *node) {
defer tracer.Trace("Register %s", n)
if _, ok := s.nodes[n.rt]; !ok {
s.nodes[n.rt] = []*node{n}
return
}
s.nodes[n.rt] = append(s.nodes[n.rt], n)
}
// used depth-first topological sort algorithm
func (s *defaultSchema) prepare(n *node) error {
var marks = map[*node]int{}
if err := visit(s, n, marks); err != nil {
return err
}
return nil
}
// find finds provideFunc by its reflect.Type and Tags.
func (s *defaultSchema) find(t reflect.Type, tags Tags) (*node, error) {
nodes, ok := s.list(t)
// type found
if ok {
matched := matchTags(nodes, tags)
if len(matched) == 0 {
return nil, fmt.Errorf("type %s%s %w", t, tags, ErrTypeNotExists)
}
if len(matched) > 1 {
return nil, fmt.Errorf("multiple definitions of %s%s, maybe you need to use group type: []%s%s", t, tags, t, tags)
}
return matched[0], nil
}
// if not a group and not have di.Inject
if t.Kind() != reflect.Slice && !canInject(t) {
return nil, fmt.Errorf("type %s%s %w", t, tags, ErrTypeNotExists)
}
if canInject(t) {
node := &node{
compiler: newTypeCompiler(t),
rt: t,
rv: new(reflect.Value),
}
// save node for future use
s.nodes[t] = append(s.nodes[t], node)
return node, nil
}
return s.group(t, tags)
}
func (s *defaultSchema) group(t reflect.Type, tags Tags) (*node, error) {
group, ok := s.list(t.Elem())
if !ok {
return nil, fmt.Errorf("type %s%s %w", t, tags, ErrTypeNotExists)
}
matched := matchTags(group, tags)
if len(matched) == 0 {
return nil, fmt.Errorf("type %s%s %w", t, tags, ErrTypeNotExists)
}
node := &node{
compiler: newGroupCompiler(t, matched),
rt: t,
tags: tags,
rv: new(reflect.Value),
}
return node, nil
}
// list lists all the nodes of its reflect.Type
func (s *defaultSchema) list(t reflect.Type) (nodes []*node, ok bool) {
for _, parent := range s.parents {
if n, o := parent.list(t); o {
nodes = append(nodes, n...)
ok = true
}
}
if n, o := s.nodes[t]; o {
nodes = append(nodes, n...)
ok = true
}
return nodes, ok
}
// isAncestor returns true if a
func (s *defaultSchema) isAncestor(a *defaultSchema) bool {
for _, parent := range s.parents {
if parent == a {
return true
}
if parent.isAncestor(a) {
return true
}
}
return false
}
func (s *defaultSchema) addParent(parent *defaultSchema) error {
if parent == s {
return fmt.Errorf("self cycle detected")
}
if parent.isAncestor(s) {
return fmt.Errorf("cycle detected")
}
if s.isAncestor(parent) {
return fmt.Errorf("parent already chained")
}
s.parents = append(s.parents, parent)
return nil
}