-
Notifications
You must be signed in to change notification settings - Fork 7
/
definition.go
91 lines (72 loc) · 1.86 KB
/
definition.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
package inject
import (
"fmt"
"reflect"
)
type Definition interface {
Ptr() interface{}
Resolve(Graph) reflect.Value
Obscure(g Graph)
fmt.Stringer
}
type definition struct {
ptr interface{}
provider Provider
value *reflect.Value
}
func NewDefinition(ptr interface{}, provider Provider) Definition {
if reflect.TypeOf(ptr).Kind() != reflect.Ptr {
panic("ptr is not a pointer")
}
targetType := reflect.ValueOf(ptr).Elem().Type()
if !provider.ReturnType().AssignableTo(targetType) {
panic(fmt.Sprintf("provider return type (%v) must be assignable to the ptr value type (%v)", provider.ReturnType(), targetType))
}
return &definition{
ptr: ptr,
provider: provider,
}
}
func (d definition) Ptr() interface{} {
return d.ptr
}
// Resolve calls the provider, initializes the result, and populates the pointer with the result value
func (d *definition) Resolve(g Graph) reflect.Value {
if d.value != nil {
// already resolved
return *d.value
}
value := d.provider.Provide(g)
obj, ok := value.Interface().(Initializable)
if ok && obj != nil {
obj.Initialize()
}
// cache the result
d.value = &value
// update the ptr value
reflect.ValueOf(d.ptr).Elem().Set(value)
return value
}
// Obscure zeros out the pointer value and finalizes its previous value
func (d *definition) Obscure(g Graph) {
if d.value == nil {
// already obscured
return
}
obj, ok := d.value.Interface().(Finalizable)
// uncache the result
d.value = nil
// zero out the ptr value
ptrValue := reflect.ValueOf(d.ptr).Elem()
ptrValue.Set(reflect.Zero(ptrValue.Type()))
if ok && obj != nil {
obj.Finalize()
}
}
func (d definition) String() string {
return fmt.Sprintf("&definition{\n%s,\n%s,\n%s\n}",
indent(fmt.Sprintf("ptr: %s", ptrString(d.ptr)), 1),
indent(fmt.Sprintf("provider: %s", d.provider), 1),
indent(fmt.Sprintf("value: %s", d.value), 1),
)
}