You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1083 lines
44 KiB
1083 lines
44 KiB
/*
|
|
* 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/component_functors.defn.h>
|
|
#include <fruit/impl/component_storage/component_storage.h>
|
|
#include <fruit/impl/component_storage/partial_component_storage.h>
|
|
#include <fruit/impl/meta/component.h>
|
|
|
|
namespace fruit {
|
|
|
|
/**
|
|
* A component (aka module) represents a collection of bindings.
|
|
* You can think of a Component object as a UML component.
|
|
*
|
|
* 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 how to construct a Component.
|
|
*/
|
|
template <typename... Params>
|
|
class Component {
|
|
public:
|
|
Component(Component&&) noexcept = 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) noexcept; // NOLINT(google-explicit-constructor)
|
|
|
|
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;
|
|
|
|
template <typename Component, typename... Args>
|
|
friend class fruit::impl::LazyComponentImpl;
|
|
|
|
friend struct fruit::impl::ComponentStorageEntry::LazyComponentWithNoArgs;
|
|
|
|
template <typename Component, typename... Args>
|
|
friend class fruit::impl::ComponentInterfaceImpl;
|
|
|
|
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.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* fruit::Component<Foo> getFooComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getComponent1)
|
|
* .install(getComponent2)
|
|
* .bind<Foo, FooImpl>();
|
|
* }
|
|
*
|
|
* Since types are auto-injected when needed, just converting this to the desired component can suffice in some cases,
|
|
* e.g.:
|
|
*
|
|
* fruit::Component<Foo> getFooComponent() {
|
|
* return fruit::createComponent();
|
|
* }
|
|
*
|
|
* That works if Foo has an Inject typedef or a constructor wrapped in INJECT.
|
|
*/
|
|
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 return a PartialComponent, which allows 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& operator=(PartialComponent&&) = delete;
|
|
PartialComponent& operator=(const PartialComponent&) = delete;
|
|
|
|
/**
|
|
* This tells Fruit that "the implementation of I is C".
|
|
* I must be a base class of C, and it's typically (but not necessarily) an abstract class.
|
|
* C is typically a concrete class, but it doesn't have to be: for example, if A inherits from B and B inherits from C
|
|
* you can specify bind<C, B>() and bind<B, A>().
|
|
*
|
|
* The most common use of this is to bind the type I to the type C, for example:
|
|
*
|
|
* class MyInterface {
|
|
* public:
|
|
* virtual void foo() = 0;
|
|
* };
|
|
*
|
|
* class MyImplementation {
|
|
* public:
|
|
* INJECT(MyImplementation()) {}
|
|
*
|
|
* void foo() {
|
|
* ...
|
|
* }
|
|
* };
|
|
*
|
|
* fruit::Component<MyInterface> getMyInterfaceComponent() {
|
|
* return fruit::createComponent()
|
|
* .bind<MyInterface, MyImplementation>();
|
|
* }
|
|
*
|
|
* The implementation class can be bound in any way, it doesn't need to be bound using constructor injection as above
|
|
* (although that's a very common use case).
|
|
*
|
|
* You can bind an interface to a type bound using a constant binding (see the bindInstance method that takes a const&
|
|
* for more details), however the interface will then also be considered bound with a constant binding, and you must
|
|
* declare that in the returned Component's type. For example:
|
|
*
|
|
* fruit::Component<const MyInterface> getMyInterfaceComponent() {
|
|
* static const MyImplementation my_implementation = MyImplementation();
|
|
* return fruit::createComponent()
|
|
* .bindInstance(my_implementation)
|
|
* .bind<MyInterface, MyImplementation>();
|
|
* }
|
|
*
|
|
* In addition to binding the type I to the type C, a `bind()` can also be used to bind a
|
|
* std::function<std::unique_ptr<I>(Args...)> to a std::function<std::unique_ptr<C>(Args...)> or a
|
|
* std::function<C(Args...)>. For example:
|
|
*
|
|
* fruit::Component<std::function<std::unique_ptr<MyInterface>(int)>> getIFactoryComponent() {
|
|
* static const std::function<MyImplementation(int)> cFactory = [](int n) { return MyImplementation(n); };
|
|
* return fruit::createComponent()
|
|
* .bind<MyInterface, MyImplementation>()
|
|
* .bindInstance(cFactory);
|
|
* }
|
|
*
|
|
* Or alternatively you can do the same using constructor injection:
|
|
*
|
|
* class MyImplementation {
|
|
* public:
|
|
* INJECT(MyImplementation(ASSISTED(int) n))
|
|
* : n(n) {
|
|
* }
|
|
* ...
|
|
* };
|
|
*
|
|
* fruit::Component<std::function<std::unique_ptr<MyInterface>(int)>> getIFactoryComponent() {
|
|
* return fruit::createComponent()
|
|
* .bind<MyInterface, MyImplementation>();
|
|
* }
|
|
*
|
|
* Fruit determines the actual binding(s) to generate based on the types you declare as provided in the returned
|
|
* Component<> type (e.g. in the last example std::function<std::unique_ptr<MyInterface>(int)> is declared as provided
|
|
* so Fruit will generate a factory binding instead of a normal MyInterface->MyImplementation binding.
|
|
*
|
|
* Fruit can also detect types that are needed for constructor/provider/factory bindings, and it will then use that
|
|
* information to determine the desired binding. For example:
|
|
*
|
|
* class MyImplementation {
|
|
* public:
|
|
* INJECT(MyImplementation(ASSISTED(int) n))
|
|
* : n(n) {
|
|
* }
|
|
* ...
|
|
* };
|
|
*
|
|
* class Foo {
|
|
* private:
|
|
* std::function<std::unique_ptr<MyInterface>(int)> factory;
|
|
* public:
|
|
* INJECT(Foo(std::function<std::unique_ptr<MyInterface>(int)> factory))
|
|
* : factory(factory) {
|
|
* }
|
|
* };
|
|
*
|
|
* fruit::Component<Foo> getIFactoryComponent() {
|
|
* return fruit::createComponent()
|
|
* // We want to bind Foo, which requires std::function<std::unique_ptr<MyInterface>(int)>.
|
|
* // So std::function<std::unique_ptr<MyInterface>(int)> will be bound to
|
|
* // std::function<std::unique_ptr<MyImplementation>(int)>, and that will be bound using constructor injection.
|
|
* .bind<MyInterface, MyImplementation>();
|
|
* }
|
|
*
|
|
* All these cases support annotated injection, just wrap I and/or C in fruit::Annotated<> if desired. For example:
|
|
*
|
|
* struct MyAnnotation{};
|
|
*
|
|
* fruit::Component<fruit::Annotated<MyAnnotation, MyInterface>> getMyInterfaceComponent() {
|
|
* return fruit::createComponent()
|
|
* .bind<fruit::Annotated<MyAnnotation, MyInterface>, MyImplementation>();
|
|
* }
|
|
*/
|
|
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 use annotated injection to prevent the bindings from clashing),
|
|
* 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. For example:
|
|
*
|
|
* struct Annotation1 {};
|
|
* struct Annotation2 {};
|
|
*
|
|
* struct Foo {
|
|
* Foo(Bar* bar) {...}
|
|
* };
|
|
*
|
|
* fruit::Component<fruit::Annotated<Annotation1, Bar>> getBarComponent() {...}
|
|
*
|
|
* fruit::Component<fruit::Annotated<Annotation2, Foo>> getFooComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getBarComponent)
|
|
* .registerConstructor<fruit::Annotated<Annotation2, Foo>(fruit::Annotated<Annotation1, Bar*>)>();
|
|
* }
|
|
*
|
|
* This does *not* support assisted injection, for that you should use registerFactory() instead.
|
|
*
|
|
* The allowed argument types in the signature are, for any class (or fundamental) type C:
|
|
*
|
|
* C
|
|
* C*
|
|
* C&
|
|
* const C*
|
|
* const C&
|
|
* shared_ptr<C>
|
|
* Provider<C>
|
|
* Provider<const C>
|
|
* Annotated<Annotation, C> (for any type `Annotation')
|
|
* Annotated<Annotation, C*> (for any type `Annotation')
|
|
* Annotated<Annotation, C&> (for any type `Annotation')
|
|
* Annotated<Annotation, const C*> (for any type `Annotation')
|
|
* Annotated<Annotation, const C&> (for any type `Annotation')
|
|
* Annotated<Annotation, shared_ptr<C>> (for any type `Annotation')
|
|
* Annotated<Annotation, Provider<C>> (for any type `Annotation')
|
|
* Annotated<Annotation, Provider<const C>> (for any type `Annotation')
|
|
*/
|
|
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:
|
|
*
|
|
* Component<Request> getRequestComponent(Request* request) {
|
|
* return fruit::createComponent()
|
|
* .bindInstance(*request);
|
|
* }
|
|
*
|
|
* NormalizedComponent<...> normalizedComponent = ...;
|
|
* Request request;
|
|
* Injector<...> injector(normalizedComponent,
|
|
* getRequestComponent,
|
|
* request));
|
|
*
|
|
* This should be used sparingly (you should 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 as in the example above (see the Server page in the Fruit tutorial for more details).
|
|
*
|
|
* It's also possible to bind constants, see the documentation of the bindInstance() method taking a const& for
|
|
* details.
|
|
*/
|
|
template <typename C>
|
|
PartialComponent<fruit::impl::BindInstance<C, C>, Bindings...> bindInstance(C& instance);
|
|
|
|
/**
|
|
* Similar to the previous, but binds a const&. Note that the reference must still outlive the component/injector
|
|
* as in the non-const case.
|
|
* When using this method, you must declare that the type is constant in the Component type. For example:
|
|
*
|
|
* Component<const MyExpensiveClass> getMyExpensiveClassComponent() {
|
|
* static const MyExpensiveClass my_expensive_class = createMyExpensiveClass();
|
|
* return fruit::createComponent()
|
|
* .bindInstance(my_expensive_class);
|
|
* }
|
|
*
|
|
* Constant bindings can be used as other bindings, except that you can only inject the constant type (e.g. as a
|
|
* constructor parameter) as:
|
|
*
|
|
* C
|
|
* const C*
|
|
* const C&
|
|
* Provider<const C>
|
|
* Annotated<Annotation, C> (for any type `Annotation')
|
|
* Annotated<Annotation, const C*> (for any type `Annotation')
|
|
* Annotated<Annotation, const C&> (for any type `Annotation')
|
|
* Annotated<Annotation, Provider<const C>> (for any type `Annotation')
|
|
*
|
|
* While you can't inject it as:
|
|
*
|
|
* C*
|
|
* C&
|
|
* shared_ptr<C>
|
|
* Provider<C>
|
|
* Annotated<Annotation, C*> (for any type `Annotation')
|
|
* Annotated<Annotation, C&> (for any type `Annotation')
|
|
* Annotated<Annotation, shared_ptr<C>> (for any type `Annotation')
|
|
* Annotated<Annotation, Provider<C>> (for any type `Annotation')
|
|
*/
|
|
template <typename C>
|
|
PartialComponent<fruit::impl::BindConstInstance<C, C>, Bindings...> bindInstance(const C& instance);
|
|
|
|
/**
|
|
* This is deleted to catch cases where the instance would likely be destroyed before the component/injectors.
|
|
*/
|
|
template <typename C>
|
|
PartialComponent<fruit::impl::BindConstInstance<C, C>, Bindings...> bindInstance(C&&) = delete;
|
|
|
|
/**
|
|
* Similar to the first 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 fruit::Annotated<Hostname, std::string>, you can use:
|
|
*
|
|
* fruit::Component<fruit::Annotated<Hostname, std::string>> getHostnameComponent(std::string* hostname) {
|
|
* fruit::createComponent()
|
|
* .bindInstance<fruit::Annotated<Hostname, std::string>>(*hostname);
|
|
* }
|
|
*/
|
|
template <typename AnnotatedType, typename C>
|
|
PartialComponent<fruit::impl::BindInstance<AnnotatedType, C>, Bindings...> bindInstance(C& instance);
|
|
|
|
/**
|
|
* Similar to the previous, but binds a const&. Example usage:
|
|
*
|
|
* fruit::Component<fruit::Annotated<Hostname, const std::string>> getHostnameComponent() {
|
|
* static const std::string hostname = determineHostname();
|
|
* fruit::createComponent()
|
|
* .bindInstance<fruit::Annotated<Hostname, std::string>>(hostname);
|
|
* }
|
|
*
|
|
* See the documentation for the bindInstance() overload that takes a non-annotated const& for more details.
|
|
*/
|
|
template <typename AnnotatedType, typename C>
|
|
PartialComponent<fruit::impl::BindConstInstance<AnnotatedType, C>, Bindings...> bindInstance(const C& instance);
|
|
|
|
/**
|
|
* This is deleted to catch cases where the instance would likely be destroyed before the component/injectors.
|
|
*/
|
|
template <typename AnnotatedType, typename C>
|
|
PartialComponent<fruit::impl::BindConstInstance<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:
|
|
*
|
|
* fruit::Component<Foo> getFooComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getBarComponent)
|
|
* .install(getBazComponent)
|
|
* .registerProvider([](Bar* bar, Baz* baz) {
|
|
* Foo foo(bar, baz);
|
|
* foo.initialize();
|
|
* return 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 stateful functors (including lambdas with captures) is NOT supported.
|
|
* However, you can write something like:
|
|
*
|
|
* struct Functor {
|
|
* Functor(int n) {...}
|
|
* MyClass operator()(Foo* foo) const {...}
|
|
* };
|
|
*
|
|
* Component<MyClass> getMyClassComponent() {
|
|
* static const Functor aFunctor(42);
|
|
* return fruit::createComponent()
|
|
* .install(getFooComponent)
|
|
* .bindInstance(aFunctor)
|
|
* .registerProvider([](const 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:
|
|
*
|
|
* struct MyAnnotation1 {};
|
|
* struct MyAnnotation2 {};
|
|
*
|
|
* Component<fruit::Annotated<Annotation1, Bar>> getBarComponent() {...}
|
|
* Component<Baz> getBazComponent() {...}
|
|
*
|
|
* fruit::Component<fruit::Annotated<Annotation2, Foo>> getFooComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getBarComponent)
|
|
* .install(getBazComponent)
|
|
* .registerProvider<
|
|
* fruit::Annotated<Annotation2, Foo>(
|
|
* fruit::Annotated<Annotation1, Bar*>,
|
|
* Baz*)
|
|
* >([](Bar* bar, Baz* baz) {
|
|
* Foo foo(bar, baz);
|
|
* foo.initialize();
|
|
* return foo;
|
|
* });
|
|
* }
|
|
*/
|
|
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().
|
|
*
|
|
* Another difference compared with normal bindings is that this can't be used to bind a
|
|
* std::function<std::unique_ptr<I>(Args...)> to a std::function<std::unique_ptr<C>(Args...)> or a
|
|
* std::function<C(Args...)>.
|
|
*
|
|
* As bind(), this supports annotated injection, just wrap I and/or C in fruit::Annotated<> if desired. See the
|
|
* documentation of bind() for more details.
|
|
*/
|
|
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 (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 several multibindings for
|
|
* the same instance will result in duplicated values in the result of getMultibindings.
|
|
*
|
|
* Another difference compared to bindInstance() is that you can't use this to bind a const& (note that there is no
|
|
* overload of this method that takes a const&).
|
|
*
|
|
* 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, you must cast the object to I& before passing it to this method.
|
|
*
|
|
* 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.
|
|
*
|
|
* Example use:
|
|
*
|
|
* class MyClass {
|
|
* ...
|
|
* };
|
|
*
|
|
* fruit::Component<> getMyComponent() {
|
|
* static MyClass x = MyClass(...);
|
|
* static MyClass y = MyClass(...);
|
|
* return fruit::createComponent()
|
|
* .addInstanceMultibinding(x)
|
|
* .addInstanceMultibinding(y);
|
|
* }
|
|
*
|
|
* fruit::Injector<> injector(getMyComponent);
|
|
* // This vector contains {&x, &y}.
|
|
* const std::vector<MyClass*>& objects = injector.getMultibindings<MyClass>();
|
|
*/
|
|
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:
|
|
*
|
|
* struct MyAnnotation {};
|
|
*
|
|
* class MyClass {
|
|
* ...
|
|
* };
|
|
*
|
|
* fruit::Component<> getMyComponent() {
|
|
* static MyClass x = MyClass(...);
|
|
* static MyClass y = MyClass(...);
|
|
* return fruit::createComponent()
|
|
* .addInstanceMultibinding<fruit::Annotated<MyAnnotation, MyClass>>(x)
|
|
* .addInstanceMultibinding<fruit::Annotated<MyAnnotation, MyClass>>(y);
|
|
* }
|
|
*
|
|
* fruit::Injector<> injector(getMyComponent);
|
|
* // This vector contains {&x, &y}.
|
|
* const std::vector<MyClass*>& objects = injector.getMultibindings<fruit::Annotated<MyAnnotation, MyClass>>();
|
|
*/
|
|
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.
|
|
*
|
|
* Example use:
|
|
*
|
|
* class MyClass {
|
|
* ...
|
|
* };
|
|
*
|
|
* fruit::Component<> getMyComponent() {
|
|
* static MyClass x = MyClass(...);
|
|
* static std::vector<MyClass> other_objects{MyClass(...), MyClass(...)};
|
|
* return fruit::createComponent()
|
|
* .addInstanceMultibinding(x)
|
|
* .addInstanceMultibindings(other_objects);
|
|
* }
|
|
*
|
|
* fruit::Injector<> injector(getMyComponent);
|
|
* // This vector contains {&x, &(other_objects[0]), &(other_objects[1])}.
|
|
* const std::vector<MyClass*>& objects = injector.getMultibindings<MyClass>();
|
|
*/
|
|
template <typename C>
|
|
PartialComponent<fruit::impl::AddInstanceVectorMultibindings<C>, Bindings...>
|
|
addInstanceMultibindings(std::vector<C>& instances);
|
|
|
|
/**
|
|
* Similar to the previous version of addInstanceMultibindings(), but it allows to specify an annotated type.
|
|
*
|
|
* Example use:
|
|
*
|
|
* class MyClass {
|
|
* ...
|
|
* };
|
|
*
|
|
* fruit::Component<> getMyComponent() {
|
|
* static MyClass x = MyClass(...);
|
|
* static std::vector<MyClass> other_objects{MyClass(...), MyClass(...)};
|
|
* return fruit::createComponent()
|
|
* .addInstanceMultibinding<fruit::Annotated<MyAnnotation, MyClass>>(x)
|
|
* .addInstanceMultibindings<fruit::Annotated<MyAnnotation, MyClass>>(other_objects);
|
|
* }
|
|
*
|
|
* fruit::Injector<> injector(getMyComponent);
|
|
* // This vector contains {&x, &(other_objects[0]), &(other_objects[1])}.
|
|
* const std::vector<MyClass*>& objects = injector.getMultibindings<fruit::Annotated<MyAnnotation, MyClass>>();
|
|
*/
|
|
template <typename AnnotatedC, typename C>
|
|
PartialComponent<fruit::impl::AddInstanceVectorMultibindings<AnnotatedC>, Bindings...>
|
|
addInstanceMultibindings(std::vector<C>& instances);
|
|
|
|
/**
|
|
* 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 (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
|
|
* 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.
|
|
*
|
|
* Example use:
|
|
*
|
|
* class MyClass {
|
|
* public:
|
|
* MyClass(int n) {...}
|
|
* };
|
|
*
|
|
* fruit::Component<> getMyComponent() {
|
|
* return fruit::createComponent()
|
|
* .addMultibindingProvider([]() { return MyClass(10); })
|
|
* .addMultibindingProvider([]() { return MyClass(10); })
|
|
* .addMultibindingProvider([]() { return MyClass(20); });
|
|
* }
|
|
*
|
|
* fruit::Injector<> injector(getMyComponent);
|
|
* // This vector contains {&x, &y, &z} where x and y are MyClass objects constructed with 10 and z is a MyClass
|
|
* // object constructed with 20.
|
|
* const std::vector<MyClass*>& objects = injector.getMultibindings<MyClass>();
|
|
*
|
|
* 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, you should cast the pointer to I*
|
|
* before returning it.
|
|
*/
|
|
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.
|
|
*
|
|
* Example use:
|
|
*
|
|
* struct MyAnnotation1 {};
|
|
* struct MyAnnotation2 {};
|
|
*
|
|
* Component<fruit::Annotated<Annotation1, Bar>> getBarComponent() {...}
|
|
* Component<Baz> getBazComponent() {...}
|
|
*
|
|
* fruit::Component<> getFooComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getBarComponent)
|
|
* .install(getBazComponent)
|
|
* .registerMultibindingProvider<
|
|
* fruit::Annotated<Annotation2, Foo>(
|
|
* fruit::Annotated<Annotation1, Bar*>,
|
|
* Baz*)
|
|
* >([](Bar* bar, Baz* baz) {
|
|
* Foo foo(bar, baz);
|
|
* foo.initialize();
|
|
* return foo;
|
|
* });
|
|
* }
|
|
*
|
|
*
|
|
* fruit::Injector<> injector(getFooComponent);
|
|
* // This vector contains {&x} where x is an instance of Foo constructed using the lambda above, with injected
|
|
* // instances of Bar and Baz.
|
|
* const std::vector<MyClass*>& objects = injector.getMultibindings<fruit::Annotated<Annotation2, Foo>>();
|
|
*/
|
|
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 it can also be used if no parameters are assisted).
|
|
*
|
|
* C can be any class (or fundamental) 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>.
|
|
* See the documentation of bind() for more details.
|
|
*
|
|
* The returned type can't be a pointer type. If you don't want to return it by value, you should return a
|
|
* std::unique_ptr instead.
|
|
*
|
|
* Example:
|
|
*
|
|
* Component<std::function<std::unique_ptr<MyClass>(int)>> getMyClassComponent() {
|
|
* fruit::createComponent()
|
|
* .install(getFooComponent)
|
|
* .registerFactory<std::unique_ptr<MyClass>(Foo*, fruit::Assisted<int>)>(
|
|
* [](Foo* foo, int n) {
|
|
* return std::unique_ptr<MyClass>(new MyClass(foo, n));
|
|
* });
|
|
* }
|
|
*
|
|
* 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);
|
|
*
|
|
* The parameters marked as Assisted will become parameters of the std::function (in the same order), while the others
|
|
* (e.g. Foo in the example above) will be injected.
|
|
*
|
|
* 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 the Component obtained by calling fun(args...) to the current component.
|
|
*
|
|
* For example, these component functions:
|
|
* fruit::Component<Foo> getComponent1();
|
|
* fruit::Component<Bar> getComponent2(int n, std::string s);
|
|
*
|
|
* can be combined as:
|
|
*
|
|
* fruit::Component<Foo, Bar> getFooBarComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getComponent1)
|
|
* .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.
|
|
*
|
|
* Args and FormalArgs (if any) must be the same types; or to be precise, each type in Args must be convertible into
|
|
* the corresponding type in FormalArgs.
|
|
*
|
|
* A lambda with no captures can also be used as the first argument, for example:
|
|
*
|
|
* fruit::Component<Foo, Bar> getFooBarComponent() {
|
|
* return fruit::createComponent()
|
|
* .install([]() { return getComponent1(); })
|
|
* .install([](int n) { return getComponent2(n, std::string("Hello")); }, 5);
|
|
* }
|
|
*
|
|
* 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.
|
|
*
|
|
* Fruit automatically de-duplicates install() calls, so they're effectively memoized (within each injector).
|
|
* For example, in this code:
|
|
*
|
|
* fruit::Component<Foo> getFooComponent() {...}
|
|
*
|
|
* fruit::Component<Bar> getBarComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getFooComponent)
|
|
* .bind<Bar, BarImpl>();
|
|
* }
|
|
*
|
|
* fruit::Component<Baz> getBazComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getFooComponent)
|
|
* .bind<Baz, BazImpl>();
|
|
* }
|
|
*
|
|
* fruit::Component<Bar, Baz> getBarBazComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getBarComponent)
|
|
* .install(getBazComponent);
|
|
* }
|
|
*
|
|
* fruit::Injector<Bar, Baz> injector(getBarBazComponent);
|
|
*
|
|
*
|
|
* getFooComponent() will only be called once.
|
|
* For Component functions with arguments, only one call will be done for each set of arguments, but multiple calls
|
|
* might be made if multiple sets of arguments are used.
|
|
*
|
|
* If you actually want a Component function to be called/installed multiple times (e.g. if it binds a multibinding
|
|
* and you actually want multiple multibindings to be bound) you can add a dummy argument and specify different values
|
|
* for that argument when installing the component.
|
|
*/
|
|
template <typename... OtherComponentParams, typename... FormalArgs, typename... Args>
|
|
PartialComponent<fruit::impl::InstallComponent<fruit::Component<OtherComponentParams...>(FormalArgs...)>, Bindings...>
|
|
install(fruit::Component<OtherComponentParams...> (*)(FormalArgs...), Args&&... args);
|
|
|
|
/**
|
|
* Similar to install(), but allows to install a variable number of component functions instead of just 1. This
|
|
* additional flexibility is sometimes useful in templated `get*Component` functions and for other advanced use-cases.
|
|
*
|
|
* To use this method, wrap each get*Component function with its args in a fruit::ComponentFunction<...> object (using
|
|
* the helper function fruit::componentFunction), then pass all the fruit::ComponentFunction<...> objects (which can
|
|
* potentially have different params) to this method.
|
|
*
|
|
* For example:
|
|
*
|
|
* fruit::Component<Foo, Bar> getBarBazComponent() {
|
|
* return fruit::createComponent()
|
|
* .installComponentFunctions(
|
|
* fruit::componentFunction(getFooComponent, a, b, c),
|
|
* fruit::componentFunction(getBarComponent, x, y));
|
|
* }
|
|
*
|
|
* Is equivalent to:
|
|
*
|
|
* fruit::Component<Foo, Bar> getBarBazComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getFooComponent, a, b, c)
|
|
* .install(getBarComponent, x, y);
|
|
* }
|
|
*
|
|
* This is a simple example to show the idea, however in a simple case like this it's easier to just use install().
|
|
*/
|
|
template <typename... ComponentFunctions>
|
|
PartialComponent<fruit::impl::InstallComponentFunctions<ComponentFunctions...>, Bindings...>
|
|
installComponentFunctions(ComponentFunctions... componentFunctions);
|
|
|
|
/**
|
|
* This class is returned by PartialComponent::replace, see the documentation of that method for more information.
|
|
*/
|
|
template <typename ReplacedComponent, typename... GetReplacedComponentFormalArgs>
|
|
class PartialComponentWithReplacementInProgress {
|
|
private:
|
|
using storage_t = fruit::impl::PartialComponentStorage<
|
|
fruit::impl::PartialReplaceComponent<ReplacedComponent(GetReplacedComponentFormalArgs...)>, Bindings...>;
|
|
|
|
public:
|
|
template <typename... FormalArgs, typename... Args>
|
|
PartialComponent<fruit::impl::ReplaceComponent<ReplacedComponent(GetReplacedComponentFormalArgs...),
|
|
ReplacedComponent(FormalArgs...)>,
|
|
Bindings...>
|
|
with(ReplacedComponent (*)(FormalArgs...), Args&&... args);
|
|
|
|
PartialComponentWithReplacementInProgress(storage_t storage) // NOLINT(google-explicit-constructor)
|
|
: storage(storage) {}
|
|
|
|
private:
|
|
storage_t storage;
|
|
|
|
PartialComponentWithReplacementInProgress() = delete;
|
|
};
|
|
|
|
/**
|
|
* This allows to replace an installed Component with another one. This is useful for testing.
|
|
* For example, if you have these components:
|
|
*
|
|
* fruit::Component<MyDependency> getDependencyComponent() {...}
|
|
*
|
|
* fruit::Component<Foo> getFooComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getDependencyComponent)
|
|
* .bind<Foo, FooImpl>();
|
|
* }
|
|
*
|
|
* fruit::Component<Bar> getBarComponent() {
|
|
* return fruit::createComponent()
|
|
* .install(getFooComponent)
|
|
* .bind<Bar, BarImpl>();
|
|
* }
|
|
*
|
|
* When you test Bar, you might want to replace getDependencyComponent with a component that binds a fake
|
|
* MyDependency:
|
|
*
|
|
* fruit::Component<MyDependency> getFakeDependencyComponent() {...}
|
|
*
|
|
* To do so, you can define a component like:
|
|
*
|
|
* fruit::Component<Bar> getBarComponentWithFakeDependency() {
|
|
* return fruit::createComponent()
|
|
* .replace(getDependencyComponent).with(getFakeDependencyComponent)
|
|
* .install(getBarComponent);
|
|
* }
|
|
*
|
|
* This component is equivalent to:
|
|
*
|
|
* fruit::Component<Bar> getBarComponentWithFakeDependency() {
|
|
* return fruit::createComponent()
|
|
* .install(getFakeDependencyComponent)
|
|
* .bind<Foo, FooImpl>()
|
|
* .bind<Bar, BarImpl>();
|
|
* }
|
|
*
|
|
* However this way you don't need to duplicate the bindings for Foo and Bar, and you don't even need to include them
|
|
* in the translation unit (i.e., cc/cpp file) that defines getBarComponentWithFakeDependency().
|
|
* In codebases with many layers, this can save a lot of duplication.
|
|
*
|
|
* Note that the .replace(...).with(...) must appear *before* installing the component to which it's applied to;
|
|
* e.g., in the example above note how we install getBarComponent after the replacement in
|
|
* getBarComponentWithFakeDependency.
|
|
* If you add a replacement after the replaced component has been installed, Fruit will report an error at run-time.
|
|
*
|
|
* In the example above, the replaced and replacement component functions had no arguments, however it's also possible
|
|
* to replace component functions with args. The arguments of the replaced and replacement component functions are
|
|
* independent; for example .replace(getDependencyComponentWithArgs, 15).with(myFakeComponentWithNoArgs) is allowed
|
|
* and it would replace all install(getDependencyComponentWithArgs, 15) calls with install(myFakeComponentWithNoArgs).
|
|
*
|
|
* The component types returned by the replaced and replacement components must be the same. For example, this is NOT
|
|
* allowed:
|
|
*
|
|
* fruit::Component<MyDependency, SomethingElse> getFakeDependencyComponentWithSomethingElse() {...}
|
|
*
|
|
* fruit::Component<Bar> getBarComponentWithFakeDependency() {
|
|
* return fruit::createComponent()
|
|
* .replace(getDependencyComponent).with(getFakeDependencyComponentWithSomethingElse) // error!
|
|
* .install(getBarComponent);
|
|
* }
|
|
*
|
|
* But replacing a replaced component is allowed:
|
|
*
|
|
* fruit::Component<MyDependency> getOtherFakeDependencyComponent() {...}
|
|
*
|
|
* fruit::Component<Bar> getBarComponentWithOtherFakeDependency() {
|
|
* return fruit::createComponent()
|
|
* // The two replacements can appear in any order, but they must both be before the install().
|
|
* .replace(getFakeDependencyComponent).with(getOtherFakeDependencyComponent)
|
|
* .replace(getDependencyComponent).with(getFakeDependencyComponent)
|
|
* .install(getBarComponent);
|
|
* }
|
|
*
|
|
* Of course this is a simple example, in the real world the replacements and the install would probably come from
|
|
* other components.
|
|
*
|
|
* And note that you can also replace components that define replacements, for example:
|
|
*
|
|
* fruit::Component<> getFakeDependencyReplacementComponent() {
|
|
* return fruit::createComponent()
|
|
* .replace(getDependencyComponent).with(getFakeDependencyComponentWithSomethingElse);
|
|
* }
|
|
*
|
|
* fruit::Component<...> getComponent() {
|
|
* return fruit::createComponent()
|
|
* .replace(getFakeDependencyReplacementComponent).with(...)
|
|
* .install(...);
|
|
* }
|
|
*
|
|
* Replacements are only installed if the replaced component is installed, otherwise they are ignored.
|
|
* In the first example above, if getFooComponent didn't install getDependencyComponent, when a test creates an
|
|
* injector for getBarComponentWithFakeDependency it would not install getFakeDependencyComponent.
|
|
*/
|
|
template <typename... OtherComponentParams, typename... FormalArgs, typename... Args>
|
|
typename PartialComponent<Bindings...>::template PartialComponentWithReplacementInProgress<
|
|
fruit::Component<OtherComponentParams...>, FormalArgs...>
|
|
replace(fruit::Component<OtherComponentParams...> (*)(FormalArgs...), Args&&... args);
|
|
|
|
~PartialComponent() = default;
|
|
|
|
// 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(PartialComponent&&) = delete;
|
|
|
|
private:
|
|
template <typename... OtherBindings>
|
|
friend class PartialComponent;
|
|
|
|
template <typename... Types>
|
|
friend class Component;
|
|
|
|
fruit::impl::PartialComponentStorage<Bindings...> storage;
|
|
|
|
PartialComponent(fruit::impl::PartialComponentStorage<Bindings...> storage); // NOLINT(google-explicit-constructor)
|
|
|
|
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
|