-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathautowire.go
102 lines (78 loc) · 1.85 KB
/
autowire.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
package gocon
import (
"context"
"errors"
"reflect"
)
var ErrNotStruct = errors.New("autowire only supports structs")
func autowire(rt reflect.Type) *Definition {
return &Definition{
Key: keyOf(rt),
Type: rt,
configureFunc: func(c Container) error {
var configure func(rt reflect.Type) error
configure = func(rt reflect.Type) error {
if rt.Kind() == reflect.Pointer {
return configure(rt.Elem())
}
if rt.Kind() != reflect.Struct {
return ErrNotStruct
}
for i := 0; i < rt.NumField(); i++ {
ft := rt.Field(i).Type
if _, err := c.Get(keyOf(ft)); err == nil || !errors.As(err, new(ServiceNotFoundError)) {
continue
}
for ft.Kind() == reflect.Pointer {
ft = ft.Elem()
}
if ft.Kind() != reflect.Struct {
continue
}
if err := c.Set(autowire(ft)); err != nil {
return err
}
}
return nil
}
return configure(rt)
},
resolveFunc: func(ctx context.Context, c Container) (*reflect.Value, error) {
var resolve func(rt reflect.Type) (*reflect.Value, error)
resolve = func(rt reflect.Type) (*reflect.Value, error) {
if rt.Kind() == reflect.Pointer {
rv, err := resolve(rt.Elem())
if err != nil {
return nil, err
}
a := rv.Addr()
return &a, nil
}
if rt.Kind() != reflect.Struct {
return nil, ErrNotStruct
}
rv := reflect.New(rt).Elem()
for i := 0; i < rt.NumField(); i++ {
field := rt.Field(i)
if !field.IsExported() {
continue
}
def, err := c.Get(keyOf(field.Type))
if err != nil {
return nil, err
}
v, err := def.Resolve(ctx, c)
if err != nil {
return nil, err
}
rv.Field(i).Set(*v)
}
return &rv, nil
}
return resolve(rt)
},
}
}
func Autowire[T any]() *Definition {
return autowire(typeOf[T]())
}