-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy pathcontainer.go
158 lines (131 loc) · 4.85 KB
/
container.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package di
import (
"reflect"
"sync"
)
// Container represents a dependency injection container.
// To create a Container, you should use a Builder, an EnhancedBuilder or another Container.
//
// A Container has a scope and may have a parent in a more generic scope
// and children in a more specific scope.
// Objects can be retrieved from the Container.
// If the requested object does not already exist in the Container,
// it is built thanks to the object definition.
type Container struct {
// containerCore contains the container data.
// Several Container can share the same containerCore.
// In this case these Container represent the same entity,
// but at a different stage of an object construction.
// They differ by their builtList field.
core *containerCore
// builtList contains the indexes of the definitions that have already been built by this Container.
// It is used to avoid cycles in object definitions.
// Each time a Container is passed as parameter of the Build function
// of a definition, this is in fact a new Container.
// Is has the same core but an updated builtList field.
builtList []int
}
// containerCore contains the data of a Container.
// But it can not build objects on its own.
// It should be used inside a container.
type containerCore struct {
m sync.RWMutex
closed bool
// scopes
scopes ScopeList
scopeLevel int
// lineage
parent *containerCore
children map[*containerCore]struct{}
unscopedChild *containerCore
deleteIfNoChild bool
// definitions and objects
indexesByName map[string]int
indexesByType map[reflect.Type][]int
definitions []Def
definitionScopeLevels []int
objects []interface{}
isBuilt []int32
building []*buildingChan
// unshared objects are stored separately in unshared.
// The index of their definition is stored in unsharedIndex at the same position as in unshared.
unshared []interface{}
unsharedIndex []int
// dependencies is a graph that allows to determine
// in which order the definitions should be closed.
// Each vertex is an index. If >= 0 it is the index of a shared object.
// If < 0, it is the opposite of the index in unshared minus 1.
// For example the first object in unshared is at position 0, so its vertice is -0-1=-1.
dependencies *graph
}
// Definitions returns the map of the available definitions ordered by name.
// These definitions represent all the objects that this Container can build.
func (ctn Container) Definitions() map[string]Def {
defs := make(map[string]Def, len(ctn.core.definitions))
for _, def := range ctn.core.definitions {
defs[def.Name] = def
}
return defs
}
// NameIsDefined returns true if there is a definition for the given name.
func (ctn Container) NameIsDefined(name string) bool {
_, ok := ctn.core.indexesByName[name]
return ok
}
// TypeIsDefined returns true if there is a definition for the given type.
// Types are declared in the Is field of a definition.
func (ctn Container) TypeIsDefined(typ reflect.Type) bool {
_, ok := ctn.core.indexesByType[typ]
return ok
}
// DefinitionsForType returns the list of the definitions matching the given type.
// Types are declared in the Is field of a definition.
func (ctn Container) DefinitionsForType(typ reflect.Type) []Def {
indexes := ctn.core.indexesByType[typ]
defs := make([]Def, 0, len(indexes))
for _, index := range indexes {
defs = append(defs, ctn.core.definitions[index])
}
return defs
}
// Scope returns the Container scope.
func (ctn Container) Scope() string {
return ctn.core.scopes[ctn.core.scopeLevel]
}
// Scopes returns the list of available scopes.
func (ctn Container) Scopes() []string {
return ctn.core.scopes.Copy()
}
// ParentScopes returns the list of scopes that are more generic than the Container scope.
func (ctn Container) ParentScopes() []string {
return ctn.core.scopes.ParentScopes(ctn.Scope())
}
// SubScopes returns the list of scopes that are more specific than the Container scope.
func (ctn Container) SubScopes() []string {
return ctn.core.scopes.SubScopes(ctn.Scope())
}
// newClosedContainer returns a closed container. It is not usable and is returned when there is an error.
func newClosedContainer() Container {
return Container{
core: &containerCore{
closed: true,
scopes: []string{},
scopeLevel: 0,
parent: nil,
children: map[*containerCore]struct{}{},
unscopedChild: nil,
deleteIfNoChild: false,
indexesByName: map[string]int{},
indexesByType: map[reflect.Type][]int{},
definitions: []Def{},
objects: []interface{}{},
definitionScopeLevels: []int{},
isBuilt: []int32{},
building: []*buildingChan{},
unshared: []interface{}{},
unsharedIndex: []int{},
dependencies: newGraph(),
},
builtList: make([]int, 0, 10),
}
}