-
Notifications
You must be signed in to change notification settings - Fork 14
/
binding.go
116 lines (98 loc) · 3.01 KB
/
binding.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
package dingo
import (
"fmt"
"reflect"
)
type (
// Binding defines a type mapped to a more concrete type
Binding struct {
typeof reflect.Type
to reflect.Type
instance *Instance
provider *Provider
eager bool
annotatedWith string
scope Scope
}
// Instance holds quick-references to type and value
Instance struct {
itype reflect.Type
ivalue reflect.Value
}
// Provider holds the provider function
Provider struct {
fnctype reflect.Type
fnc reflect.Value
binding *Binding
}
)
// To binds a concrete type to a binding
func (b *Binding) To(what interface{}) *Binding {
to := reflect.TypeOf(what)
for to.Kind() == reflect.Ptr {
to = to.Elem()
}
if !to.AssignableTo(b.typeof) && !reflect.PtrTo(to).AssignableTo(b.typeof) {
panic(fmt.Sprintf("%s#%s not assignable to %s#%s", to.PkgPath(), to.Name(), b.typeof.PkgPath(), b.typeof.Name()))
}
b.to = to
return b
}
// ToInstance binds an instance to a binding
func (b *Binding) ToInstance(instance interface{}) *Binding {
b.instance = &Instance{
itype: reflect.TypeOf(instance),
ivalue: reflect.ValueOf(instance),
}
if !b.instance.itype.AssignableTo(b.typeof) && !b.instance.itype.AssignableTo(reflect.PtrTo(b.typeof)) {
panic(fmt.Sprintf("%s#%s not assignable to %s#%s", b.instance.itype.PkgPath(), b.instance.itype.Name(), b.typeof.PkgPath(), b.typeof.Name()))
}
return b
}
// ToProvider binds a provider to an instance. The provider's arguments are automatically injected
func (b *Binding) ToProvider(p interface{}) *Binding {
provider := &Provider{
fnc: reflect.ValueOf(p),
binding: b,
}
provider.fnctype = provider.fnc.Type().Out(0)
if !provider.fnctype.AssignableTo(b.typeof) && !provider.fnctype.AssignableTo(reflect.PtrTo(b.typeof)) {
panic(fmt.Sprintf("provider returns %q which is not assignable to %q", provider.fnctype, b.typeof))
}
b.provider = provider
return b
}
// AnnotatedWith sets the binding's annotation
func (b *Binding) AnnotatedWith(annotation string) *Binding {
b.annotatedWith = annotation
return b
}
// In set's the bindings scope
func (b *Binding) In(scope Scope) *Binding {
b.scope = scope
return b
}
// AsEagerSingleton set's the binding to singleton and requests eager initialization
func (b *Binding) AsEagerSingleton() *Binding {
b.In(Singleton)
b.eager = true
return b
}
func (b *Binding) equal(to *Binding) bool {
return reflect.DeepEqual(b, to)
}
// Create creates a new instance by the provider and requests injection, all provider arguments are automatically filled
func (p *Provider) Create(injector *Injector) (reflect.Value, error) {
in := make([]reflect.Value, p.fnc.Type().NumIn())
var err error
for i := 0; i < p.fnc.Type().NumIn(); i++ {
if in[i], err = injector.getInstance(p.fnc.Type().In(i), "", traceCircular); err != nil {
return reflect.Value{}, err
}
for !in[i].Type().AssignableTo(p.fnc.Type().In(i)) && in[i].Kind() == reflect.Ptr {
in[i] = in[i].Elem()
}
}
res := p.fnc.Call(in)[0]
return res, injector.requestInjection(res, traceCircular)
}