Sauce-0.10.1
A C++ Dependency Injection Framework
injector.h
1#ifndef SAUCE_INJECTOR_H_
2#define SAUCE_INJECTOR_H_
3
4#include <cassert>
5#include <string>
6
7#include <sauce/memory.h>
8#include <sauce/named.h>
9#include <sauce/scopes.h>
10#include <sauce/internal/base_injector.h>
11#include <sauce/internal/key.h>
12#include <sauce/internal/locker_factory.h>
13#include <sauce/internal/scope_cache.h>
14#include <sauce/internal/type_id.h>
15
16namespace sauce {
17
18class Modules;
19class Injector;
20
21namespace internal {
22class ImplicitBindings;
23class InjectorFriend;
24typedef sauce::shared_ptr<Injector> InjectorPtr;
25}
26
27class Injector {
28 i::TypeId const scopeKey;
29 i::ScopeCache scopeCache;
30 sauce::weak_ptr<Injector> weak;
31 i::InjectorPtr const next;
32 sauce::shared_ptr<i::BaseInjector<i::ImplicitBindings> > const base;
33
34 friend class Modules;
35 friend class i::InjectorFriend;
36
37 Injector(i::TypeId scopeKey, i::InjectorPtr next):
38 scopeKey(scopeKey),
39 scopeCache(),
40 weak(),
41 next(next),
42 base() {}
43
44 Injector(sauce::shared_ptr<i::BaseInjector<i::ImplicitBindings> > const base):
45 scopeKey(i::typeIdOf<SingletonScope>()),
46 scopeCache(),
47 weak(),
48 next(),
49 base(base) {}
50
51 void setSelfPtr(i::InjectorPtr shared) {
52 assert(shared.get() == this);
53 weak = shared;
54 }
55
56 i::InjectorPtr getSelf() const {
57 i::InjectorPtr self = weak.lock();
58 assert(self.get() == this);
59 return self;
60 }
61
62 template<typename Dependency>
63 void validateAcyclic(bool validateProviding, i::InjectorPtr injector, i::TypeIds & ids, std::string const name) {
64 if (base.get() == NULL) {
65 next->validateAcyclic<Dependency>(validateProviding, injector, ids, name);
66 } else {
67 base->validateAcyclic<Dependency>(validateProviding, injector, ids, name);
68 }
69 }
70
71 template<typename Dependency>
72 void inject(typename i::Key<Dependency>::Ptr & injected, i::InjectorPtr injector, std::string const name) {
73 if (base.get() == NULL) {
74 next->inject<Dependency>(injected, injector, name);
75 } else {
76 base->inject<Dependency>(injected, injector, name);
77 }
78 }
79
83 sauce::auto_ptr<i::Lock> acquireLock() {
84 if (base.get() == NULL) {
85 return next->acquireLock();
86 } else {
87 return base->acquireLock();
88 }
89 }
90
91 template<typename Scope>
92 void eagerlyInject(i::InjectorPtr injector) {
93 if (base.get() == NULL) {
94 next->eagerlyInject<Scope>(injector);
95 } else {
96 base->eagerlyInject<Scope>(injector);
97 }
98 }
99
100 template<typename Dependency>
101 void cache(typename i::Key<Dependency>::Ptr pointer, i::TypeId dependencyScopeKey) {
102 if (scopeKey == dependencyScopeKey) {
103 scopeCache.template put<Dependency>(pointer);
104 } else if (next.get() == NULL) {
105 dependencyScopeKey.throwOutOfScopeException();
106 } else {
107 next->cache<Dependency>(pointer, dependencyScopeKey);
108 }
109 }
110
111 template<typename Dependency>
112 bool probe(typename i::Key<Dependency>::Ptr & out, i::TypeId dependencyScopeKey) const {
113 if (scopeKey == dependencyScopeKey) {
114 return scopeCache.template get<Dependency>(out);
115 } else if (next.get() == NULL) {
116 dependencyScopeKey.throwOutOfScopeException();
117 return false; // never reached
118 } else {
119 return next->probe<Dependency>(out, dependencyScopeKey);
120 }
121 }
122
123 template<typename Scope>
124 bool alreadyInScope() const {
125 if (scopeKey == i::typeIdOf<Scope>()) {
126 return true;
127 } else if (next.get() == NULL) {
128 return false;
129 } else {
130 return next->alreadyInScope<Scope>();
131 }
132 }
133
134public:
135
136 template<typename Dependency>
137 void inject(typename i::Key<Dependency>::Ptr & injected, std::string const name = unnamed()) {
138 typedef typename i::Key<Dependency>::Ptr Ptr;
139 typedef typename i::Key<Dependency>::Normalized Normalized;
140
141 sauce::auto_ptr<i::Lock> lock = acquireLock();
142
143 i::TypeIds ids;
144 bool validateProviding = (injected.get() == NULL);
145 validateAcyclic<Normalized>(validateProviding, getSelf(), ids, name); // TODO Make this check optional.
146
147 inject<Normalized>(injected, getSelf(), name);
148 }
149
150 template<typename Iface, typename Name>
151 void inject(typename i::Key<Named<Iface, Name> >::Ptr & injected, std::string const name = unnamed()) {
152 inject<Named<Iface, Name> >(injected, name);
153 }
154
155 template<typename Dependency>
156 typename i::Key<Dependency>::Ptr get(std::string const name = unnamed()) {
157 typename i::Key<Dependency>::Ptr injected;
158 inject<Dependency>(injected, name);
159 return injected;
160 }
161
162 template<typename Iface, typename Name>
163 typename i::Key<Named<Iface, Name> >::Ptr get(std::string const name = unnamed()) {
164 return get<Named<Iface, Name> >(name);
165 }
166
167 template<typename Scope>
168 i::InjectorPtr enter() const {
169 if (alreadyInScope<Scope>()) {
171 }
172
173 i::InjectorPtr scoped(new Injector(i::typeIdOf<Scope>(), getSelf()));
174 scoped->setSelfPtr(scoped);
175 return scoped;
176 }
177
178 i::InjectorPtr exit() const {
179 if (next.get() == NULL) {
181 } else {
182 return next;
183 }
184 }
185
186 template<typename Scope>
187 void eagerlyInject() {
188 sauce::auto_ptr<i::Lock> lock = acquireLock();
189 eagerlyInject<Scope>(getSelf());
190 }
191
192};
193
194namespace internal {
195
197protected:
198
199 template<typename Dependency>
200 void validateAcyclicHelper(InjectorPtr injector, TypeIds & ids, std::string const name) const {
201 injector->validateAcyclic<Dependency>(true, injector, ids, name);
202 }
203
204 template<typename Dependency>
205 void injectHelper(typename Key<Dependency>::Ptr & injected, InjectorPtr injector, std::string const name) const {
206 injector->inject<Dependency>(injected, injector, name);
207 }
208
209 template<typename Dependency>
210 void cache(InjectorPtr injector, typename Key<Dependency>::Ptr injected, i::TypeId scope) const {
211 injector->template cache<Dependency>(injected, scope);
212 }
213
214 template<typename Dependency>
215 bool probe(InjectorPtr injector, typename Key<Dependency>::Ptr & injected, i::TypeId scope) const {
216 return injector->template probe<Dependency>(injected, scope);
217 }
218
219};
220
221}
222
223}
224
225#endif // SAUCE_INJECTOR_H_
Thrown when re-entering the given scope, which is already open.
Definition: exceptions.h:103
Thrown when exiting the singleton scope.
Definition: exceptions.h:111
Definition: injector.h:27
A factory that accepts Modules and creates Injectors.
Definition: modules.h:77
Wrap dependency requests with Named to choose one of several (statically) named alternatives.
Definition: named.h:12
Definition: base_injector.h:51
Definition: injector.h:196
A complete specification of a dependency request.
Definition: key.h:15
Definition: scope_cache.h:19
A TypeSignature equipped with specific helper methods dealing in the hidden type.
Definition: type_id.h:34
virtual void throwOutOfScopeException() const
Throw an OutOfScopeException appropriate for the hidden type, assuming it is a Scope.
Definition: type_id.h:64