blob: 7b8f82cd3debe87cfa0827dca7e230f1309df1bc [file] [log] [blame]
Marco Polettia5f49d42014-06-29 10:41:12 +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
17#ifndef FRUIT_PROVIDER_H
18#define FRUIT_PROVIDER_H
19
Marco Polettia5289cf2015-03-15 10:42:03 +000020// This include is not required here, but having it here shortens the include trace in error messages.
Marco Polettif2895102016-01-30 13:38:37 +000021#include <fruit/impl/injection_errors.h>
Marco Polettia5289cf2015-03-15 10:42:03 +000022
Marco Polettif2895102016-01-30 13:38:37 +000023#include <fruit/component.h>
Marco Poletti97e36232014-08-24 10:55:28 +020024
Marco Polettia5f49d42014-06-29 10:41:12 +010025namespace fruit {
Marco Polettia5f49d42014-06-29 10:41:12 +010026
Marco Poletti9250dea2014-11-09 09:10:53 +000027/**
28 * A Provider is a class that allows access to instances of the types used as parameters of the Provider template.
29 * It's possible to inject a Provider<MyClass> instead of MyClass itself, and this allows lazy injection.
30 * For example:
31 *
32 * class S {
33 * private:
34 * Bar* bar = nullptr;
35 *
36 * public:
37 * INJECT(S(Foo* foo, Provider<Bar> barProvider)) {
38 * if (foo->needsBar()) {
39 * bar = barProvider.get();
40 * }
41 * }
42 * };
43 *
44 * In the example above, Bar will only be created if get<Bar*> is called.
45 * This can be useful if Bar is expensive to create (or some other types that need to be injected when a Bar is injected are)
46 * or if there are other side effects of the Bar constructor that are undesirable when !foo->needsBar().
47 * It's also possible to store the Provider object in a field, and create the Bar instance when the first method that needs it is
48 * called:
49 *
50 * class S {
51 * private:
52 * Provider<Bar> barProvider;
53 *
54 * public:
55 * INJECT(S(Provider<Bar> barProvider))
56 * : barProvider(barProvider) {
57 * }
58 *
59 * void execute() {
60 * if (...) {
61 * Bar* bar = barProvider.get();
62 * ...
63 * }
64 * }
65 * };
66 *
67 * As usual, Fruit ensures that (at most) one instance is ever created in a given injector, so if the Bar object was already
68 * constructed, the get() will simply return it.
69 */
70template <typename C>
Marco Polettia5f49d42014-06-29 10:41:12 +010071class Provider {
Marco Poletti4406e322014-10-04 10:53:59 +010072public:
Marco Poletti9250dea2014-11-09 09:10:53 +000073
74 // Equivalent to get<C*>().
75 C* get();
76
Marco Poletti4406e322014-10-04 10:53:59 +010077 /**
Marco Poletti9250dea2014-11-09 09:10:53 +000078 * Returns an instance of the specified type. The following variations are allowed:
Marco Poletti4406e322014-10-04 10:53:59 +010079 *
80 * get<C>()
81 * get<C*>()
82 * get<C&>()
83 * get<const C*>()
84 * get<const C&>()
85 * get<shared_ptr<C>>()
86 *
87 * The shared_ptr version comes with a slight performance hit, avoid it if possible.
Marco Polettia185d5e2014-11-08 09:00:35 +000088 * Calling get<> repeatedly for the same class with the same injector will return the same instance (except for the first
89 * variation above, that returns a value; in that case, another copy of the same instance will be returned).
Marco Poletti4406e322014-10-04 10:53:59 +010090 */
91 template <typename T>
92 T get();
93
94 /**
95 * This is a convenient way to call get(). E.g.:
96 *
Marco Poletti9250dea2014-11-09 09:10:53 +000097 * C& x(injector);
Marco Poletti4406e322014-10-04 10:53:59 +010098 *
99 * is equivalent to:
100 *
Marco Poletti9250dea2014-11-09 09:10:53 +0000101 * C& x = injector.get<C&>();
Marco Poletti4406e322014-10-04 10:53:59 +0100102 */
103 template <typename T>
104 explicit operator T();
105
Marco Polettia5f49d42014-06-29 10:41:12 +0100106private:
Marco Poletti3b95a512015-07-11 13:43:39 +0100107 using Check1 = typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(fruit::impl::meta::Type<C>)>>::type;
Marco Poletti43637ba2015-03-07 19:45:41 +0000108 // Force instantiation of Check1.
109 static_assert(true || sizeof(Check1), "");
Marco Polettia5f49d42014-06-29 10:41:12 +0100110
Marco Poletti3b95a512015-07-11 13:43:39 +0100111 using Check2 = typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNotAnnotatedTypes(fruit::impl::meta::Type<C>)>>::type;
Marco Polettie4647132015-05-31 14:35:27 +0100112 // Force instantiation of Check2.
113 static_assert(true || sizeof(Check2), "");
114
Marco Polettia5f49d42014-06-29 10:41:12 +0100115 // This is NOT owned by the provider object. It is not deleted on destruction.
116 // This is never nullptr.
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100117 fruit::impl::InjectorStorage* storage;
Marco Poletti934689f2014-11-16 14:28:16 +0000118 fruit::impl::InjectorStorage::Graph::node_iterator itr;
Marco Polettia5f49d42014-06-29 10:41:12 +0100119
Marco Poletti934689f2014-11-16 14:28:16 +0000120 Provider(fruit::impl::InjectorStorage* storage, fruit::impl::InjectorStorage::Graph::node_iterator itr);
Marco Polettia5f49d42014-06-29 10:41:12 +0100121
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100122 friend class fruit::impl::InjectorStorage;
Marco Polettia5f49d42014-06-29 10:41:12 +0100123
Marco Poletti9250dea2014-11-09 09:10:53 +0000124 template <typename T>
Marco Polettifdc79902017-05-21 13:27:57 +0100125 friend struct fruit::impl::GetFirstStage;
126
Marco Polettia5f49d42014-06-29 10:41:12 +0100127 template <typename... OtherPs>
128 friend class Injector;
Marco Polettia5f49d42014-06-29 10:41:12 +0100129};
130
131} // namespace fruit
132
Marco Polettif2895102016-01-30 13:38:37 +0000133#include <fruit/impl/provider.defn.h>
Marco Polettia5f49d42014-06-29 10:41:12 +0100134
135#endif // FRUIT_PROVIDER_H