blob: 72612e37b36dee445fc3787f99db68b054bb1eb2 [file] [log] [blame]
Marco Poletticf798fa2014-06-21 15:05:15 +01001/*
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
Marco Poletti7f35b652014-11-01 10:11:37 +000017#ifndef FRUIT_COMPONENT_DEFN_H
18#define FRUIT_COMPONENT_DEFN_H
Marco Poletticf798fa2014-06-21 15:05:15 +010019
Marco Polettif2895102016-01-30 13:38:37 +000020#include <fruit/component.h>
Marco Poletti103f6502014-10-04 09:48:09 +010021
Marco Polettif2895102016-01-30 13:38:37 +000022#include <fruit/impl/injection_errors.h>
23#include <fruit/impl/storage/component_storage.h>
Marco Poletti32381f62014-11-01 15:51:05 +000024
25#include <memory>
26
Marco Poletticf798fa2014-06-21 15:05:15 +010027namespace fruit {
Marco Poletti5d849292014-07-05 19:04:31 +010028
Marco Poletti6cf268f2016-03-25 11:45:08 +000029namespace impl {
30namespace meta {
31// This is a helper class used in the implementation of Component and PartialComponent.
32// It's in fruit::impl::meta so that we don't need to qualify everything with fruit::impl::meta.
33template <typename... PreviousBindings>
34struct OpForComponent {
35 template <typename Comp>
36 using ConvertTo = Eval<
Marco Poletti905dc092017-03-12 15:54:31 +000037 Call(ReverseComposeFunctors(Id<ComponentFunctor(ConvertComponent, Comp)>,
38 ProcessDeferredBindings,
39 Id<ProcessBinding(PreviousBindings)>...),
40 ConstructComponentImpl())>;
Marco Poletti6cf268f2016-03-25 11:45:08 +000041
42 template <typename Binding>
43 using AddBinding = Eval<
Marco Poletti905dc092017-03-12 15:54:31 +000044 Call(ReverseComposeFunctors(Id<ProcessBinding(Binding)>,
45 Id<ProcessBinding(PreviousBindings)>...),
46 ConstructComponentImpl())>;
Marco Poletti6cf268f2016-03-25 11:45:08 +000047};
48} // namespace meta
49} // namespace impl
50
Marco Poletti4406e322014-10-04 10:53:59 +010051template <typename... Params>
Marco Poletticbe3c7a2016-02-07 09:52:02 +000052template <typename... Bindings>
Marco Poletti04cf9242016-08-29 19:31:12 +010053inline Component<Params...>::Component(PartialComponent<Bindings...> component)
Marco Poletti0316a002016-08-29 16:43:10 +010054 : storage() {
55
Marco Polettie8443552016-02-07 10:25:39 +000056 (void)typename fruit::impl::meta::CheckIfError<Comp>::type();
Marco Poletti0316a002016-08-29 16:43:10 +010057
Marco Poletti6cf268f2016-03-25 11:45:08 +000058 using Op = typename fruit::impl::meta::OpForComponent<Bindings...>::template ConvertTo<Comp>;
Marco Polettie8443552016-02-07 10:25:39 +000059 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
Marco Poletti0316a002016-08-29 16:43:10 +010060
Marco Poletti36253c92015-07-19 17:12:47 +010061#ifndef FRUIT_NO_LOOP_CHECK
Marco Poletti6cf268f2016-03-25 11:45:08 +000062 (void)typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNoLoopInDeps(typename Op::Result)>>::type();
Marco Polettie5c936b2015-07-25 11:24:27 +010063#endif // !FRUIT_NO_LOOP_CHECK
Marco Poletti6cf268f2016-03-25 11:45:08 +000064
Marco Poletti0316a002016-08-29 16:43:10 +010065 component.storage.addBindings(storage);
66
67 // TODO: re-enable this check somehow.
68 // component.component.already_converted_to_component = true;
Marco Poletti04cf9242016-08-29 19:31:12 +010069
Marco Poletti6cf268f2016-03-25 11:45:08 +000070 Op()(storage);
Marco Poletti4406e322014-10-04 10:53:59 +010071}
72
Marco Poletticbe3c7a2016-02-07 09:52:02 +000073template <typename... Params>
74template <typename... OtherParams>
75inline Component<Params...>::Component(Component<OtherParams...> component)
Marco Polettic9e7a0b2017-06-11 20:04:03 +010076 : storage(std::move(component.storage)) {
77 (void)typename fruit::impl::meta::CheckIfError<Comp>::type();
78
79 using InstallBinding = fruit::impl::InstallComponent<Component<OtherParams...>>;
80
81 using Op1 = typename fruit::impl::meta::OpForComponent<>::template AddBinding<InstallBinding>;
82 (void)typename fruit::impl::meta::CheckIfError<Op1>::type();
83
84 using Op2 = typename fruit::impl::meta::OpForComponent<InstallBinding>::template ConvertTo<Comp>;
85 (void)typename fruit::impl::meta::CheckIfError<Op2>::type();
86
87 Op2()(storage);
88
89#ifndef FRUIT_NO_LOOP_CHECK
90 (void)typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNoLoopInDeps(typename Op2::Result)>>::type();
91#endif // !FRUIT_NO_LOOP_CHECK
Marco Poletti4406e322014-10-04 10:53:59 +010092}
93
Marco Poletticbe3c7a2016-02-07 09:52:02 +000094template <typename... Bindings>
Marco Poletti0316a002016-08-29 16:43:10 +010095inline PartialComponent<Bindings...>::~PartialComponent() {
96}
97
98template <>
99inline PartialComponent<>::~PartialComponent() {
100
101}
102
103inline PartialComponent<> createComponent() {
104 return {{}};
Marco Poletticf798fa2014-06-21 15:05:15 +0100105}
106
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000107template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100108template <typename AnnotatedI, typename AnnotatedC>
Marco Poletti0109baa2016-03-25 13:04:47 +0000109inline PartialComponent<fruit::impl::Bind<AnnotatedI, AnnotatedC>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100110PartialComponent<Bindings...>::bind() {
Marco Poletti0109baa2016-03-25 13:04:47 +0000111 using Op = OpFor<fruit::impl::Bind<AnnotatedI, AnnotatedC>>;
Marco Polettie8443552016-02-07 10:25:39 +0000112 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
113
Marco Poletti0316a002016-08-29 16:43:10 +0100114 return {{storage}};
Marco Poletti4406e322014-10-04 10:53:59 +0100115}
116
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000117template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100118template <typename AnnotatedSignature>
Marco Poletti0109baa2016-03-25 13:04:47 +0000119inline PartialComponent<fruit::impl::RegisterConstructor<AnnotatedSignature>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100120PartialComponent<Bindings...>::registerConstructor() {
Marco Poletti0109baa2016-03-25 13:04:47 +0000121 using Op = OpFor<fruit::impl::RegisterConstructor<AnnotatedSignature>>;
Marco Polettie8443552016-02-07 10:25:39 +0000122 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
123
Marco Poletti0316a002016-08-29 16:43:10 +0100124 return {{storage}};
Marco Poletti4406e322014-10-04 10:53:59 +0100125}
126
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000127template <typename... Bindings>
Marco Poletti4406e322014-10-04 10:53:59 +0100128template <typename C>
Marco Poletti0acba692016-12-10 17:44:38 +0000129inline PartialComponent<fruit::impl::BindInstance<C, C>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100130PartialComponent<Bindings...>::bindInstance(C& instance) {
Marco Poletti0acba692016-12-10 17:44:38 +0000131 using Op = OpFor<fruit::impl::BindInstance<C, C>>;
Marco Polettie8443552016-02-07 10:25:39 +0000132 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
Marco Poletti0316a002016-08-29 16:43:10 +0100133 return {{storage, instance}};
Marco Poletti4406e322014-10-04 10:53:59 +0100134}
135
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000136template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100137template <typename AnnotatedC, typename C>
Marco Poletti0acba692016-12-10 17:44:38 +0000138inline PartialComponent<fruit::impl::BindInstance<AnnotatedC, C>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100139PartialComponent<Bindings...>::bindInstance(C& instance) {
Marco Poletti0acba692016-12-10 17:44:38 +0000140 using Op = OpFor<fruit::impl::BindInstance<AnnotatedC, C>>;
Marco Polettie8443552016-02-07 10:25:39 +0000141 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
Marco Poletti0316a002016-08-29 16:43:10 +0100142 return {{storage, instance}};
Marco Poletti31f638a2015-05-10 21:21:25 +0100143}
144
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000145template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100146template <typename Lambda>
Marco Poletti0109baa2016-03-25 13:04:47 +0000147inline PartialComponent<fruit::impl::RegisterProvider<Lambda>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100148PartialComponent<Bindings...>::registerProvider(Lambda) {
Marco Poletti0109baa2016-03-25 13:04:47 +0000149 using Op = OpFor<fruit::impl::RegisterProvider<Lambda>>;
Marco Polettie8443552016-02-07 10:25:39 +0000150 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
Marco Poletti0316a002016-08-29 16:43:10 +0100151 return {{storage}};
Marco Poletti4406e322014-10-04 10:53:59 +0100152}
153
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000154template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100155template <typename AnnotatedSignature, typename Lambda>
Marco Poletti0109baa2016-03-25 13:04:47 +0000156inline PartialComponent<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100157PartialComponent<Bindings...>::registerProvider(Lambda) {
Marco Poletti0109baa2016-03-25 13:04:47 +0000158 using Op = OpFor<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>>;
Marco Polettie8443552016-02-07 10:25:39 +0000159 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
Marco Poletti0316a002016-08-29 16:43:10 +0100160 return {{storage}};
Marco Poletti31f638a2015-05-10 21:21:25 +0100161}
162
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000163template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100164template <typename AnnotatedI, typename AnnotatedC>
Marco Poletti0109baa2016-03-25 13:04:47 +0000165inline PartialComponent<fruit::impl::AddMultibinding<AnnotatedI, AnnotatedC>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100166PartialComponent<Bindings...>::addMultibinding() {
Marco Poletti0109baa2016-03-25 13:04:47 +0000167 using Op = OpFor<fruit::impl::AddMultibinding<AnnotatedI, AnnotatedC>>;
Marco Polettie8443552016-02-07 10:25:39 +0000168 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
169
Marco Poletti0316a002016-08-29 16:43:10 +0100170 return {{storage}};
Marco Poletti4406e322014-10-04 10:53:59 +0100171}
172
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000173template <typename... Bindings>
Marco Poletti4406e322014-10-04 10:53:59 +0100174template <typename C>
Marco Poletti0316a002016-08-29 16:43:10 +0100175inline PartialComponent<fruit::impl::AddInstanceMultibinding<C>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100176PartialComponent<Bindings...>::addInstanceMultibinding(C& instance) {
Marco Poletti0316a002016-08-29 16:43:10 +0100177 return {{storage, instance}};
Marco Poletti31f638a2015-05-10 21:21:25 +0100178}
179
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000180template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100181template <typename AnnotatedC, typename C>
Marco Poletti0316a002016-08-29 16:43:10 +0100182inline PartialComponent<fruit::impl::AddInstanceMultibinding<AnnotatedC>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100183PartialComponent<Bindings...>::addInstanceMultibinding(C& instance) {
Marco Poletti0316a002016-08-29 16:43:10 +0100184 return {{storage, instance}};
Marco Poletti4406e322014-10-04 10:53:59 +0100185}
186
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000187template <typename... Bindings>
Marco Polettie53b79e2015-01-28 06:23:48 +0000188template <typename C>
Marco Poletti0316a002016-08-29 16:43:10 +0100189inline PartialComponent<fruit::impl::AddInstanceVectorMultibindings<C>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100190PartialComponent<Bindings...>::addInstanceMultibindings(std::vector<C>& instances) {
Marco Poletti0316a002016-08-29 16:43:10 +0100191 return {{storage, instances}};
Marco Polettie53b79e2015-01-28 06:23:48 +0000192}
193
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000194template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100195template <typename AnnotatedC, typename C>
Marco Poletti0316a002016-08-29 16:43:10 +0100196inline PartialComponent<fruit::impl::AddInstanceVectorMultibindings<AnnotatedC>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100197PartialComponent<Bindings...>::addInstanceMultibindings(std::vector<C>& instances) {
Marco Poletti0316a002016-08-29 16:43:10 +0100198 return {{storage, instances}};
Marco Poletti31f638a2015-05-10 21:21:25 +0100199}
200
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000201template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100202template <typename Lambda>
Marco Poletti0109baa2016-03-25 13:04:47 +0000203inline PartialComponent<fruit::impl::AddMultibindingProvider<Lambda>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100204PartialComponent<Bindings...>::addMultibindingProvider(Lambda) {
Marco Poletti0109baa2016-03-25 13:04:47 +0000205 using Op = OpFor<fruit::impl::AddMultibindingProvider<Lambda>>;
Marco Polettie8443552016-02-07 10:25:39 +0000206 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
207
Marco Poletti0316a002016-08-29 16:43:10 +0100208 return {{storage}};
Marco Poletti4406e322014-10-04 10:53:59 +0100209}
Marco Poletti90367fd2014-09-07 19:53:06 +0100210
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000211template <typename... Bindings>
Marco Polettied4d62b2014-11-24 18:24:09 +0000212template <typename AnnotatedSignature, typename Lambda>
Marco Poletti0109baa2016-03-25 13:04:47 +0000213inline PartialComponent<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100214PartialComponent<Bindings...>::addMultibindingProvider(Lambda) {
Marco Poletti0109baa2016-03-25 13:04:47 +0000215 using Op = OpFor<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>>;
Marco Polettie8443552016-02-07 10:25:39 +0000216 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
217
Marco Poletti0316a002016-08-29 16:43:10 +0100218 return {{storage}};
Marco Poletti31f638a2015-05-10 21:21:25 +0100219}
220
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000221template <typename... Bindings>
Marco Poletti31f638a2015-05-10 21:21:25 +0100222template <typename DecoratedSignature, typename Lambda>
Marco Poletti0109baa2016-03-25 13:04:47 +0000223inline PartialComponent<fruit::impl::RegisterFactory<DecoratedSignature, Lambda>, Bindings...>
Marco Poletticf5c9f12016-08-28 20:43:00 +0100224PartialComponent<Bindings...>::registerFactory(Lambda) {
Marco Poletti0109baa2016-03-25 13:04:47 +0000225 using Op = OpFor<fruit::impl::RegisterFactory<DecoratedSignature, Lambda>>;
Marco Polettie8443552016-02-07 10:25:39 +0000226 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
227
Marco Poletti0316a002016-08-29 16:43:10 +0100228 return {{storage}};
229}
230
231template <typename... Bindings>
232inline PartialComponent<Bindings...>::PartialComponent(fruit::impl::PartialComponentStorage<Bindings...> storage)
233 : storage(std::move(storage)) {
Marco Poletti4406e322014-10-04 10:53:59 +0100234}
235
Marco Poletticbe3c7a2016-02-07 09:52:02 +0000236template <typename... Bindings>
Marco Poletti4406e322014-10-04 10:53:59 +0100237template <typename... OtherCompParams>
Marco Poletti3e21dcf2017-06-17 15:58:00 +0100238FRUIT_DEPRECATED_DEFINITION(
Marco Poletti09843e02017-06-11 11:48:37 +0100239inline PartialComponent<fruit::impl::OldStyleInstallComponent<Component<OtherCompParams...>>, Bindings...>
Marco Poletti3e21dcf2017-06-17 15:58:00 +0100240PartialComponent<Bindings...>::install(const Component<OtherCompParams...>& other_component)) {
Marco Poletti09843e02017-06-11 11:48:37 +0100241 using Op = OpFor<fruit::impl::OldStyleInstallComponent<Component<OtherCompParams...>>>;
Marco Polettie8443552016-02-07 10:25:39 +0000242 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
Marco Poletti0316a002016-08-29 16:43:10 +0100243 return {{storage, other_component.storage}};
Marco Poletticf798fa2014-06-21 15:05:15 +0100244}
245
Marco Poletti09843e02017-06-11 11:48:37 +0100246template <typename T>
247FRUIT_ALWAYS_INLINE
248inline int checkAcceptableComponentInstallArg() {
249 // This lambda checks that the required operations on T exist.
250 // Note that the lambda is never actually executed.
251 auto checkRequirements = [](const T& constRef, T value) {
252 T x1(constRef);
253 T x2(std::move(value));
254 x1 = constRef;
255 x2 = std::move(value);
256 bool b = (constRef == constRef);
257 std::size_t h = std::hash<T>()(constRef);
258 (void)x1;
259 (void)x2;
260 (void)b;
261 (void)h;
262 };
263 (void)checkRequirements;
264 return 0;
265}
266
267template <typename... Bindings>
268template <typename OtherComponent, typename... Args>
269inline PartialComponent<fruit::impl::InstallComponent<OtherComponent, Args...>, Bindings...>
Marco Poletti5de0d4f2017-06-11 12:47:52 +0100270PartialComponent<Bindings...>::install(OtherComponent(*fun)(Args...), Args... args) {
Marco Poletti09843e02017-06-11 11:48:37 +0100271 using IntCollector = int[];
272 (void)(IntCollector{0, checkAcceptableComponentInstallArg<Args>()...});
273
274 using Op = OpFor<fruit::impl::InstallComponent<OtherComponent, Args...>>;
275 (void)typename fruit::impl::meta::CheckIfError<Op>::type();
276
277 return {{storage, fun, std::move(args)...}};
278}
279
Marco Poletti09843e02017-06-11 11:48:37 +0100280
Marco Poletticf798fa2014-06-21 15:05:15 +0100281} // namespace fruit
282
Marco Poletti7f35b652014-11-01 10:11:37 +0000283#endif // FRUIT_COMPONENT_DEFN_H