-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathauto_provider.go
60 lines (50 loc) · 1.71 KB
/
auto_provider.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
package inject
import (
"fmt"
"reflect"
)
type autoProvider struct {
constructor interface{}
}
// NewAutoProvider specifies how to construct a value given its constructor function.
// Argument values are auto-resolved by type.
func NewAutoProvider(constructor interface{}) Provider {
fnValue := reflect.ValueOf(constructor)
if fnValue.Kind() != reflect.Func {
panic("constructor is not a function")
}
fnType := reflect.TypeOf(constructor)
if fnType.NumOut() != 1 {
panic("constructor must have exactly 1 return value")
}
return autoProvider{
constructor: constructor,
}
}
// Provide returns the result of executing the constructor with argument values resolved by type from a dependency graph
func (p autoProvider) Provide(g Graph) reflect.Value {
fnType := reflect.TypeOf(p.constructor)
argCount := fnType.NumIn()
args := make([]reflect.Value, argCount, argCount)
for i := 0; i < argCount; i++ {
argType := fnType.In(i)
values := g.ResolveByType(argType)
if len(values) > 1 {
panic(fmt.Sprintf("more than one defined pointer is assignable to the provider argument %d of type (%v)", i, argType))
} else if len(values) == 0 {
panic(fmt.Sprintf("no defined pointer is assignable to the provider argument %d of type (%v)", i, argType))
}
args[i] = values[0]
}
return reflect.ValueOf(p.constructor).Call(args)[0]
}
// Type returns the type of value to expect from Provide
func (p autoProvider) ReturnType() reflect.Type {
return reflect.TypeOf(p.constructor).Out(0)
}
// String returns a multiline string representation of the autoProvider
func (p autoProvider) String() string {
return fmt.Sprintf("&autoProvider{\n%s\n}",
indent(fmt.Sprintf("constructor: %s", reflect.TypeOf(p.constructor)), 1),
)
}