-
Notifications
You must be signed in to change notification settings - Fork 13
/
cmp_ctor.go
108 lines (96 loc) · 2.39 KB
/
cmp_ctor.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
package di
import (
"reflect"
)
// ctorType describes types of constructor provider.
type ctorType int
const (
ctorUnknown ctorType = iota
ctorValue // (deps) (result)
ctorValueError // (deps) (result, error)
ctorValueCleanup // (deps) (result, cleanup)
ctorValueCleanupError // (deps) (result, cleanup, error)
)
// constructorCompiler compiles constructor functions.
type constructorCompiler struct {
typ ctorType
fn function
}
// newConstructorCompiler creates new function compiler from function.
func newConstructorCompiler(fn function) (*constructorCompiler, bool) {
ctorType := determineCtorType(fn)
if ctorType == ctorUnknown {
return nil, false
}
return &constructorCompiler{
typ: ctorType,
fn: fn,
}, true
}
func (c constructorCompiler) deps(s schema) (deps []*node, err error) {
for i := 0; i < c.fn.NumIn(); i++ {
in := c.fn.Type.In(i)
node, err := s.find(in, Tags{})
if err != nil {
return nil, err
}
deps = append(deps, node)
}
return deps, nil
}
func (c constructorCompiler) compile(dependencies []reflect.Value, s schema) (reflect.Value, error) {
// call constructor function
out := funcResult(c.fn.Call(dependencies))
rv := out.value()
switch c.typ {
case ctorValue:
return rv, nil
case ctorValueError:
return rv, out.error(1)
case ctorValueCleanup:
s.cleanup(out.cleanup())
return rv, nil
case ctorValueCleanupError:
s.cleanup(out.cleanup())
return rv, out.error(2)
}
bug()
return reflect.Value{}, nil
}
// determineCtorType
func determineCtorType(fn function) ctorType {
switch true {
case fn.NumOut() == 1:
return ctorValue
case fn.NumOut() == 2:
if isError(fn.Out(1)) {
return ctorValueError
}
if isCleanup(fn.Out(1)) {
return ctorValueCleanup
}
case fn.NumOut() == 3 && isCleanup(fn.Out(1)) && isError(fn.Out(2)):
return ctorValueCleanupError
}
return ctorUnknown
}
// funcResult is a helper struct for reflect.Call.
type funcResult []reflect.Value
// value returns first result type.
func (r funcResult) value() reflect.Value {
return r[0]
}
// cleanup returns cleanup function.
func (r funcResult) cleanup() func() {
if r[1].IsNil() {
return nil
}
return r[1].Interface().(func())
}
// error returns error if it exists.
func (r funcResult) error(position int) error {
if r[position].IsNil() {
return nil
}
return r[position].Interface().(error)
}