-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathgraph.go
117 lines (102 loc) · 3.09 KB
/
graph.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
package inject
import (
"fmt"
"reflect"
"sort"
)
// Graph describes a dependency graph that resolves nodes using well defined relationships.
// These relationships are defined with node pointers and Providers.
type Graph interface {
Finalizable
Add(Definition)
Define(ptr interface{}, provider Provider) Definition
Resolve(ptr interface{}) reflect.Value
ResolveByType(ptrType reflect.Type) []reflect.Value
ResolveByAssignableType(ptrType reflect.Type) []reflect.Value
ResolveAll() []reflect.Value
fmt.Stringer
}
type graph struct {
definitions map[interface{}]Definition
}
// NewGraph constructs a new Graph, initializing the provider and value maps.
func NewGraph(defs ...Definition) Graph {
defMap := make(map[interface{}]Definition, len(defs))
for _, def := range defs {
defMap[def.Ptr()] = def
}
return &graph{
definitions: defMap,
}
}
func (g *graph) Add(def Definition) {
g.definitions[def.Ptr()] = def
}
// Define a pointer as being resolved by a provider
func (g *graph) Define(ptr interface{}, provider Provider) Definition {
def := NewDefinition(ptr, provider)
g.Add(def)
return def
}
// Resolve a pointer into a value by recursively resolving its dependencies and/or returning the cached result
func (g *graph) Resolve(ptr interface{}) reflect.Value {
ptrType := reflect.TypeOf(ptr)
if ptrType.Kind() != reflect.Ptr {
panic(fmt.Sprintf("ptr (%v) is not a pointer", ptrType))
}
ptrValueElem := reflect.ValueOf(ptr).Elem()
def, found := g.definitions[ptr]
if !found {
// no known definition - return the current value of the pointer
return ptrValueElem
}
return def.Resolve(g)
}
// Resolve a type into a list of values by resolving all defined pointers with that exact type
func (g *graph) ResolveByType(ptrType reflect.Type) []reflect.Value {
var values []reflect.Value
for ptr, def := range g.definitions {
if reflect.TypeOf(ptr).Elem() == ptrType {
values = append(values, def.Resolve(g))
}
}
return values
}
// Resolve a type into a list of values by resolving all defined pointers assignable to that type
func (g *graph) ResolveByAssignableType(ptrType reflect.Type) []reflect.Value {
var values []reflect.Value
for ptr, def := range g.definitions {
if reflect.TypeOf(ptr).Elem().AssignableTo(ptrType) {
values = append(values, def.Resolve(g))
}
}
return values
}
// ResolveAll known pointers into values, caching and returning the results
func (g *graph) ResolveAll() []reflect.Value {
var values []reflect.Value
for _, def := range g.definitions {
values = append(values, def.Resolve(g))
}
return values
}
// Finalize obscures (finalizes) all the resolved definitions
func (g *graph) Finalize() {
for _, def := range g.definitions {
def.Obscure(g)
}
}
// String returns a multiline string representation of the dependency graph
func (g graph) String() string {
return fmt.Sprintf("&graph{\n%s\n}",
indent(fmt.Sprintf("definitions: %s", g.fmtDefinitions()), 1),
)
}
func (g graph) fmtDefinitions() string {
a := make([]string, 0, len(g.definitions))
for _, def := range g.definitions {
a = append(a, def.String())
}
sort.Strings(a)
return arrayString(a)
}