1 /*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef FRUIT_COMPONENT_DEFN_H
18 #define FRUIT_COMPONENT_DEFN_H
19
20 #include <fruit/component.h>
21
22 #include <fruit/impl/component_storage/component_storage.h>
23 #include <fruit/impl/injection_errors.h>
24 #include <fruit/impl/component_install_arg_checks.h>
25
26 #include <memory>
27
28 namespace fruit {
29
30 namespace impl {
31 namespace meta {
32 // This is a helper class used in the implementation of Component and PartialComponent.
33 // It's in fruit::impl::meta so that we don't need to qualify everything with fruit::impl::meta.
34 template <typename... PreviousBindings>
35 struct OpForComponent {
36 template <typename Comp>
37 using ConvertTo = Eval<Call(ReverseComposeFunctors(Id<ComponentFunctor(ConvertComponent, Comp)>,
38 ProcessDeferredBindings, Id<ProcessBinding(PreviousBindings)>...),
39 ConstructComponentImpl())>;
40
41 template <typename Binding>
42 using AddBinding =
43 Eval<Call(ReverseComposeFunctors(Id<ProcessBinding(Binding)>, Id<ProcessBinding(PreviousBindings)>...),
44 ConstructComponentImpl())>;
45 };
46 } // namespace meta
47 } // namespace impl
48
49 template <typename... Params>
50 template <typename... Bindings>
Component(PartialComponent<Bindings...> && partial_component)51 inline Component<Params...>::Component(PartialComponent<Bindings...>&& partial_component) : storage() {
52
53 (void)typename fruit::impl::meta::CheckIfError<Comp>::type();
54
55 using Op = typename fruit::impl::meta::OpForComponent<Bindings...>::template ConvertTo<Comp>;
56 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
57
58 #if !FRUIT_NO_LOOP_CHECK
59 (void)typename fruit::impl::meta::CheckIfError<
60 fruit::impl::meta::Eval<fruit::impl::meta::CheckNoLoopInDeps(typename Op::Result)>>::type();
61 #endif // !FRUIT_NO_LOOP_CHECK
62
63 std::size_t num_entries = partial_component.storage.numBindings() + Op().numEntries();
64 fruit::impl::FixedSizeVector<fruit::impl::ComponentStorageEntry> entries(num_entries);
65
66 Op()(entries);
67
68 // addBindings may modify the storage member of PartialComponent.
69 // Therefore, it should not be used after this operation.
70 partial_component.storage.addBindings(entries);
71
72 // TODO: re-enable this check somehow.
73 // component.component.already_converted_to_component = true;
74
75 FruitAssert(entries.size() == num_entries);
76
77 storage = fruit::impl::ComponentStorage(std::move(entries));
78 }
79
80 template <typename... Bindings>
~PartialComponent()81 inline PartialComponent<Bindings...>::~PartialComponent() {}
82
createComponent()83 inline PartialComponent<> createComponent() {
84 return {{}};
85 }
86
87 template <typename... Bindings>
88 template <typename AnnotatedI, typename AnnotatedC>
bind()89 inline PartialComponent<fruit::impl::Bind<AnnotatedI, AnnotatedC>, Bindings...> PartialComponent<Bindings...>::bind() {
90 using Op = OpFor<fruit::impl::Bind<AnnotatedI, AnnotatedC>>;
91 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
92
93 return {{storage}};
94 }
95
96 template <typename... Bindings>
97 template <typename AnnotatedSignature>
98 inline PartialComponent<fruit::impl::RegisterConstructor<AnnotatedSignature>, Bindings...>
registerConstructor()99 PartialComponent<Bindings...>::registerConstructor() {
100 using Op = OpFor<fruit::impl::RegisterConstructor<AnnotatedSignature>>;
101 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
102
103 return {{storage}};
104 }
105
106 template <typename... Bindings>
107 template <typename C>
108 inline PartialComponent<fruit::impl::BindInstance<C, C>, Bindings...>
bindInstance(C & instance)109 PartialComponent<Bindings...>::bindInstance(C& instance) {
110 using Op = OpFor<fruit::impl::BindInstance<C, C>>;
111 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
112 return {{storage, instance}};
113 }
114
115 template <typename... Bindings>
116 template <typename C>
117 inline PartialComponent<fruit::impl::BindConstInstance<C, C>, Bindings...>
bindInstance(const C & instance)118 PartialComponent<Bindings...>::bindInstance(const C& instance) {
119 using Op = OpFor<fruit::impl::BindConstInstance<C, C>>;
120 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
121 return {{storage, instance}};
122 }
123
124 template <typename... Bindings>
125 template <typename AnnotatedC, typename C>
126 inline PartialComponent<fruit::impl::BindInstance<AnnotatedC, C>, Bindings...>
bindInstance(C & instance)127 PartialComponent<Bindings...>::bindInstance(C& instance) {
128 using Op = OpFor<fruit::impl::BindInstance<AnnotatedC, C>>;
129 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
130 return {{storage, instance}};
131 }
132
133 template <typename... Bindings>
134 template <typename AnnotatedC, typename C>
135 inline PartialComponent<fruit::impl::BindConstInstance<AnnotatedC, C>, Bindings...>
bindInstance(const C & instance)136 PartialComponent<Bindings...>::bindInstance(const C& instance) {
137 using Op = OpFor<fruit::impl::BindConstInstance<AnnotatedC, C>>;
138 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
139 return {{storage, instance}};
140 }
141
142 template <typename... Bindings>
143 template <typename Lambda>
144 inline PartialComponent<fruit::impl::RegisterProvider<Lambda>, Bindings...>
registerProvider(Lambda)145 PartialComponent<Bindings...>::registerProvider(Lambda) {
146 using Op = OpFor<fruit::impl::RegisterProvider<Lambda>>;
147 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
148 return {{storage}};
149 }
150
151 template <typename... Bindings>
152 template <typename AnnotatedSignature, typename Lambda>
153 inline PartialComponent<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>, Bindings...>
registerProvider(Lambda)154 PartialComponent<Bindings...>::registerProvider(Lambda) {
155 using Op = OpFor<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>>;
156 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
157 return {{storage}};
158 }
159
160 template <typename... Bindings>
161 template <typename AnnotatedI, typename AnnotatedC>
162 inline PartialComponent<fruit::impl::AddMultibinding<AnnotatedI, AnnotatedC>, Bindings...>
addMultibinding()163 PartialComponent<Bindings...>::addMultibinding() {
164 using Op = OpFor<fruit::impl::AddMultibinding<AnnotatedI, AnnotatedC>>;
165 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
166
167 return {{storage}};
168 }
169
170 template <typename... Bindings>
171 template <typename C>
172 inline PartialComponent<fruit::impl::AddInstanceMultibinding<C>, Bindings...>
addInstanceMultibinding(C & instance)173 PartialComponent<Bindings...>::addInstanceMultibinding(C& instance) {
174 using Op = fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(
175 fruit::impl::meta::Vector<fruit::impl::meta::Type<C>>)>;
176 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
177
178 return {{storage, instance}};
179 }
180
181 template <typename... Bindings>
182 template <typename AnnotatedC, typename C>
183 inline PartialComponent<fruit::impl::AddInstanceMultibinding<AnnotatedC>, Bindings...>
addInstanceMultibinding(C & instance)184 PartialComponent<Bindings...>::addInstanceMultibinding(C& instance) {
185 using Op = fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(
186 fruit::impl::meta::Vector<fruit::impl::meta::Type<C>>)>;
187 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
188 return {{storage, instance}};
189 }
190
191 template <typename... Bindings>
192 template <typename C>
193 inline PartialComponent<fruit::impl::AddInstanceVectorMultibindings<C>, Bindings...>
addInstanceMultibindings(std::vector<C> & instances)194 PartialComponent<Bindings...>::addInstanceMultibindings(std::vector<C>& instances) {
195 using Op = fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(
196 fruit::impl::meta::Vector<fruit::impl::meta::Type<C>>)>;
197 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
198 return {{storage, instances}};
199 }
200
201 template <typename... Bindings>
202 template <typename AnnotatedC, typename C>
203 inline PartialComponent<fruit::impl::AddInstanceVectorMultibindings<AnnotatedC>, Bindings...>
addInstanceMultibindings(std::vector<C> & instances)204 PartialComponent<Bindings...>::addInstanceMultibindings(std::vector<C>& instances) {
205 using Op = fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(
206 fruit::impl::meta::Vector<fruit::impl::meta::Type<C>>)>;
207 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
208
209 return {{storage, instances}};
210 }
211
212 template <typename... Bindings>
213 template <typename Lambda>
214 inline PartialComponent<fruit::impl::AddMultibindingProvider<Lambda>, Bindings...>
addMultibindingProvider(Lambda)215 PartialComponent<Bindings...>::addMultibindingProvider(Lambda) {
216 using Op = OpFor<fruit::impl::AddMultibindingProvider<Lambda>>;
217 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
218
219 return {{storage}};
220 }
221
222 template <typename... Bindings>
223 template <typename AnnotatedSignature, typename Lambda>
224 inline PartialComponent<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>, Bindings...>
addMultibindingProvider(Lambda)225 PartialComponent<Bindings...>::addMultibindingProvider(Lambda) {
226 using Op = OpFor<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>>;
227 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
228
229 return {{storage}};
230 }
231
232 template <typename... Bindings>
233 template <typename DecoratedSignature, typename Lambda>
234 inline PartialComponent<fruit::impl::RegisterFactory<DecoratedSignature, Lambda>, Bindings...>
registerFactory(Lambda)235 PartialComponent<Bindings...>::registerFactory(Lambda) {
236 using Op = OpFor<fruit::impl::RegisterFactory<DecoratedSignature, Lambda>>;
237 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
238
239 return {{storage}};
240 }
241
242 template <typename... Bindings>
PartialComponent(fruit::impl::PartialComponentStorage<Bindings...> storage)243 inline PartialComponent<Bindings...>::PartialComponent(fruit::impl::PartialComponentStorage<Bindings...> storage)
244 : storage(std::move(storage)) {}
245
246 template <typename... Bindings>
247 template <typename... OtherComponentParams, typename... FormalArgs, typename... Args>
248 inline PartialComponent<fruit::impl::InstallComponent<fruit::Component<OtherComponentParams...>(FormalArgs...)>,
249 Bindings...>
install(fruit::Component<OtherComponentParams...> (* getComponent)(FormalArgs...),Args &&...args)250 PartialComponent<Bindings...>::install(fruit::Component<OtherComponentParams...> (*getComponent)(FormalArgs...),
251 Args&&... args) {
252 using IntCollector = int[];
253 (void)IntCollector{0, fruit::impl::checkAcceptableComponentInstallArg<FormalArgs>()...};
254
255 using Op = OpFor<fruit::impl::InstallComponent<fruit::Component<OtherComponentParams...>(FormalArgs...)>>;
256 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
257
258 std::tuple<FormalArgs...> args_tuple{std::forward<Args>(args)...};
259
260 return {{storage, getComponent, std::move(args_tuple)}};
261 }
262
263 template <typename... Bindings>
264 template <typename... ComponentFunctions>
265 inline PartialComponent<fruit::impl::InstallComponentFunctions<ComponentFunctions...>, Bindings...>
installComponentFunctions(ComponentFunctions...componentFunctions)266 PartialComponent<Bindings...>::installComponentFunctions(ComponentFunctions... componentFunctions) {
267
268 using Op = OpFor<fruit::impl::InstallComponentFunctions<ComponentFunctions...>>;
269 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
270
271 std::tuple<ComponentFunctions...> component_functions_tuple{std::move(componentFunctions)...};
272
273 return {{storage, std::move(component_functions_tuple)}};
274 }
275
276 template <typename... Bindings>
277 template <typename... OtherComponentParams, typename... FormalArgs, typename... Args>
278 inline typename PartialComponent<Bindings...>::template PartialComponentWithReplacementInProgress<
279 fruit::Component<OtherComponentParams...>, FormalArgs...>
replace(fruit::Component<OtherComponentParams...> (* getReplacedComponent)(FormalArgs...),Args &&...args)280 PartialComponent<Bindings...>::replace(fruit::Component<OtherComponentParams...> (*getReplacedComponent)(FormalArgs...),
281 Args&&... args) {
282 using IntCollector = int[];
283 (void)IntCollector{0, fruit::impl::checkAcceptableComponentInstallArg<FormalArgs>()...};
284
285 std::tuple<FormalArgs...> args_tuple{std::forward<Args>(args)...};
286
287 return {{storage, getReplacedComponent, std::move(args_tuple)}};
288 }
289
290 template <typename... Bindings>
291 template <typename OtherComponent, typename... GetReplacedComponentFormalArgs>
292 template <typename... GetReplacementComponentFormalArgs, typename... Args>
293 inline PartialComponent<fruit::impl::ReplaceComponent<OtherComponent(GetReplacedComponentFormalArgs...),
294 OtherComponent(GetReplacementComponentFormalArgs...)>,
295 Bindings...>
296 PartialComponent<Bindings...>::
with(OtherComponent (* getReplacementComponent)(GetReplacementComponentFormalArgs...),Args &&...args)297 PartialComponentWithReplacementInProgress<OtherComponent, GetReplacedComponentFormalArgs...>::with(
298 OtherComponent (*getReplacementComponent)(GetReplacementComponentFormalArgs...), Args&&... args) {
299 using IntCollector = int[];
300 (void)IntCollector{0, fruit::impl::checkAcceptableComponentInstallArg<GetReplacementComponentFormalArgs>()...};
301
302 std::tuple<GetReplacementComponentFormalArgs...> args_tuple{std::forward<Args>(args)...};
303
304 return {{storage, getReplacementComponent, std::move(args_tuple)}};
305 }
306
307 } // namespace fruit
308
309 #endif // FRUIT_COMPONENT_DEFN_H
310