-
Notifications
You must be signed in to change notification settings - Fork 2
/
registry.go
135 lines (122 loc) · 3.66 KB
/
registry.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package ioc
import (
"fmt"
"reflect"
"sync"
)
// Lifetime represents the lifetime characteristics of an instance.
type Lifetime int
const (
// Per Container Lifetime requires that an instance is only created once per container.
PerContainer Lifetime = iota
// Per Scope lifetime requires that an instance is only created once per scope.
PerScope
// Per Request lifetime requires that a new instance is created on every request.
PerRequest
)
func (lifetime Lifetime) String() string {
switch lifetime {
case PerContainer:
return "Per Container Lifetime"
case PerScope:
return "Per Scope Lifetime"
case PerRequest:
return "Per Request Lifetime"
default:
return fmt.Sprintf("%+v", int(lifetime))
}
}
//-----------------------------------------------
// registry
//-----------------------------------------------
// registry is a thread safe type-name-registration container.
type registry struct {
m *sync.RWMutex
registrations map[reflect.Type]map[string]*Registration
}
// newRegistry creates a new registry.
func newRegistry() *registry {
return ®istry{
m: new(sync.RWMutex),
registrations: make(map[reflect.Type]map[string]*Registration),
}
}
// Get a registration by type and name.
func (r *registry) get(typ reflect.Type, name string) *Registration {
// assume typ != nil
r.m.RLock()
var registration *Registration
if named, ok := r.registrations[typ]; ok {
registration = named[name]
}
r.m.RUnlock()
return registration
}
// Add or update a registration by type and name.
func (r *registry) set(typ reflect.Type, name string, registration *Registration) {
// assume typ != nil
r.m.Lock()
if named, ok := r.registrations[typ]; ok {
named[name] = registration
} else {
r.registrations[typ] = map[string]*Registration{name: registration}
}
r.m.Unlock()
}
// Get all the registrations.
func (r *registry) getAll() []*Registration {
r.m.RLock()
registrations := make([]*Registration, 0)
for _, named := range r.registrations {
for _, registration := range named {
registrations = append(registrations, registration)
}
}
r.m.RUnlock()
return registrations
}
//-----------------------------------------------
// registration
//-----------------------------------------------
// Registration contains the information necessary to construct an instance.
type Registration struct {
Type reflect.Type
Name string
Value interface{}
CreateInstanceFn func(Factory) (interface{}, error)
Lifetime Lifetime
}
// CreateInstance creates an instance using the factory function.
//
// Returns an error when:
// - The factory function is nil or returns an error. (Registration.CreateInstanceFn)
// - The created instance type is nil. (no type information)
// - The created instance is a nil pointer or interface.
// - The created instance type doesn't match the registration type or
// - The implementation type is an interface and the created instance doesn't implement the interface.
func (r *Registration) CreateInstance(factory Factory) (*reflect.Value, error) {
if r.CreateInstanceFn == nil {
return nil, errCreateInstanceFnNil(r.Type, r.Name)
}
instance, err := r.CreateInstanceFn(factory)
if err != nil {
return nil, errCreateInstance(r.Type, r.Name, err)
}
rv, err := GetNamedInstance(instance, r.Name)
if err != nil {
return nil, err
}
typ := rv.Type()
if typ == r.Type {
return rv, nil
}
if r.Type == nil || r.Type.Kind() != reflect.Interface {
return nil, errUnexpectedValueType(typ, r.Name, r.Type)
}
typ = reflect.TypeOf(instance)
if !typ.Implements(r.Type) {
return nil, errInterfaceNotImplemented(typ, r.Name, r.Type)
}
v := reflect.ValueOf(instance)
return &v, nil
}