Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 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_PROVIDER_H |
| 18 | #define FRUIT_PROVIDER_H |
| 19 | |
Marco Poletti | a5289cf | 2015-03-15 10:42:03 +0000 | [diff] [blame] | 20 | // This include is not required here, but having it here shortens the include trace in error messages. |
| 21 | #include "impl/injection_errors.h" |
| 22 | |
Marco Poletti | 97e3623 | 2014-08-24 10:55:28 +0200 | [diff] [blame] | 23 | #include "component.h" |
| 24 | |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 25 | namespace fruit { |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 26 | |
Marco Poletti | 9250dea | 2014-11-09 09:10:53 +0000 | [diff] [blame] | 27 | /** |
| 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 | */ |
| 70 | template <typename C> |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 71 | class Provider { |
Marco Poletti | 4406e32 | 2014-10-04 10:53:59 +0100 | [diff] [blame] | 72 | public: |
Marco Poletti | 9250dea | 2014-11-09 09:10:53 +0000 | [diff] [blame] | 73 | |
| 74 | // Equivalent to get<C*>(). |
| 75 | C* get(); |
| 76 | |
Marco Poletti | 4406e32 | 2014-10-04 10:53:59 +0100 | [diff] [blame] | 77 | /** |
Marco Poletti | 9250dea | 2014-11-09 09:10:53 +0000 | [diff] [blame] | 78 | * Returns an instance of the specified type. The following variations are allowed: |
Marco Poletti | 4406e32 | 2014-10-04 10:53:59 +0100 | [diff] [blame] | 79 | * |
| 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 Poletti | a185d5e | 2014-11-08 09:00:35 +0000 | [diff] [blame] | 88 | * 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 Poletti | 4406e32 | 2014-10-04 10:53:59 +0100 | [diff] [blame] | 90 | */ |
| 91 | template <typename T> |
| 92 | T get(); |
| 93 | |
| 94 | /** |
| 95 | * This is a convenient way to call get(). E.g.: |
| 96 | * |
Marco Poletti | 9250dea | 2014-11-09 09:10:53 +0000 | [diff] [blame] | 97 | * C& x(injector); |
Marco Poletti | 4406e32 | 2014-10-04 10:53:59 +0100 | [diff] [blame] | 98 | * |
| 99 | * is equivalent to: |
| 100 | * |
Marco Poletti | 9250dea | 2014-11-09 09:10:53 +0000 | [diff] [blame] | 101 | * C& x = injector.get<C&>(); |
Marco Poletti | 4406e32 | 2014-10-04 10:53:59 +0100 | [diff] [blame] | 102 | */ |
| 103 | template <typename T> |
| 104 | explicit operator T(); |
| 105 | |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 106 | private: |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame^] | 107 | using Check1 = typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(fruit::impl::meta::Type<C>)>>::type; |
Marco Poletti | 43637ba | 2015-03-07 19:45:41 +0000 | [diff] [blame] | 108 | // Force instantiation of Check1. |
| 109 | static_assert(true || sizeof(Check1), ""); |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 110 | |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame^] | 111 | using Check2 = typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNotAnnotatedTypes(fruit::impl::meta::Type<C>)>>::type; |
Marco Poletti | e464713 | 2015-05-31 14:35:27 +0100 | [diff] [blame] | 112 | // Force instantiation of Check2. |
| 113 | static_assert(true || sizeof(Check2), ""); |
| 114 | |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 115 | // This is NOT owned by the provider object. It is not deleted on destruction. |
| 116 | // This is never nullptr. |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 117 | fruit::impl::InjectorStorage* storage; |
Marco Poletti | 934689f | 2014-11-16 14:28:16 +0000 | [diff] [blame] | 118 | fruit::impl::InjectorStorage::Graph::node_iterator itr; |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 119 | |
Marco Poletti | 934689f | 2014-11-16 14:28:16 +0000 | [diff] [blame] | 120 | Provider(fruit::impl::InjectorStorage* storage, fruit::impl::InjectorStorage::Graph::node_iterator itr); |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 121 | |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 122 | friend class fruit::impl::InjectorStorage; |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 123 | |
Marco Poletti | 9250dea | 2014-11-09 09:10:53 +0000 | [diff] [blame] | 124 | template <typename T> |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 125 | friend struct fruit::impl::GetHelper; |
| 126 | |
| 127 | template <typename... OtherPs> |
| 128 | friend class Injector; |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 129 | }; |
| 130 | |
| 131 | } // namespace fruit |
| 132 | |
Marco Poletti | 7f35b65 | 2014-11-01 10:11:37 +0000 | [diff] [blame] | 133 | #include "impl/provider.defn.h" |
Marco Poletti | a5f49d4 | 2014-06-29 10:41:12 +0100 | [diff] [blame] | 134 | |
| 135 | #endif // FRUIT_PROVIDER_H |