blob: 7b8f82cd3debe87cfa0827dca7e230f1309df1bc [file] [log] [blame]
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FRUIT_PROVIDER_H
#define FRUIT_PROVIDER_H
// This include is not required here, but having it here shortens the include trace in error messages.
#include <fruit/impl/injection_errors.h>
#include <fruit/component.h>
namespace fruit {
/**
* A Provider is a class that allows access to instances of the types used as parameters of the Provider template.
* It's possible to inject a Provider<MyClass> instead of MyClass itself, and this allows lazy injection.
* For example:
*
* class S {
* private:
* Bar* bar = nullptr;
*
* public:
* INJECT(S(Foo* foo, Provider<Bar> barProvider)) {
* if (foo->needsBar()) {
* bar = barProvider.get();
* }
* }
* };
*
* In the example above, Bar will only be created if get<Bar*> is called.
* 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)
* or if there are other side effects of the Bar constructor that are undesirable when !foo->needsBar().
* 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
* called:
*
* class S {
* private:
* Provider<Bar> barProvider;
*
* public:
* INJECT(S(Provider<Bar> barProvider))
* : barProvider(barProvider) {
* }
*
* void execute() {
* if (...) {
* Bar* bar = barProvider.get();
* ...
* }
* }
* };
*
* As usual, Fruit ensures that (at most) one instance is ever created in a given injector, so if the Bar object was already
* constructed, the get() will simply return it.
*/
template <typename C>
class Provider {
public:
// Equivalent to get<C*>().
C* get();
/**
* Returns an instance of the specified type. The following variations are allowed:
*
* get<C>()
* get<C*>()
* get<C&>()
* get<const C*>()
* get<const C&>()
* get<shared_ptr<C>>()
*
* The shared_ptr version comes with a slight performance hit, avoid it if possible.
* Calling get<> repeatedly for the same class with the same injector will return the same instance (except for the first
* variation above, that returns a value; in that case, another copy of the same instance will be returned).
*/
template <typename T>
T get();
/**
* This is a convenient way to call get(). E.g.:
*
* C& x(injector);
*
* is equivalent to:
*
* C& x = injector.get<C&>();
*/
template <typename T>
explicit operator T();
private:
using Check1 = typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(fruit::impl::meta::Type<C>)>>::type;
// Force instantiation of Check1.
static_assert(true || sizeof(Check1), "");
using Check2 = typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNotAnnotatedTypes(fruit::impl::meta::Type<C>)>>::type;
// Force instantiation of Check2.
static_assert(true || sizeof(Check2), "");
// This is NOT owned by the provider object. It is not deleted on destruction.
// This is never nullptr.
fruit::impl::InjectorStorage* storage;
fruit::impl::InjectorStorage::Graph::node_iterator itr;
Provider(fruit::impl::InjectorStorage* storage, fruit::impl::InjectorStorage::Graph::node_iterator itr);
friend class fruit::impl::InjectorStorage;
template <typename T>
friend struct fruit::impl::GetFirstStage;
template <typename... OtherPs>
friend class Injector;
};
} // namespace fruit
#include <fruit/impl/provider.defn.h>
#endif // FRUIT_PROVIDER_H