blob: 72612e37b36dee445fc3787f99db68b054bb1eb2 [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_DEFN_H
#define FRUIT_COMPONENT_DEFN_H
#include <fruit/component.h>
#include <fruit/impl/injection_errors.h>
#include <fruit/impl/storage/component_storage.h>
#include <memory>
namespace fruit {
namespace impl {
namespace meta {
// This is a helper class used in the implementation of Component and PartialComponent.
// It's in fruit::impl::meta so that we don't need to qualify everything with fruit::impl::meta.
template <typename... PreviousBindings>
struct OpForComponent {
template <typename Comp>
using ConvertTo = Eval<
Call(ReverseComposeFunctors(Id<ComponentFunctor(ConvertComponent, Comp)>,
ProcessDeferredBindings,
Id<ProcessBinding(PreviousBindings)>...),
ConstructComponentImpl())>;
template <typename Binding>
using AddBinding = Eval<
Call(ReverseComposeFunctors(Id<ProcessBinding(Binding)>,
Id<ProcessBinding(PreviousBindings)>...),
ConstructComponentImpl())>;
};
} // namespace meta
} // namespace impl
template <typename... Params>
template <typename... Bindings>
inline Component<Params...>::Component(PartialComponent<Bindings...> component)
: storage() {
(void)typename fruit::impl::meta::CheckIfError<Comp>::type();
using Op = typename fruit::impl::meta::OpForComponent<Bindings...>::template ConvertTo<Comp>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
#ifndef FRUIT_NO_LOOP_CHECK
(void)typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNoLoopInDeps(typename Op::Result)>>::type();
#endif // !FRUIT_NO_LOOP_CHECK
component.storage.addBindings(storage);
// TODO: re-enable this check somehow.
// component.component.already_converted_to_component = true;
Op()(storage);
}
template <typename... Params>
template <typename... OtherParams>
inline Component<Params...>::Component(Component<OtherParams...> component)
: storage(std::move(component.storage)) {
(void)typename fruit::impl::meta::CheckIfError<Comp>::type();
using InstallBinding = fruit::impl::InstallComponent<Component<OtherParams...>>;
using Op1 = typename fruit::impl::meta::OpForComponent<>::template AddBinding<InstallBinding>;
(void)typename fruit::impl::meta::CheckIfError<Op1>::type();
using Op2 = typename fruit::impl::meta::OpForComponent<InstallBinding>::template ConvertTo<Comp>;
(void)typename fruit::impl::meta::CheckIfError<Op2>::type();
Op2()(storage);
#ifndef FRUIT_NO_LOOP_CHECK
(void)typename fruit::impl::meta::CheckIfError<fruit::impl::meta::Eval<fruit::impl::meta::CheckNoLoopInDeps(typename Op2::Result)>>::type();
#endif // !FRUIT_NO_LOOP_CHECK
}
template <typename... Bindings>
inline PartialComponent<Bindings...>::~PartialComponent() {
}
template <>
inline PartialComponent<>::~PartialComponent() {
}
inline PartialComponent<> createComponent() {
return {{}};
}
template <typename... Bindings>
template <typename AnnotatedI, typename AnnotatedC>
inline PartialComponent<fruit::impl::Bind<AnnotatedI, AnnotatedC>, Bindings...>
PartialComponent<Bindings...>::bind() {
using Op = OpFor<fruit::impl::Bind<AnnotatedI, AnnotatedC>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
template <typename AnnotatedSignature>
inline PartialComponent<fruit::impl::RegisterConstructor<AnnotatedSignature>, Bindings...>
PartialComponent<Bindings...>::registerConstructor() {
using Op = OpFor<fruit::impl::RegisterConstructor<AnnotatedSignature>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
template <typename C>
inline PartialComponent<fruit::impl::BindInstance<C, C>, Bindings...>
PartialComponent<Bindings...>::bindInstance(C& instance) {
using Op = OpFor<fruit::impl::BindInstance<C, C>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage, instance}};
}
template <typename... Bindings>
template <typename AnnotatedC, typename C>
inline PartialComponent<fruit::impl::BindInstance<AnnotatedC, C>, Bindings...>
PartialComponent<Bindings...>::bindInstance(C& instance) {
using Op = OpFor<fruit::impl::BindInstance<AnnotatedC, C>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage, instance}};
}
template <typename... Bindings>
template <typename Lambda>
inline PartialComponent<fruit::impl::RegisterProvider<Lambda>, Bindings...>
PartialComponent<Bindings...>::registerProvider(Lambda) {
using Op = OpFor<fruit::impl::RegisterProvider<Lambda>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
template <typename AnnotatedSignature, typename Lambda>
inline PartialComponent<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>, Bindings...>
PartialComponent<Bindings...>::registerProvider(Lambda) {
using Op = OpFor<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
template <typename AnnotatedI, typename AnnotatedC>
inline PartialComponent<fruit::impl::AddMultibinding<AnnotatedI, AnnotatedC>, Bindings...>
PartialComponent<Bindings...>::addMultibinding() {
using Op = OpFor<fruit::impl::AddMultibinding<AnnotatedI, AnnotatedC>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
template <typename C>
inline PartialComponent<fruit::impl::AddInstanceMultibinding<C>, Bindings...>
PartialComponent<Bindings...>::addInstanceMultibinding(C& instance) {
return {{storage, instance}};
}
template <typename... Bindings>
template <typename AnnotatedC, typename C>
inline PartialComponent<fruit::impl::AddInstanceMultibinding<AnnotatedC>, Bindings...>
PartialComponent<Bindings...>::addInstanceMultibinding(C& instance) {
return {{storage, instance}};
}
template <typename... Bindings>
template <typename C>
inline PartialComponent<fruit::impl::AddInstanceVectorMultibindings<C>, Bindings...>
PartialComponent<Bindings...>::addInstanceMultibindings(std::vector<C>& instances) {
return {{storage, instances}};
}
template <typename... Bindings>
template <typename AnnotatedC, typename C>
inline PartialComponent<fruit::impl::AddInstanceVectorMultibindings<AnnotatedC>, Bindings...>
PartialComponent<Bindings...>::addInstanceMultibindings(std::vector<C>& instances) {
return {{storage, instances}};
}
template <typename... Bindings>
template <typename Lambda>
inline PartialComponent<fruit::impl::AddMultibindingProvider<Lambda>, Bindings...>
PartialComponent<Bindings...>::addMultibindingProvider(Lambda) {
using Op = OpFor<fruit::impl::AddMultibindingProvider<Lambda>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
template <typename AnnotatedSignature, typename Lambda>
inline PartialComponent<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>, Bindings...>
PartialComponent<Bindings...>::addMultibindingProvider(Lambda) {
using Op = OpFor<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
template <typename DecoratedSignature, typename Lambda>
inline PartialComponent<fruit::impl::RegisterFactory<DecoratedSignature, Lambda>, Bindings...>
PartialComponent<Bindings...>::registerFactory(Lambda) {
using Op = OpFor<fruit::impl::RegisterFactory<DecoratedSignature, Lambda>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage}};
}
template <typename... Bindings>
inline PartialComponent<Bindings...>::PartialComponent(fruit::impl::PartialComponentStorage<Bindings...> storage)
: storage(std::move(storage)) {
}
template <typename... Bindings>
template <typename... OtherCompParams>
FRUIT_DEPRECATED_DEFINITION(
inline PartialComponent<fruit::impl::OldStyleInstallComponent<Component<OtherCompParams...>>, Bindings...>
PartialComponent<Bindings...>::install(const Component<OtherCompParams...>& other_component)) {
using Op = OpFor<fruit::impl::OldStyleInstallComponent<Component<OtherCompParams...>>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage, other_component.storage}};
}
template <typename T>
FRUIT_ALWAYS_INLINE
inline int checkAcceptableComponentInstallArg() {
// This lambda checks that the required operations on T exist.
// Note that the lambda is never actually executed.
auto checkRequirements = [](const T& constRef, T value) {
T x1(constRef);
T x2(std::move(value));
x1 = constRef;
x2 = std::move(value);
bool b = (constRef == constRef);
std::size_t h = std::hash<T>()(constRef);
(void)x1;
(void)x2;
(void)b;
(void)h;
};
(void)checkRequirements;
return 0;
}
template <typename... Bindings>
template <typename OtherComponent, typename... Args>
inline PartialComponent<fruit::impl::InstallComponent<OtherComponent, Args...>, Bindings...>
PartialComponent<Bindings...>::install(OtherComponent(*fun)(Args...), Args... args) {
using IntCollector = int[];
(void)(IntCollector{0, checkAcceptableComponentInstallArg<Args>()...});
using Op = OpFor<fruit::impl::InstallComponent<OtherComponent, Args...>>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return {{storage, fun, std::move(args)...}};
}
} // namespace fruit
#endif // FRUIT_COMPONENT_DEFN_H