blob: 5f37262d897568b78317f702239d2e5de7133109 [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_COMPONENT_H
#define FRUIT_COMPONENT_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/fruit_forward_decls.h>
#include <fruit/impl/bindings.h>
#include <fruit/impl/meta/component.h>
#include <fruit/impl/storage/component_storage.h>
#include <fruit/impl/storage/partial_component_storage.h>
#include <fruit/impl/component_functors.defn.h>
namespace fruit {
/**
* The parameters can be of the form <P...> or <Required<R...>, P...> where:
* * R... are the required types (types required to inject some types in P... but that are not provided by this Component), if any
* * P... are the types provided by this Component.
* No type can appear twice, not even once in R and once in P.
*
* See PartialComponent below for the methods available in this class.
*/
template<typename... Params>
class Component {
public:
Component(Component &&) = default;
Component(const Component &) = default;
Component &operator=(Component &&) = delete;
Component &operator=(const Component &) = delete;
/**
* Converts a PartialComponent to an arbitrary Component, auto-injecting the missing types (if
* any).
* This is usually called implicitly when returning a component from a function. See
* PartialComponent for an example.
*/
template<typename... Bindings>
Component(PartialComponent<Bindings...> component);
/**
* Conversion from an arbitrary Component.
* This is equivalent to the component returned by:
* Component<Params...>(createComponent().install(component))
* It's provided only for convenience.
*/
template<typename... OtherParams>
Component(Component<OtherParams...> component);
private:
// Do not use. Use fruit::createComponent() instead.
Component() = default;
template<typename... Types>
friend class Component;
template<typename... Bindings>
friend
class PartialComponent;
template<typename... OtherParams>
friend
class NormalizedComponent;
template<typename... OtherParams>
friend
class Injector;
template <typename... Bindings>
friend
class fruit::impl::PartialComponentStorage;
fruit::impl::ComponentStorage storage;
using Comp = fruit::impl::meta::Eval<fruit::impl::meta::ConstructComponentImpl(fruit::impl::meta::Type<Params>...)>;
using Check1 = typename fruit::impl::meta::CheckIfError<Comp>::type;
// Force instantiation of Check1.
static_assert(true || sizeof(Check1), "");
};
/**
* Constructs an empty component. Note that EmptyPartialComponent is a subclass of PartialComponent<> and has no additional methods,
* so see PartialComponent<> for the methods that you can call on an EmptyPartialComponent.
*
* Example usage:
*
* const fruit::Component<Foo>& getFooComponent() {
* static const fruit::Component<Foo> comp = fruit::createComponent()
* .install(getComponent1)
* .install(getComponent2)
* .bind<Foo, FooImpl>();
* return comp;
* }
*
* Since types are auto-injected when needed, just converting this to the desired component can suffice in some cases, e.g.:
*
* const fruit::Component<Foo>& getFooComponent() {
* static const fruit::Component<Foo> comp = fruit::createComponent();
* return comp;
* }
*
* This works if Foo has an Inject typedef or a constructor wrapped in INJECT.
*
* WARNING: the resulting component *must* be converted to a Component (unless an exception is thrown).
* If it isn't, Fruit will abort the program.
* Note that the return type of createComponent() is PartialComponent, not Component, so that too needs to be converted.
* Therefore, using auto to avoid mentioning the type of `comp' again will not work, since the type is PartialComponent and not Component.
*/
PartialComponent<> createComponent();
/**
* A partially constructed component.
*
* Client code should never write `PartialComponent'; always start the construction of a component with fruit::createComponent(),
* and end it by casting the PartialComponent to the desired Component (often done implicitly by returning a PartialComponent
* from a function that has Component<...> as the return type).
*
* The template parameter is used to propagate information about bound types, it is purely an implementation detail; users of the
* Fruit library can pretend that this class is not templated, in no case a specific template parameter is required. All methods
* of this class take `this' as &&, allowing to chain method invocations without declaring a variable of type PartialComponent.
*
* Example usage:
*
* fruit::Component<Foo> getFooComponent() {
* return fruit::createComponent()
* .install(getComponent1)
* .install(getComponent2)
* .bind<Foo, FooImpl>();
* }
*
* Note that no variable of type PartialComponent has been declared; this class should only be used for temporary values.
*/
template<typename... Bindings>
class PartialComponent {
public:
PartialComponent(PartialComponent &&) = default;
PartialComponent &operator=(PartialComponent &&) = delete;
PartialComponent &operator=(const PartialComponent &) = delete;
/**
* Binds the base class (typically, an interface or abstract class) I to the implementation C.
*
* This supports annotated injection, just wrap I and/or C in fruit::Annotated<> if desired.
*/
template<typename I, typename C>
PartialComponent<fruit::impl::Bind<I, C>, Bindings...> bind();
/**
* Registers Signature as the constructor signature to use to inject a type.
*
* Example usage:
*
* fruit::createComponent()
* .registerConstructor<Foo(Bar*,Baz*)>() // Registers the constructor Foo::Foo(Bar*,Baz*)
*
* It's usually more convenient to use an INJECT macro or Inject typedef instead, e.g.:
*
* class Foo {
* public:
* // This also declares the constructor
* INJECT(Foo(Bar* bar, Baz* baz));
* ...
* };
*
* or (equivalent):
*
* class Foo {
* public:
* using Inject = Foo(Bar*, Baz*);
* Foo(Bar* bar, Baz* baz);
* ...
* };
*
* Use registerConstructor() when you want to inject the class C in different ways in different components (just make sure those
* don't end up in the same injector), or when C is a third-party class that can't be modified.
*
* This supports annotated injection, just wrap the desired types (return type and/or argument types of the signature)
* with fruit::Annotated<> if desired.
*/
template<typename Signature>
PartialComponent<fruit::impl::RegisterConstructor<Signature>, Bindings...> registerConstructor();
/**
* Use this method to bind the type C to a specific instance.
* The caller must ensure that the provided reference is valid for the entire lifetime of the component and of any components
* or injectors that install this component; the caller must also ensure that the object is destroyed after the last
* components/injectors using it are destroyed.
*
* Example usage:
*
* NormalizedComponent<...> normalizedComponent = ...;
* Request request;
* Injector<...> injector(normalizedComponent,
* Component<Request>(fruit::createComponent()
* .bindInstance(request)));
*
* This should be used sparingly (let Fruit handle the object lifetime when possible), but in some cases it is necessary; for
* example, if a web server creates an injector to handle each request, this method can be used to inject the request itself.
*/
template<typename C>
PartialComponent<fruit::impl::BindInstance<C, C>, Bindings...> bindInstance(C &instance);
/**
* Similar to the previous version of bindInstance(), but allows to specify an annotated type that
* will be bound to the specified value.
* For example, to bind an instance to the type Annotated<Hostname, std::string>, you can use:
*
* fruit::createComponent()
* .bindInstance<fruit::Annotated<Hostname, std::string>>(hostname)
*/
template<typename AnnotatedType, typename C>
PartialComponent<fruit::impl::BindInstance<AnnotatedType, C>, Bindings...> bindInstance(C &instance);
/**
* Registers `provider' as a provider of C, where provider is a lambda with no captures returning either C or C* (prefer
* returning a C by value instead of allocating a C using `new C', to avoid the allocation).
*
* When injecting a C, the arguments of the provider will be injected and the provider will then be called to create the
* C instance, that will then be stored in the injector.
*
* If `provider' returns a pointer, it must be non-null; otherwise the program will abort.
*
* Example:
*
* registerProvider([](Bar* bar, Baz* baz) {
* Foo foo(bar, baz);
* foo.initialize();
* return std::move(foo);
* })
*
* As in the previous example, it's not necessary to specify the type parameter, it will be inferred by the compiler.
*
* registerProvider() can't be called with a plain function, but you can write a lambda that wraps the function to achieve the
* same result.
*
* Registering a stateful functors (including lambdas with captures) is NOT supported.
* However, you can write something like:
*
* struct Functor {
* Functor(int n) {...}
* MyClass operator()(Foo* foo) {...}
* };
*
* Component<MyClass> getMyClassComponent() {
* static const Functor aFunctor(42);
* return fruit::createComponent()
* ... // Bind Foo
* .bindInstance(aFunctor)
* .registerProvider([](Functor functor, Foo* foo) { return functor(foo); });
* }
*/
template<typename Lambda>
PartialComponent<fruit::impl::RegisterProvider<Lambda>, Bindings...> registerProvider(Lambda lambda);
/**
* Similar to the previous version of registerProvider(), but allows to specify an annotated type
* for the provider. This allows to inject annotated types in the parameters and/or bind the
* provider to an annotated type. For example:
*
* .registerProvider<Annotated<MyAnnotation, Foo>(Annotated<SomeOtherAnnotation, Bar*>, Baz*)>(
* [](Bar* bar, Baz* baz) {
* Foo foo(bar, baz);
* foo.initialize();
* return std::move(foo);
* })
*
* Binds the type Foo (annotated with MyAnnotation) and injects the Bar annotated with
* SomeOtherAnnotation as the first parameter of the lambda.
*/
template<typename AnnotatedSignature, typename Lambda>
PartialComponent<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>, Bindings...> registerProvider(Lambda lambda);
/**
* Similar to bind<I, C>(), but adds a multibinding instead.
*
* Multibindings are independent from bindings; creating a binding with bind doesn't count as a multibinding, and adding a
* multibinding doesn't allow to inject the type (it only allows to retrieve multibindings through the getMultibindings method
* of the injector).
*
* Unlike bindings, where adding a the same binding twice is allowed (and ignored), adding the same multibinding multiple times
* will result in the creation of multiple "equivalent" instances, that will all be returned by getMultibindings().
* It is good practice to add the multibindings in a component that is "close" to the injector, to avoid installing that
* component more than once.
*
* This supports annotated injection, just wrap I and/or C in fruit::Annotated<> if desired.
*/
template<typename I, typename C>
PartialComponent<fruit::impl::AddMultibinding<I, C>, Bindings...> addMultibinding();
/**
* Similar to bindInstance(), but adds a multibinding instead.
*
* Multibindings are independent from bindings; creating a binding with bindInstance doesn't count as a
* multibinding, and adding a multibinding doesn't allow to inject the type (only allows to retrieve
* multibindings through the getMultibindings method of the injector).
*
* Unlike bindings, where adding a the same binding twice is allowed (and ignored), adding several multibindings for the same
* instance will result in duplicated values in the result of getMultibindings.
* It is good practice to add the multibindings in a component that is "close" to the injector, to avoid installing that
* component more than once.
*
* This method adds a multibinding for C. If the object implements an interface I and you want to add a multibinding
* for that interface instead, cast the object to I& before calling this.
*
* Note that this takes the instance by reference, not by value; it must remain valid for the entire lifetime of this component
* and of any injectors created from this component.
*/
template<typename C>
PartialComponent<fruit::impl::AddInstanceMultibinding<C>, Bindings...> addInstanceMultibinding(C &instance);
/**
* Similar to the previous version of addInstanceMultibinding(), but allows to specify an
* annotated type.
* Example use:
*
* createComponent()
* // With someObject of type MyClass
* .addInstanceMultibinding<Annotated<MyAnnotation, MyClass>>(someObject)
*/
template<typename AnnotatedC, typename C>
PartialComponent<fruit::impl::AddInstanceMultibinding<AnnotatedC>, Bindings...> addInstanceMultibinding(C &instance);
/**
* Equivalent to calling addInstanceMultibinding() for each elements of `instances'.
* See the documentation of addInstanceMultibinding() for more details.
*
* Note that this takes the vector by reference, not by value; the vector (and its elements) must remain valid for the entire
* lifetime of this component and of any injectors created from this component.
*/
template<typename C>
PartialComponent<fruit::impl::AddInstanceVectorMultibindings<C>, Bindings...> addInstanceMultibindings(std::vector<C> &instances);
/**
* Similar to the previous version of addInstanceMultibindings(), but allows to specify an
* annotated type.
* Example use:
*
* createComponent()
* // With v of type std::vector<MyClass>
* .addInstanceMultibindings<Annotated<MyAnnotation, MyClass>>(v)
*/
template<typename AnnotatedC, typename C>
PartialComponent<fruit::impl::AddInstanceVectorMultibindings<AnnotatedC>, Bindings...> addInstanceMultibindings(std::vector<C> &instance);
/**
* Similar to registerProvider, but adds a multibinding instead.
*
* Multibindings are independent from bindings; creating a binding with registerProvider doesn't count as a
* multibinding, and adding a multibinding doesn't allow to inject the type (only allows to retrieve multibindings
* through the getMultibindings method of the injector).
*
* Unlike bindings, where adding a the same binding twice is allowed (and ignored), adding the same multibinding provider
* multiple times will result in the creation of multiple "equivalent" instances, that will all be returned by getMultibindings.
* It is good practice to add the multibindings in a component that is "close" to the injector in the get*Component call chain,
* to avoid adding the same multibinding more than once.
*
* Note that this method adds a multibinding for the type returned by the provider. If the returned object implements an
* interface I and you want to add a multibinding for that interface instead, return a pointer casted to I*.
*/
template<typename Lambda>
PartialComponent<fruit::impl::AddMultibindingProvider<Lambda>, Bindings...> addMultibindingProvider(Lambda lambda);
/**
* Similar to the previous version of addMultibindingProvider(), but allows to specify an annotated type
* for the provider. This allows to inject annotated types in the parameters and/or bind the
* provider to an annotated type. For example:
*
* .addMultibindingProvider<Annotated<MyAnnotation, Foo>(Annotated<SomeOtherAnnotation, Bar*>, Baz*)>(
* [](Bar* bar, Baz* baz) {
* Foo foo(bar, baz);
* foo.initialize();
* return std::move(foo);
* })
*
* Add a multibinding for the type Foo (annotated with MyAnnotation) and injects the Bar annotated with
* SomeOtherAnnotation as the first parameter of the lambda.
*/
template<typename AnnotatedSignature, typename Lambda>
PartialComponent<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>, Bindings...> addMultibindingProvider(Lambda lambda);
/**
* Registers `factory' as a factory of C, where `factory' is a lambda with no captures returning C.
* This is typically used for assisted injection (but can also be used if no parameters are assisted).
*
* C can be any class type. If C is std::unique_ptr<T>, the factory together with a bind<I,C> in the same component
* will automatically bind the corresponding std::function that returns a std::unique_ptr<I>.
*
* C can NOT be a pointer type. If you don't want to return by value, return a std::unique_ptr instead of a naked pointer.
*
* Example:
*
* Component<std::function<std::unique_ptr<MyClass>(int)>> getMyClassComponent() {
* fruit::createComponent()
* ... // Bind Foo
* .registerFactory<std::unique_ptr<MyClass>(Foo*, Assisted<int>)>(
* [](Foo* foo, int n) {
* return std::unique_ptr<MyClass>(new MyClass(foo, n));
* });
* }
*
* and then, e.g. in main():
*
* Injector<std::function<std::unique_ptr<MyClass>(int)>> injector(getMyClassComponent());
*
* std::function<std::unique_ptr<MyClass>(int)> factory(injector);
* std::unique_ptr<MyClass> x = factory(42);
*
* Note that non-assisted parameters will be passed automatically by Fruit.
*
* Unlike registerProvider(), where the signature is inferred, for this method the signature (including any Assisted
* annotations) must be specified explicitly, while the second template parameter is inferred.
*
* If the only thing that the factory does is to call new and the constructor of the class, it's usually more convenient to use
* an Inject typedef or INJECT macro instead, e.g. the following are equivalent to the above:
*
* class MyClass {
* public:
* using Inject = MyClass(Foo*, Assisted<int>);
*
* MyClass(Foo* foo, int n) {...}
* };
*
* or:
*
* class MyClass {
* public:
* INJECT(MyClass(Foo* foo, ASSISTED(int) n) {...}
* };
*
* Use registerFactory() when you want to inject the class in different ways in different components (just make sure those
* don't end up in the same injector), or when MyClass is a third-party class that can't be modified.
*
* registerFactory() can't be called with a plain function, but you can write a lambda that wraps the function to achieve the
* same result.
*
* Registering stateful functors (including lambdas with captures) is NOT supported.
* However, you can write something like:
*
* struct Functor {
* Functor(float x) {...}
* std::unique_ptr<MyClass> operator()(Foo* foo, int n) {...}
* };
*
* Component<std::function<std::unique_ptr<MyClass>(int)>> getMyClassComponent() {
* static const Functor aFunctor(42.0);
* return fruit::createComponent()
* ... // Bind Foo
* .bindInstance(aFunctor)
* .registerFactory<std::unique_ptr<MyClass>(Functor functor, Foo*, Assisted<int>)>(
* [](Functor* functor, Foo* foo, int n) { return functor(foo, n); });
* }
*/
template<typename DecoratedSignature, typename Factory>
PartialComponent<fruit::impl::RegisterFactory<DecoratedSignature, Factory>, Bindings...> registerFactory(Factory factory);
/**
* Adds the bindings (and multibindings) in `component' to the current component.
*
* Example usage:
*
* createComponent()
* .install(getComponent1)
* .install(getComponent2)
*
* As in the example, the template parameters will be inferred by the compiler, it's not necessary to specify them explicitly.
*/
template<typename... Params>
FRUIT_DEPRECATED(
PartialComponent<fruit::impl::OldStyleInstallComponent<Component<Params...>>, Bindings...>
install(const Component<Params...>& component)
);
/**
* Adds the bindings (and multibindings) in the Component obtained by calling fun(params...) to the current component.
*
* For example, these components:
* Component<Foo> getComponent1();
* Component<Bar> getComponent2(int n, std::string s);
*
* can be installed as:
*
* createComponent()
* // equivalent to install(getComponent1())
* .install(getComponent1)
* // equivalent to install(getComponent2(5, std::string("Hello"))
* .install(getComponent2, 5, std::string("Hello"))
*
* If any `args` are provided, they must be:
* - Copy-constructible
* - Move-constructible
* - Assignable
* - Move-assignable
* - Equality comparable (i.e., operator== must be defined for two values of that type)
* - Hashable (i.e., std::hash must be defined for values of that type)
*
* Note that this only applies to `args`. E.g. in the example above `int` and `std::string` must satisfy this
* requirement (and they do), but `Foo` and `Bar` don't need to.
*
* A lambda with no captures can also be used as the first argument, for example:
*
* createComponent()
* .install([]() {return getComponent1();})
* .install([](int n, std::string s) {return getComponent2(n, s);}, 5, std::string("Hello"))
*
* These two install() calls are equivalent to the previous ones.
*
* As in the example, the template parameters for this method will be inferred by the compiler, it's not necessary to
* specify them explicitly.
*/
template <typename OtherComponent, typename... Args>
PartialComponent<fruit::impl::InstallComponent<OtherComponent, Args...>, Bindings...> install(
OtherComponent(*)(Args...),
Args... args);
~PartialComponent();
private:
template<typename... OtherBindings>
friend class PartialComponent;
template<typename... Types>
friend class Component;
fruit::impl::PartialComponentStorage<Bindings...> storage;
// Do not use. Use fruit::createComponent() instead.
PartialComponent() = delete;
// Do not use. Only use PartialComponent for temporaries, and then convert it to a Component.
PartialComponent(const PartialComponent &) = delete;
PartialComponent(fruit::impl::PartialComponentStorage<Bindings...> storage);
template<typename NewBinding>
using OpFor = typename fruit::impl::meta::OpForComponent<Bindings...>::template AddBinding<NewBinding>;
friend PartialComponent<> createComponent();
};
} // namespace fruit
#include <fruit/impl/component.defn.h>
#endif // FRUIT_COMPONENT_H