blob: 1df57d018726a4bb64ab227527be31d8c60f6278 [file] [log] [blame] [edit]
/*
* 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_FUNCTORS_DEFN_H
#define FRUIT_COMPONENT_FUNCTORS_DEFN_H
#include <fruit/component.h>
#include <fruit/impl/injection_debug_errors.h>
#include <fruit/impl/injection_errors.h>
#include <fruit/impl/injector/injector_storage.h>
#include <memory>
/*********************************************************************************************************************************
This file contains functors that take a Comp and return a struct Op with the form:
struct {
using Result = Comp1;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {...}
std::size_t numEntries() {...}
}
*********************************************************************************************************************************/
namespace fruit {
namespace impl {
namespace meta {
struct GetResult {
template <typename F>
struct apply {
using type = typename F::Result;
};
};
// Call(ComponentFunctor(F, Args...), Comp)
// is equivalent to:
// F(Comp, Args...)
struct ComponentFunctor {
template <typename F, typename... Args>
struct apply {
struct type {
template <typename Comp>
struct apply {
using type = F(Comp, Args...);
};
};
};
};
struct ComponentFunctorIdentity {
template <typename Comp>
struct apply {
struct type {
using Result = Comp;
void operator()(FixedSizeVector<ComponentStorageEntry>&) {}
std::size_t numEntries() {
return 0;
}
};
};
};
struct Compose2ComponentFunctors {
template <typename F1, typename F2>
struct apply {
struct type {
template <typename Comp>
struct apply {
using Op1 = F1(Comp);
using Op2 = F2(GetResult(Op1));
struct Op {
using Result = Eval<GetResult(Op2)>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
Eval<Op2>()(entries);
Eval<Op1>()(entries);
}
std::size_t numEntries() {
return Eval<Op1>().numEntries() + Eval<Op2>().numEntries();
}
};
using type = PropagateError(Op1, PropagateError(Op2, Op));
};
};
};
};
// ComposeFunctors(F1,..,Fn) returns a functor that executes F1,..,Fn in order (stopping at the
// first Error).
struct ComposeFunctors {
template <typename... Functors>
struct apply {
using type = Fold(Compose2ComponentFunctors, ComponentFunctorIdentity, Functors...);
};
};
// ReverseComposeFunctors(T1, ..., Tn) is equivalent to ComposeFunctors(Tn, ..., T1), but it's more
// efficient when all of the following must be evaluated:
// ReverseComposeFunctors<T1>
// ReverseComposeFunctors<T2, T1>
// ReverseComposeFunctors<T3, T2, T1>
// In that case, this implementation shares many more instantiations with previous invocations
struct ReverseComposeFunctors {
template <typename... Functors>
struct apply {
using type = ComponentFunctorIdentity;
};
template <typename Functor>
struct apply<Functor> {
using type = Functor;
};
template <typename Functor, typename... Functors>
struct apply<Functor, Functors...> {
using type = Compose2ComponentFunctors(ReverseComposeFunctors(Functors...), Functor);
};
};
struct EnsureProvidedType;
struct EnsureProvidedTypes;
// Doesn't actually bind in ComponentStorage. The binding is added later (if needed) using ProcessInterfaceBinding.
struct AddDeferredInterfaceBinding {
template <typename Comp, typename AnnotatedI, typename AnnotatedC>
struct apply {
using Comp1 = ConsComp(typename Comp::RsSuperset, typename Comp::Ps, typename Comp::NonConstRsPs,
#if !FRUIT_NO_LOOP_CHECK
typename Comp::Deps,
#endif
PushFront(typename Comp::InterfaceBindings, Pair<AnnotatedI, AnnotatedC>),
typename Comp::DeferredBindingFunctors);
struct Op {
// Note that we do NOT call AddProvidedType here. We'll only know the right required type
// when the binding will be used.
using Result = Eval<Comp1>;
void operator()(FixedSizeVector<ComponentStorageEntry>&) {}
std::size_t numEntries() {
return 0;
}
};
using I = RemoveAnnotations(AnnotatedI);
using C = RemoveAnnotations(AnnotatedC);
using type =
If(IsSame(I, C), ConstructError(InterfaceBindingToSelfErrorTag, C),
If(Not(IsBaseOf(I, C)), ConstructError(NotABaseClassOfErrorTag, I, C),
If(Not(IsSame(I, NormalizeType(I))), ConstructError(NonClassTypeErrorTag, I, NormalizeUntilStable(I)),
If(Not(IsSame(C, NormalizeType(C))),
// We handle this case too, just to be on the safe side, but this should never happen.
ConstructError(NonClassTypeErrorTag, C, NormalizeUntilStable(C)),
If(IsInSet(AnnotatedI, typename Comp::Ps), ConstructError(TypeAlreadyBoundErrorTag, AnnotatedI),
If(MapContainsKey(typename Comp::InterfaceBindings, AnnotatedI),
ConstructError(TypeAlreadyBoundErrorTag, AnnotatedI), Op))))));
};
};
struct ProcessInterfaceBinding {
template <typename Comp, typename AnnotatedI, typename AnnotatedC, typename NonConstBindingRequired>
struct apply {
using R = If(NonConstBindingRequired,
AddProvidedTypeIgnoringInterfaceBindings(Comp, AnnotatedI, NonConstBindingRequired, Vector<AnnotatedC>,
Vector<AnnotatedC>),
AddProvidedTypeIgnoringInterfaceBindings(Comp, AnnotatedI, NonConstBindingRequired, Vector<AnnotatedC>,
Vector<>));
struct ConstOp {
// This must be here (and not in AddDeferredInterfaceBinding) because the binding might be
// used to bind functors instead, so we might never need to add C to the requirements.
using Result = Eval<R>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(
InjectorStorage::createComponentStorageEntryForConstBind<UnwrapType<AnnotatedI>, UnwrapType<AnnotatedC>>());
};
std::size_t numEntries() {
return 1;
}
};
struct NonConstOp {
// This must be here (and not in AddDeferredInterfaceBinding) because the binding might be
// used to bind functors instead, so we might never need to add C to the requirements.
using Result = Eval<R>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(
InjectorStorage::createComponentStorageEntryForBind<UnwrapType<AnnotatedI>, UnwrapType<AnnotatedC>>());
};
std::size_t numEntries() {
return 1;
}
};
using type = PropagateError(R, If(NonConstBindingRequired, NonConstOp, ConstOp));
};
};
struct AddInterfaceMultibinding {
template <typename Comp, typename AnnotatedI, typename AnnotatedC>
struct apply {
using I = RemoveAnnotations(AnnotatedI);
using C = RemoveAnnotations(AnnotatedC);
using R = AddRequirements(Comp, Vector<AnnotatedC>, Vector<AnnotatedC>);
struct Op {
using Result = Eval<R>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(InjectorStorage::createComponentStorageEntryForMultibinding<UnwrapType<AnnotatedI>,
UnwrapType<AnnotatedC>>());
entries.push_back(
InjectorStorage::createComponentStorageEntryForMultibindingVectorCreator<UnwrapType<AnnotatedI>>());
};
std::size_t numEntries() {
return 2;
}
};
using type = If(Not(IsBaseOf(I, C)), ConstructError(NotABaseClassOfErrorTag, I, C), Op);
};
};
template <typename AnnotatedSignature, typename Lambda, typename OptionalAnnotatedI>
struct PostProcessRegisterProviderHelper;
template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI>
struct PostProcessRegisterProviderHelper;
template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI>
struct PostProcessRegisterProviderHelper<AnnotatedSignature, Lambda, Type<AnnotatedI>> {
inline void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(
InjectorStorage::createComponentStorageEntryForCompressedProvider<AnnotatedSignature, Lambda, AnnotatedI>());
entries.push_back(InjectorStorage::createComponentStorageEntryForProvider<AnnotatedSignature, Lambda>());
}
std::size_t numEntries() {
return 2;
}
};
template <typename AnnotatedSignature, typename Lambda>
struct PostProcessRegisterProviderHelper<AnnotatedSignature, Lambda, None> {
inline void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(InjectorStorage::createComponentStorageEntryForProvider<AnnotatedSignature, Lambda>());
}
std::size_t numEntries() {
return 1;
}
};
// T can't be any injectable type, it must match the return type of the provider in one of
// the registerProvider() overloads in ComponentStorage.
struct PostProcessRegisterProvider {
template <typename Comp, typename AnnotatedSignature, typename Lambda>
struct apply {
using AnnotatedC = NormalizeType(SignatureType(AnnotatedSignature));
using OptionalAnnotatedI = FindValueInMap(typename Comp::InterfaceBindings, AnnotatedC);
struct Op {
using Result = Comp;
using Helper = PostProcessRegisterProviderHelper<UnwrapType<AnnotatedSignature>, UnwrapType<Lambda>,
Eval<OptionalAnnotatedI>>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
Helper()(entries);
}
std::size_t numEntries() {
return Helper().numEntries();
}
};
using type = Op;
};
};
struct PreProcessRegisterProvider {
template <typename Comp, typename AnnotatedSignature, typename Lambda>
struct apply {
using Signature = RemoveAnnotationsFromSignature(AnnotatedSignature);
using SignatureFromLambda = FunctionSignature(Lambda);
using AnnotatedC = NormalizeType(SignatureType(AnnotatedSignature));
using AnnotatedCDeps = NormalizeTypeVector(SignatureArgs(AnnotatedSignature));
using R = AddProvidedType(Comp, AnnotatedC, Bool<true>, AnnotatedCDeps,
Id<NormalizedNonConstTypesIn(SignatureArgs(AnnotatedSignature))>);
using type =
If(Not(IsSame(Signature, SignatureFromLambda)),
ConstructError(AnnotatedSignatureDifferentFromLambdaSignatureErrorTag, Signature, SignatureFromLambda),
PropagateError(
CheckInjectableType(RemoveAnnotations(SignatureType(AnnotatedSignature))),
PropagateError(
CheckInjectableTypeVector(RemoveAnnotationsFromVector(AnnotatedCDeps)),
PropagateError(
CheckInjectableType(SignatureType(SignatureFromLambda)),
PropagateError(
CheckInjectableTypeVector(SignatureArgs(SignatureFromLambda)),
If(And(IsPointer(SignatureType(SignatureFromLambda)),
And(IsAbstract(RemovePointer(SignatureType(SignatureFromLambda))),
Not(HasVirtualDestructor(RemovePointer(SignatureType(SignatureFromLambda)))))),
ConstructError(ProviderReturningPointerToAbstractClassWithNoVirtualDestructorErrorTag,
RemovePointer(SignatureType(SignatureFromLambda))),
ComponentFunctorIdentity(R)))))));
};
};
// The registration is actually deferred until the PartialComponent is converted to a component.
struct DeferredRegisterProviderWithAnnotations {
template <typename Comp, typename AnnotatedSignature, typename Lambda>
struct apply {
using Comp1 = AddDeferredBinding(Comp, ComponentFunctor(PostProcessRegisterProvider, AnnotatedSignature, Lambda));
using type = PreProcessRegisterProvider(Comp1, AnnotatedSignature, Lambda);
};
};
// The registration is actually deferred until the PartialComponent is converted to a component.
struct DeferredRegisterProvider {
template <typename Comp, typename Lambda>
struct apply {
using type = DeferredRegisterProviderWithAnnotations(Comp, FunctionSignature(Lambda), Lambda);
};
};
// T can't be any injectable type, it must match the return type of the provider in one of
// the registerMultibindingProvider() overloads in ComponentStorage.
struct RegisterMultibindingProviderWithAnnotations {
template <typename Comp, typename AnnotatedSignature, typename Lambda>
struct apply {
using Signature = RemoveAnnotationsFromSignature(AnnotatedSignature);
using SignatureFromLambda = FunctionSignature(Lambda);
using AnnotatedArgs = SignatureArgs(AnnotatedSignature);
using AnnotatedArgVector = NormalizeTypeVector(AnnotatedArgs);
using NonConstRequirements = NormalizedNonConstTypesIn(AnnotatedArgs);
using R = AddRequirements(Comp, AnnotatedArgVector, NonConstRequirements);
struct Op {
using Result = Eval<R>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(
InjectorStorage::createComponentStorageEntryForMultibindingProvider<UnwrapType<AnnotatedSignature>,
UnwrapType<Lambda>>());
entries.push_back(InjectorStorage::createComponentStorageEntryForMultibindingVectorCreator<
UnwrapType<Eval<NormalizeType(SignatureType(AnnotatedSignature))>>>());
}
std::size_t numEntries() {
return 2;
}
};
using type = If(
Not(IsValidSignature(AnnotatedSignature)), ConstructError(NotASignatureErrorTag, AnnotatedSignature),
PropagateError(
CheckInjectableType(RemoveAnnotations(SignatureType(AnnotatedSignature))),
PropagateError(
CheckInjectableTypeVector(RemoveAnnotationsFromVector(SignatureArgs(AnnotatedSignature))),
PropagateError(
CheckInjectableType(SignatureType(SignatureFromLambda)),
PropagateError(
CheckInjectableTypeVector(SignatureArgs(SignatureFromLambda)),
If(IsAbstract(RemoveAnnotations(SignatureType(AnnotatedSignature))),
ConstructError(CannotConstructAbstractClassErrorTag,
RemoveAnnotations(SignatureType(AnnotatedSignature))),
If(Not(IsSame(Signature, SignatureFromLambda)),
ConstructError(AnnotatedSignatureDifferentFromLambdaSignatureErrorTag, Signature,
SignatureFromLambda),
If(And(IsPointer(SignatureType(SignatureFromLambda)),
And(IsAbstract(RemovePointer(SignatureType(SignatureFromLambda))),
Not(HasVirtualDestructor(RemovePointer(SignatureType(SignatureFromLambda)))))),
ConstructError(
MultibindingProviderReturningPointerToAbstractClassWithNoVirtualDestructorErrorTag,
RemovePointer(SignatureType(SignatureFromLambda))),
PropagateError(R, Op)))))))));
};
};
// T can't be any injectable type, it must match the return type of the provider in one of
// the registerMultibindingProvider() overloads in ComponentStorage.
struct RegisterMultibindingProvider {
template <typename Comp, typename Lambda>
struct apply {
using type = RegisterMultibindingProviderWithAnnotations(Comp, FunctionSignature(Lambda), Lambda);
};
};
// Non-assisted case.
template <int numAssistedBefore, int numNonAssistedBefore, typename Arg>
struct GetAssistedArg {
template <typename InjectedArgsTuple, typename UserProvidedArgsTuple>
inline Arg operator()(InjectedArgsTuple& injected_args, UserProvidedArgsTuple&) {
return std::get<numNonAssistedBefore>(injected_args);
}
};
// Assisted case.
template <int numAssistedBefore, int numNonAssistedBefore, typename Arg>
struct GetAssistedArg<numAssistedBefore, numNonAssistedBefore, Assisted<Arg>> {
template <typename InjectedArgsTuple, typename UserProvidedArgsTuple>
inline Arg operator()(InjectedArgsTuple&, UserProvidedArgsTuple& user_provided_args) {
return std::forward<typename std::tuple_element<numAssistedBefore, UserProvidedArgsTuple>::type>(std::get<numAssistedBefore>(user_provided_args));
}
};
struct RegisterFactoryHelper {
template <typename Comp, typename DecoratedSignature, typename Lambda,
// std::function<InjectedSignature> is the injected type (possibly with an Annotation<> wrapping it)
typename InjectedSignature, typename RequiredLambdaSignature, typename InjectedAnnotatedArgs,
// The types that are injected, unwrapped from any Annotation<>.
typename InjectedArgs, typename IndexSequence>
struct apply;
template <typename Comp, typename DecoratedSignature, typename Lambda, typename NakedC,
typename... NakedUserProvidedArgs, typename... NakedAllArgs, typename... InjectedAnnotatedArgs,
typename... NakedInjectedArgs, typename... Indexes>
struct apply<Comp, DecoratedSignature, Lambda, Type<NakedC(NakedUserProvidedArgs...)>, Type<NakedC(NakedAllArgs...)>,
Vector<InjectedAnnotatedArgs...>, Vector<Type<NakedInjectedArgs>...>, Vector<Indexes...>> {
// Here we call "decorated" the types that might be wrapped in Annotated<> or Assisted<>,
// while we call "annotated" the ones that might only be wrapped in Annotated<> (but not Assisted<>).
using AnnotatedT = SignatureType(DecoratedSignature);
using T = RemoveAnnotations(AnnotatedT);
using DecoratedArgs = SignatureArgs(DecoratedSignature);
using NakedInjectedSignature = NakedC(NakedUserProvidedArgs...);
using NakedRequiredSignature = NakedC(NakedAllArgs...);
using NakedFunctor = std::function<NakedInjectedSignature>;
// This is usually the same as Functor, but this might be annotated.
using AnnotatedFunctor = CopyAnnotation(AnnotatedT, Type<NakedFunctor>);
using FunctorDeps = NormalizeTypeVector(Vector<InjectedAnnotatedArgs...>);
using FunctorNonConstDeps = NormalizedNonConstTypesIn(Vector<InjectedAnnotatedArgs...>);
using R = AddProvidedType(Comp, AnnotatedFunctor, Bool<true>, FunctorDeps, FunctorNonConstDeps);
struct ObjectProvider {
std::tuple<NakedInjectedArgs...> injected_args;
explicit ObjectProvider(std::tuple<NakedInjectedArgs...>&& injected_args) : injected_args(std::move(injected_args)) {}
NakedC operator()(NakedUserProvidedArgs&&... params) {
auto user_provided_args = std::forward_as_tuple(std::forward<decltype(params)>(params)...);
// These are unused if they are 0-arg tuples. Silence the unused-variable warnings anyway.
(void)injected_args;
(void)user_provided_args;
return LambdaInvoker::invoke<UnwrapType<Lambda>, NakedAllArgs...>(
GetAssistedArg<
Eval<NumAssistedBefore(Indexes, DecoratedArgs)>::value,
getIntValue<Indexes>() - Eval<NumAssistedBefore(Indexes, DecoratedArgs)>::value,
// Note that the Assisted<> wrapper (if any) remains, we just remove any wrapping Annotated<>.
UnwrapType<Eval<RemoveAnnotations(GetNthType(Indexes, DecoratedArgs))>>>()(injected_args,
user_provided_args)...);
}
};
struct Op {
using Result = Eval<R>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
auto function_provider = [](NakedInjectedArgs... args) {
return NakedFunctor{ObjectProvider{std::tuple<NakedInjectedArgs...>{args...}}};
};
(void)function_provider;
entries.push_back(InjectorStorage::createComponentStorageEntryForProvider<
UnwrapType<Eval<ConsSignatureWithVector(AnnotatedFunctor, Vector<InjectedAnnotatedArgs...>)>>,
decltype(function_provider)>());
}
std::size_t numEntries() {
return 1;
}
};
// The first two IsValidSignature checks are a bit of a hack, they are needed to make the F2/RealF2 split
// work in the caller (we need to allow Lambda to be a function type).
using type = If(Not(IsSame(Type<NakedRequiredSignature>, FunctionSignature(Lambda))),
ConstructError(FunctorSignatureDoesNotMatchErrorTag, Type<NakedRequiredSignature>,
FunctionSignature(Lambda)),
If(IsPointer(T), ConstructError(FactoryReturningPointerErrorTag, DecoratedSignature),
PropagateError(R, Op)));
};
};
struct RegisterFactory {
template <typename Comp, typename DecoratedSignature, typename Lambda>
struct apply {
using LambdaReturnType = SignatureType(FunctionSignature(Lambda));
using type =
If(Not(IsValidSignature(DecoratedSignature)), ConstructError(NotASignatureErrorTag, DecoratedSignature),
PropagateError(
CheckInjectableType(RemoveAnnotations(SignatureType(DecoratedSignature))),
PropagateError(
CheckInjectableTypeVector(
RemoveAnnotationsFromVector(RemoveAssisted(SignatureArgs(DecoratedSignature)))),
If(IsAbstract(RemoveAnnotations(SignatureType(DecoratedSignature))),
// We error out early in this case. Calling RegisterFactoryHelper would also produce an error, but
// it'd be
// much less user-friendly.
ConstructError(CannotConstructAbstractClassErrorTag,
RemoveAnnotations(SignatureType(DecoratedSignature))),
If(Not(Or(IsEmpty(Lambda), IsValidSignature(Lambda))),
ConstructError(LambdaWithCapturesErrorTag, Lambda),
If(Not(Or(IsTriviallyCopyable(Lambda), IsValidSignature(Lambda))),
ConstructError(NonTriviallyCopyableLambdaErrorTag, Lambda),
If(And(IsUniquePtr(LambdaReturnType),
And(IsAbstract(RemoveUniquePtr(LambdaReturnType)),
Not(HasVirtualDestructor(RemoveUniquePtr(LambdaReturnType))))),
ConstructError(RegisterFactoryForUniquePtrOfAbstractClassWithNoVirtualDestructorErrorTag,
RemoveUniquePtr(LambdaReturnType)),
RegisterFactoryHelper(
Comp, DecoratedSignature, Lambda,
InjectedSignatureForAssistedFactory(DecoratedSignature),
RequiredLambdaSignatureForAssistedFactory(DecoratedSignature),
RemoveAssisted(SignatureArgs(DecoratedSignature)),
RemoveAnnotationsFromVector(RemoveAssisted(SignatureArgs(DecoratedSignature))),
GenerateIntSequence(
VectorSize(RequiredLambdaArgsForAssistedFactory(DecoratedSignature)))))))))));
};
};
struct PostProcessRegisterConstructor;
template <typename AnnotatedSignature, typename OptionalAnnotatedI>
struct PostProcessRegisterConstructorHelper;
template <typename AnnotatedSignature, typename AnnotatedI>
struct PostProcessRegisterConstructorHelper;
template <typename AnnotatedSignature, typename AnnotatedI>
struct PostProcessRegisterConstructorHelper<AnnotatedSignature, Type<AnnotatedI>> {
inline void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(
InjectorStorage::createComponentStorageEntryForCompressedConstructor<AnnotatedSignature, AnnotatedI>());
entries.push_back(InjectorStorage::createComponentStorageEntryForConstructor<AnnotatedSignature>());
}
std::size_t numEntries() {
return 2;
}
};
template <typename AnnotatedSignature>
struct PostProcessRegisterConstructorHelper<AnnotatedSignature, None> {
inline void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
entries.push_back(InjectorStorage::createComponentStorageEntryForConstructor<AnnotatedSignature>());
}
std::size_t numEntries() {
return 1;
}
};
struct PostProcessRegisterConstructor {
template <typename Comp, typename AnnotatedSignature>
struct apply {
struct type {
using AnnotatedC = NormalizeType(SignatureType(AnnotatedSignature));
using Result = Comp;
using Helper =
PostProcessRegisterConstructorHelper<UnwrapType<AnnotatedSignature>,
Eval<FindValueInMap(typename Comp::InterfaceBindings, AnnotatedC)>>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
Helper()(entries);
}
std::size_t numEntries() {
return Helper().numEntries();
}
};
};
};
struct PreProcessRegisterConstructor {
template <typename Comp, typename AnnotatedSignature>
struct apply {
using Signature = RemoveAnnotationsFromSignature(AnnotatedSignature);
using C = SignatureType(Signature);
using Args = SignatureArgs(Signature);
using AnnotatedT = SignatureType(AnnotatedSignature);
using AnnotatedArgs = SignatureArgs(AnnotatedSignature);
using AnnotatedC = NormalizeType(AnnotatedT);
using CDeps = NormalizeTypeVector(AnnotatedArgs);
using CNonConstDeps = NormalizedNonConstTypesIn(AnnotatedArgs);
using R = AddProvidedType(Comp, AnnotatedC, Bool<true>, CDeps, CNonConstDeps);
using type = If(Not(IsValidSignature(AnnotatedSignature)), ConstructError(NotASignatureErrorTag, AnnotatedSignature),
If(Not(IsSame(RemoveAssisted(Args), Args)), ConstructError(AssistedParamInRegisterConstructorSignatureErrorTag, AnnotatedSignature),
PropagateError(CheckInjectableType(RemoveAnnotations(C)),
PropagateError(CheckInjectableTypeVector(RemoveAnnotationsFromVector(Args)),
If(IsAbstract(RemoveAnnotations(SignatureType(AnnotatedSignature))),
ConstructError(CannotConstructAbstractClassErrorTag,
RemoveAnnotations(SignatureType(AnnotatedSignature))),
If(Not(IsConstructibleWithVector(C, Args)),
ConstructError(NoConstructorMatchingInjectSignatureErrorTag, C, Signature),
PropagateError(R, ComponentFunctorIdentity(R))))))));
};
};
struct DeferredRegisterConstructor {
template <typename Comp, typename AnnotatedSignature>
struct apply {
using Comp1 = AddDeferredBinding(Comp, ComponentFunctor(PostProcessRegisterConstructor, AnnotatedSignature));
using type = PreProcessRegisterConstructor(Comp1, AnnotatedSignature);
};
};
struct RegisterInstance {
template <typename Comp, typename AnnotatedC, typename C, typename IsNonConst>
struct apply {
using R = AddProvidedType(Comp, AnnotatedC, IsNonConst, Vector<>, Vector<>);
struct Op {
using Result = Eval<R>;
void operator()(FixedSizeVector<ComponentStorageEntry>&) {}
std::size_t numEntries() {
return 0;
}
};
using type = PropagateError(
CheckNormalizedTypes(ConsVector(RemoveAnnotations(AnnotatedC))),
PropagateError(
CheckNormalizedTypes(ConsVector(C)),
If(Not(IsSame(C, NormalizeType(C))), ConstructError(NonClassTypeErrorTag, C, NormalizeUntilStable(C)),
If(Not(IsSame(RemoveAnnotations(AnnotatedC), NormalizeType(RemoveAnnotations(AnnotatedC)))),
ConstructError(NonClassTypeErrorTag, RemoveAnnotations(AnnotatedC),
NormalizeUntilStable(RemoveAnnotations(C))),
// The IsSame check is not redundant because IsBaseOf returns false for non-class types (e.g. int).
If(Not(Or(IsSame(RemoveAnnotations(AnnotatedC), C), IsBaseOf(RemoveAnnotations(AnnotatedC), C))),
ConstructError(TypeMismatchInBindInstanceErrorTag, RemoveAnnotations(AnnotatedC), C),
PropagateError(R, Op))))));
};
};
struct RegisterConstructorAsValueFactory {
template <typename Comp, typename DecoratedSignature,
typename RequiredSignature = Eval<RequiredLambdaSignatureForAssistedFactory(DecoratedSignature)>>
struct apply;
template <typename Comp, typename DecoratedSignature, typename NakedT, typename... NakedArgs>
struct apply<Comp, DecoratedSignature, Type<NakedT(NakedArgs...)>> {
using RequiredSignature = Type<NakedT(NakedArgs...)>;
using Op1 = RegisterFactory(Comp, DecoratedSignature, RequiredSignature);
struct Op {
using Result = Eval<GetResult(Op1)>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
auto provider = [](NakedArgs... args) { return NakedT(std::forward<NakedArgs>(args)...); };
using RealOp = RegisterFactory(Comp, DecoratedSignature, Type<decltype(provider)>);
FruitStaticAssert(IsSame(GetResult(Op1), GetResult(RealOp)));
Eval<RealOp>()(entries);
}
std::size_t numEntries() {
#if FRUIT_EXTRA_DEBUG
auto provider = [](NakedArgs... args) { return NakedT(std::forward<NakedArgs>(args)...); };
using RealOp = RegisterFactory(Comp, DecoratedSignature, Type<decltype(provider)>);
FruitAssert(Eval<Op1>().numEntries() == Eval<RealOp>().numEntries());
#endif
return Eval<Op1>().numEntries();
}
};
using type = PropagateError(Op1, Op);
};
};
struct RegisterConstructorAsUniquePtrFactory {
template <typename Comp, typename DecoratedSignature,
typename RequiredSignature = Eval<RequiredLambdaSignatureForAssistedFactory(DecoratedSignature)>>
struct apply;
template <typename Comp, typename DecoratedSignature, typename NakedT, typename... NakedArgs>
struct apply<Comp, DecoratedSignature, Type<std::unique_ptr<NakedT>(NakedArgs...)>> {
using RequiredSignature = Type<std::unique_ptr<NakedT>(NakedArgs...)>;
using Op1 = RegisterFactory(Comp, DecoratedSignature, RequiredSignature);
struct Op {
using Result = Eval<GetResult(Op1)>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
auto provider = [](NakedArgs... args) {
return std::unique_ptr<NakedT>(new NakedT(std::forward<NakedArgs>(args)...));
};
// Changed to typedef from a using declaration to workaround a bug in MSVC 2022.
typedef RegisterFactory RealOp(Comp, DecoratedSignature, Type<decltype(provider)>);
FruitStaticAssert(IsSame(GetResult(Op1), GetResult(RealOp)));
Eval<RealOp>()(entries);
};
std::size_t numEntries() {
#if FRUIT_EXTRA_DEBUG
auto provider = [](NakedArgs... args) {
return std::unique_ptr<NakedT>(new NakedT(std::forward<NakedArgs>(args)...));
};
using RealOp = RegisterFactory(Comp, DecoratedSignature, Type<decltype(provider)>);
FruitAssert(Eval<Op1>().numEntries() == Eval<RealOp>().numEntries());
#endif
return Eval<Op1>().numEntries();
}
};
using type = PropagateError(Op1, Op);
};
};
struct InstallComponent {
template <typename Comp, typename OtherComp>
struct apply {
using new_RsSuperset = SetUnion(typename OtherComp::RsSuperset, typename Comp::RsSuperset);
using new_Ps = SetUncheckedUnion(typename OtherComp::Ps, typename Comp::Ps);
using new_NonConstRsPs = SetUnion(typename OtherComp::NonConstRsPs, typename Comp::NonConstRsPs);
#if !FRUIT_NO_LOOP_CHECK
using new_Deps = ConcatVectors(typename OtherComp::Deps, typename Comp::Deps);
#endif
FruitStaticAssert(IsSame(typename OtherComp::InterfaceBindings, Vector<>));
using new_InterfaceBindings = typename Comp::InterfaceBindings;
FruitStaticAssert(IsSame(typename OtherComp::DeferredBindingFunctors, EmptyList));
using new_DeferredBindingFunctors = typename Comp::DeferredBindingFunctors;
using R = ConsComp(new_RsSuperset, new_Ps, new_NonConstRsPs,
#if !FRUIT_NO_LOOP_CHECK
new_Deps,
#endif
new_InterfaceBindings, new_DeferredBindingFunctors);
struct Op {
using Result = Eval<R>;
void operator()(FixedSizeVector<ComponentStorageEntry>&) {}
std::size_t numEntries() {
return 0;
}
};
using InterfacePs = VectorToSetUnchecked(GetMapKeys(typename Comp::InterfaceBindings));
using AllPs = SetUncheckedUnion(InterfacePs, typename Comp::Ps);
using DuplicateTypes = SetIntersection(typename OtherComp::Ps, AllPs);
using CompConstPs = SetDifference(typename Comp::Ps, typename Comp::NonConstRsPs);
using CompRs = SetDifference(typename Comp::RsSuperset, typename Comp::Ps);
using CompNonConstRs = SetIntersection(CompRs, typename Comp::NonConstRsPs);
using OtherCompConstPs = SetDifference(typename OtherComp::Ps, typename OtherComp::NonConstRsPs);
using OtherCompRs = SetDifference(typename OtherComp::RsSuperset, typename OtherComp::Ps);
using OtherCompNonConstRs = SetIntersection(OtherCompRs, typename OtherComp::NonConstRsPs);
using type = If(Not(IsDisjoint(typename OtherComp::Ps, AllPs)),
ConstructErrorWithArgVector(DuplicateTypesInComponentErrorTag, SetToVector(DuplicateTypes)),
If(Not(IsDisjoint(CompConstPs, OtherCompNonConstRs)),
ConstructError(NonConstBindingRequiredButConstBindingProvidedErrorTag,
GetArbitrarySetElement(SetIntersection(CompConstPs, OtherCompNonConstRs))),
If(Not(IsDisjoint(CompNonConstRs, OtherCompConstPs)),
ConstructError(NonConstBindingRequiredButConstBindingProvidedErrorTag,
GetArbitrarySetElement(SetIntersection(CompNonConstRs, OtherCompConstPs))),
Op)));
};
};
struct InstallComponentHelper {
template <typename Comp, typename... OtherCompParams>
struct apply {
using OtherComp = ConstructComponentImpl(OtherCompParams...);
using type = InstallComponent(Comp, OtherComp);
};
};
struct InstallComponentFunctions {
template <typename Comp, typename... ComponentFunctions>
struct apply;
template <typename Comp>
struct apply<Comp> {
using type = ComponentFunctorIdentity(Comp);
};
template <typename Comp, typename... ComponentParams, typename... ComponentFunctionArgs, typename... ComponentFunctions>
struct apply<Comp, Type<fruit::ComponentFunction<fruit::Component<ComponentParams...>, ComponentFunctionArgs...>>, ComponentFunctions...> {
using type =
Call(
Compose2ComponentFunctors(
ComponentFunctor(InstallComponent, ConstructComponentImpl(Type<ComponentParams>...)),
ComponentFunctor(InstallComponentFunctions, ComponentFunctions...)),
Comp);
};
template <typename Comp, typename T, typename... ComponentFunctions>
struct apply<Comp, T, ComponentFunctions...> {
using type = ConstructError(IncorrectArgTypePassedToInstallComponentFuntionsErrorTag, T);
};
};
// CatchAll(PropagateError(Expr, Bool<false>), IsErrorExceptionHandler) evaluates to Bool<true> if Expr throws an error,
// and Bool<false> otherwise.
struct IsErrorExceptionHandler {
template <typename E>
struct apply {
using type = Bool<true>;
};
};
struct ConvertComponent {
template <typename SourceComp, typename DestComp>
struct apply {
using SourcePs = typename SourceComp::Ps;
using DestPs = typename DestComp::Ps;
using SourceRs = SetDifference(typename SourceComp::RsSuperset, typename SourceComp::Ps);
using DestRs = SetDifference(typename DestComp::RsSuperset, typename DestComp::Ps);
using NonConstSourceRs = SetIntersection(SourceRs, typename SourceComp::NonConstRsPs);
using NonConstDestPs = SetIntersection(DestPs, typename DestComp::NonConstRsPs);
using NonConstDestRs = SetIntersection(DestRs, typename DestComp::NonConstRsPs);
using ConstSourcePs = SetDifference(SourcePs, typename SourceComp::NonConstRsPs);
using ConstDestRs = SetDifference(DestRs, typename DestComp::NonConstRsPs);
// We need to register:
// * All the types provided by the new component
// * All the types required by the old component
// except:
// * The ones already provided by the old component (if they have the right constness).
// * The ones required by the new one (if they have the right constness).
using ToRegister = SetUnion(
// The types that we must provide and aren't currently provided
SetDifference(SetUnion(DestPs, SourceRs), SetUnion(DestRs, SourcePs)),
// And the ones that are currently provided as const but that we need to provide as non-const
SetIntersection(SetUnion(NonConstDestPs, NonConstSourceRs), SetUnion(ConstDestRs, ConstSourcePs)));
using NonConstTypesToRegister = SetIntersection(ToRegister, SetUnion(typename SourceComp::NonConstRsPs,
typename DestComp::NonConstRsPs));
using type = EnsureProvidedTypes(SourceComp, DestRs, NonConstDestRs, SetToVector(ToRegister),
NonConstTypesToRegister);
// Not needed, just double-checking.
// Uses FruitStaticAssert instead of FruitDelegateCheck so that it's checked only in debug mode.
#if FRUIT_EXTRA_DEBUG
FruitDelegateCheck(
If(CatchAll(PropagateError(type, PropagateError(Id<GetResult(type)>, Bool<false>)), IsErrorExceptionHandler),
// We're going to return an error soon anyway, we don't want to interfere by reporting this one.
None, CheckComponentEntails(GetResult(type), DestComp)));
#endif // FRUIT_EXTRA_DEBUG
};
};
struct ProcessDeferredBindings {
template <typename Comp>
struct apply;
template <typename RsSupersetParam, typename PsParam, typename NonConstRsPsParam,
#if !FRUIT_NO_LOOP_CHECK
typename DepsParam,
#endif
typename InterfaceBindingsParam, typename DeferredBindingFunctors>
struct apply<Comp<RsSupersetParam, PsParam, NonConstRsPsParam,
#if !FRUIT_NO_LOOP_CHECK
DepsParam,
#endif
InterfaceBindingsParam, DeferredBindingFunctors>> {
// Comp1 is the same as Comp, but without the DeferredBindingFunctors.
using Comp1 = ConsComp(RsSupersetParam, PsParam, NonConstRsPsParam,
#if !FRUIT_NO_LOOP_CHECK
DepsParam,
#endif
InterfaceBindingsParam, EmptyList);
using type = Call(FoldList(DeferredBindingFunctors, Compose2ComponentFunctors, ComponentFunctorIdentity), Comp1);
};
};
template <typename AnnotatedCFunctor, typename AnnotatedCUniquePtrFunctor>
struct AutoRegisterFactoryHelperErrorHandler {
template <typename E>
struct apply {
using type = E;
};
template <typename T>
struct apply<Error<NoBindingFoundErrorTag, T>> {
using type = If(IsSame(Type<T>, AnnotatedCFunctor), ConstructNoBindingFoundError(AnnotatedCUniquePtrFunctor),
ConstructError(NoBindingFoundErrorTag, Type<T>));
};
template <typename T1, typename T2>
struct apply<Error<NoBindingFoundForAbstractClassErrorTag, T1, T2>> {
using type = If(IsSame(Type<T1>, AnnotatedCFunctor), ConstructNoBindingFoundError(AnnotatedCUniquePtrFunctor),
ConstructError(NoBindingFoundForAbstractClassErrorTag, Type<T1>, Type<T2>));
};
};
struct AutoRegisterFactoryHelper {
// General case, no way to bind it.
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename InterfaceBinding,
typename has_inject_annotation, typename is_abstract, typename C, typename AnnotatedSignature,
typename... Args>
struct apply {
using AnnotatedC = SignatureType(AnnotatedSignature);
using CFunctor = ConsStdFunction(RemoveAnnotationsFromSignature(AnnotatedSignature));
using AnnotatedCFunctor = CopyAnnotation(AnnotatedC, CFunctor);
using type = If(IsAbstract(C), ConstructError(NoBindingFoundForAbstractClassErrorTag, AnnotatedCFunctor, C),
ConstructError(NoBindingFoundErrorTag, AnnotatedCFunctor));
};
// No way to bind it (we need this specialization too to ensure that the specialization below
// is not chosen for AnnotatedC=None).
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename unused1,
typename unused2, typename NakedI, typename AnnotatedSignature, typename... Args>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, None, unused1, unused2,
Type<std::unique_ptr<NakedI>>, AnnotatedSignature, Args...> {
using AnnotatedC = SignatureType(AnnotatedSignature);
using CFunctor = ConsStdFunction(RemoveAnnotationsFromSignature(AnnotatedSignature));
using AnnotatedCFunctor = CopyAnnotation(AnnotatedC, CFunctor);
using type = If(IsAbstract(Type<NakedI>),
ConstructError(NoBindingFoundForAbstractClassErrorTag, AnnotatedCFunctor, Type<NakedI>),
ConstructError(NoBindingFoundErrorTag, AnnotatedCFunctor));
};
// AnnotatedI has an interface binding, use it and look for a factory that returns the type that AnnotatedI is bound
// to.
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename AnnotatedC,
typename unused1, typename unused2, typename NakedI, typename AnnotatedSignature, typename... Args>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, AnnotatedC, unused1, unused2,
Type<std::unique_ptr<NakedI>>, AnnotatedSignature, Args...> {
using I = Type<NakedI>;
using AnnotatedI = CopyAnnotation(SignatureType(AnnotatedSignature), I);
using C = RemoveAnnotations(AnnotatedC);
using IFunctor = ConsStdFunction(ConsSignature(ConsUniquePtr(I), Args...));
using CFunctor = ConsStdFunction(ConsSignature(ConsUniquePtr(C), Args...));
using AnnotatedIFunctor = CopyAnnotation(AnnotatedI, IFunctor);
using AnnotatedCFunctor = CopyAnnotation(AnnotatedC, CFunctor);
using ProvidedSignature = ConsSignature(AnnotatedIFunctor,
CopyAnnotation(AnnotatedC, ConsConstReference(CFunctor)));
using LambdaSignature = ConsSignature(IFunctor, ConsConstReference(CFunctor));
using F1 = ComponentFunctor(EnsureProvidedType, TargetRequirements, TargetNonConstRequirements, AnnotatedCFunctor,
Bool<false>);
using F2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, LambdaSignature);
using F3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, LambdaSignature);
using R = Call(ComposeFunctors(F1, F2, F3), Comp);
struct Op {
using Result = Eval<GetResult(R)>;
using NakedC = UnwrapType<Eval<C>>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
auto provider = [](const UnwrapType<Eval<CFunctor>>& fun) {
return UnwrapType<Eval<IFunctor>>([=](typename Args::type... args) {
NakedC* c = fun(args...).release();
NakedI* i = static_cast<NakedI*>(c);
return std::unique_ptr<NakedI>(i);
});
};
FruitStaticAssert(IsSame(
GetResult(
Call(ComposeFunctors(
F1,
ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>),
ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>)),
Comp)),
GetResult(R)));
Eval<Call(ComposeFunctors(
F1,
ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>),
ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>)),
Comp)>()(entries);
}
std::size_t numEntries() {
#if FRUIT_EXTRA_DEBUG
auto provider = [](const UnwrapType<Eval<CFunctor>>& fun) {
return UnwrapType<Eval<IFunctor>>([=](typename Args::type... args) {
NakedC* c = fun(args...).release();
NakedI* i = static_cast<NakedI*>(c);
return std::unique_ptr<NakedI>(i);
});
};
FruitAssert(
Eval<R>().numEntries() ==
Eval<Call(ComposeFunctors(
F1, ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>),
ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>)),
Comp)>()
.numEntries());
#endif
return Eval<R>().numEntries();
}
};
using type = PropagateError(R, If(Not(HasVirtualDestructor(I)),
ConstructError(FactoryBindingForUniquePtrOfClassWithNoVirtualDestructorErrorTag,
IFunctor, CFunctor),
Op));
};
// C doesn't have an interface binding as interface, nor an INJECT annotation, and is not an abstract class.
// Bind std::function<unique_ptr<C>(Args...)> to std::function<C(Args...)> (possibly with annotations).
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename NakedC,
typename AnnotatedSignature, typename... Args>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, None, Bool<false>, Bool<false>,
Type<std::unique_ptr<NakedC>>, AnnotatedSignature, Args...> {
using C = Type<NakedC>;
using CFunctor = ConsStdFunction(ConsSignature(C, Args...));
using CUniquePtrFunctor = ConsStdFunction(ConsSignature(ConsUniquePtr(C), Args...));
using AnnotatedCUniquePtr = SignatureType(AnnotatedSignature);
using AnnotatedC = CopyAnnotation(AnnotatedCUniquePtr, C);
using AnnotatedCFunctor = CopyAnnotation(AnnotatedCUniquePtr, CFunctor);
using AnnotatedCUniquePtrFunctor = CopyAnnotation(AnnotatedCUniquePtr, CUniquePtrFunctor);
using AnnotatedCFunctorRef = CopyAnnotation(AnnotatedCUniquePtr, ConsConstReference(CFunctor));
using ProvidedSignature = ConsSignature(AnnotatedCUniquePtrFunctor, AnnotatedCFunctorRef);
using LambdaSignature = ConsSignature(CUniquePtrFunctor, ConsConstReference(CFunctor));
using F1 = ComponentFunctor(EnsureProvidedType, TargetRequirements, TargetNonConstRequirements, AnnotatedCFunctor,
Bool<false>);
using F2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, LambdaSignature);
using F3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, LambdaSignature);
using R = Call(ComposeFunctors(F1, F2, F3), Comp);
struct Op {
using Result = Eval<GetResult(R)>;
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
auto provider = [](const UnwrapType<Eval<CFunctor>>& fun) {
return UnwrapType<Eval<CUniquePtrFunctor>>([=](typename TypeUnwrapper<Args>::type... args) {
NakedC* c = new NakedC(fun(args...));
return std::unique_ptr<NakedC>(c);
});
};
using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);
using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);
using RealOp = Call(ComposeFunctors(F1, RealF2, RealF3), Comp);
FruitStaticAssert(IsSame(GetResult(RealOp), GetResult(R)));
Eval<RealOp>()(entries);
}
std::size_t numEntries() {
#if FRUIT_EXTRA_DEBUG
auto provider = [](const UnwrapType<Eval<CFunctor>>& fun) {
return UnwrapType<Eval<CUniquePtrFunctor>>([=](typename TypeUnwrapper<Args>::type... args) {
NakedC* c = new NakedC(fun(args...));
return std::unique_ptr<NakedC>(c);
});
};
using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);
using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);
using RealOp = Call(ComposeFunctors(F1, RealF2, RealF3), Comp);
FruitAssert(Eval<R>().numEntries() == Eval<RealOp>().numEntries());
#endif
return Eval<R>().numEntries();
}
};
using ErrorHandler =
AutoRegisterFactoryHelperErrorHandler<Eval<AnnotatedCFunctor>, Eval<AnnotatedCUniquePtrFunctor>>;
// If we are about to report a NoBindingFound/NoBindingFoundForAbstractClass error for AnnotatedCFunctor,
// report one for std::function<std::unique_ptr<C>(Args...)> instead,
// otherwise we'd report an error about a type that the user doesn't expect.
using type = PropagateError(Catch(Catch(R, NoBindingFoundErrorTag, ErrorHandler),
NoBindingFoundForAbstractClassErrorTag, ErrorHandler),
Op);
};
// C has an Inject typedef, use it. unique_ptr case.
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename unused,
typename NakedC, typename AnnotatedSignature, typename... Args>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, None, Bool<true>, unused,
Type<std::unique_ptr<NakedC>>, AnnotatedSignature, Args...> {
using AnnotatedCUniquePtr = SignatureType(AnnotatedSignature);
using AnnotatedC = CopyAnnotation(AnnotatedCUniquePtr, RemoveUniquePtr(RemoveAnnotations(AnnotatedCUniquePtr)));
using DecoratedSignatureReturningValue = GetInjectAnnotation(AnnotatedC);
using DecoratedSignature = ConsSignatureWithVector(AnnotatedCUniquePtr,
SignatureArgs(DecoratedSignatureReturningValue));
using DecoratedSignatureArgs = SignatureArgs(DecoratedSignature);
using ActualSignatureInInjectionTypedef = ConsSignatureWithVector(SignatureType(DecoratedSignature),
RemoveNonAssisted(DecoratedSignatureArgs));
using NonAssistedArgs = RemoveAssisted(DecoratedSignatureArgs);
using F1 = ComponentFunctor(RegisterConstructorAsUniquePtrFactory, DecoratedSignature);
using F2 = ComponentFunctor(EnsureProvidedTypes, TargetRequirements, TargetNonConstRequirements,
NormalizeTypeVector(NonAssistedArgs), NormalizedNonConstTypesIn(NonAssistedArgs));
using type = If(Not(IsSame(AnnotatedSignature, ActualSignatureInInjectionTypedef)),
ConstructError(FunctorSignatureDoesNotMatchErrorTag, AnnotatedSignature,
ActualSignatureInInjectionTypedef),
Call(ComposeFunctors(F1, F2), Comp));
};
// C has an Inject typedef, use it. Value (not unique_ptr) case.
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename unused,
typename NakedC, typename AnnotatedSignature, typename... Args>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, None, Bool<true>, unused, Type<NakedC>,
AnnotatedSignature, Args...> {
using AnnotatedC = SignatureType(AnnotatedSignature);
using DecoratedSignature = GetInjectAnnotation(AnnotatedC);
using DecoratedSignatureArgs = SignatureArgs(DecoratedSignature);
using ActualSignatureInInjectionTypedef = ConsSignatureWithVector(SignatureType(DecoratedSignature),
RemoveNonAssisted(DecoratedSignatureArgs));
using NonAssistedArgs = RemoveAssisted(DecoratedSignatureArgs);
using F1 = ComponentFunctor(RegisterConstructorAsValueFactory, DecoratedSignature);
using F2 = ComponentFunctor(EnsureProvidedTypes, TargetRequirements, TargetNonConstRequirements,
NormalizeTypeVector(NonAssistedArgs), NormalizedNonConstTypesIn(NonAssistedArgs));
using type = If(Not(IsSame(AnnotatedSignature, ActualSignatureInInjectionTypedef)),
ConstructError(FunctorSignatureDoesNotMatchErrorTag, AnnotatedSignature,
ActualSignatureInInjectionTypedef),
Call(ComposeFunctors(F1, F2), Comp));
};
};
struct AutoRegister {
// The types in TargetRequirements will not be auto-registered.
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename AnnotatedC>
struct apply;
// Tries to register C by looking for a typedef called Inject inside C.
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename AnnotatedC>
struct apply {
using CHasInjectAnnotation = HasInjectAnnotation(RemoveAnnotations(AnnotatedC));
using Inject = GetInjectAnnotation(AnnotatedC);
using CRequirements = NormalizeTypeVector(SignatureArgs(Inject));
using CNonConstRequirements = NormalizedNonConstTypesIn(SignatureArgs(Inject));
using F = ComposeFunctors(ComponentFunctor(PreProcessRegisterConstructor, Inject),
ComponentFunctor(PostProcessRegisterConstructor, Inject),
ComponentFunctor(EnsureProvidedTypes, TargetRequirements, TargetNonConstRequirements,
CRequirements, CNonConstRequirements));
using type = If(CHasInjectAnnotation, Call(F, Comp), ConstructNoBindingFoundError(AnnotatedC));
};
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename NakedC,
typename... NakedArgs>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, Type<std::function<NakedC(NakedArgs...)>>> {
using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements,
FindInMap(typename Comp::InterfaceBindings, Type<NakedC>),
HasInjectAnnotation(Type<NakedC>), IsAbstract(Type<NakedC>), Type<NakedC>,
Type<NakedC(NakedArgs...)>, Id<RemoveAnnotations(Type<NakedArgs>)>...);
};
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename NakedC,
typename... NakedArgs>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements,
Type<std::function<std::unique_ptr<NakedC>(NakedArgs...)>>> {
using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements,
FindInMap(typename Comp::InterfaceBindings, Type<NakedC>),
HasInjectAnnotation(Type<NakedC>), IsAbstract(Type<NakedC>),
Type<std::unique_ptr<NakedC>>, Type<std::unique_ptr<NakedC>(NakedArgs...)>,
Id<RemoveAnnotations(Type<NakedArgs>)>...);
};
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename Annotation,
typename NakedC, typename... NakedArgs>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements,
Type<fruit::Annotated<Annotation, std::function<NakedC(NakedArgs...)>>>> {
using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements,
FindInMap(typename Comp::InterfaceBindings,
Type<fruit::Annotated<Annotation, NakedC>>),
HasInjectAnnotation(Type<NakedC>), IsAbstract(Type<NakedC>), Type<NakedC>,
Type<fruit::Annotated<Annotation, NakedC>(NakedArgs...)>,
Id<RemoveAnnotations(Type<NakedArgs>)>...);
};
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename Annotation,
typename NakedC, typename... NakedArgs>
struct apply<Comp, TargetRequirements, TargetNonConstRequirements,
Type<fruit::Annotated<Annotation, std::function<std::unique_ptr<NakedC>(NakedArgs...)>>>> {
using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements,
FindInMap(typename Comp::InterfaceBindings,
Type<fruit::Annotated<Annotation, NakedC>>),
HasInjectAnnotation(Type<NakedC>), IsAbstract(Type<NakedC>),
Type<std::unique_ptr<NakedC>>,
Type<fruit::Annotated<Annotation, std::unique_ptr<NakedC>>(NakedArgs...)>,
Id<RemoveAnnotations(Type<NakedArgs>)>...);
};
};
template <typename AnnotatedT>
struct EnsureProvidedTypeErrorHandler {
template <typename E>
struct apply {
using type = E;
};
template <typename T>
struct apply<Error<NoBindingFoundErrorTag, T>> {
using type = If(IsSame(Type<T>, AnnotatedT),
ConstructError(ConstBindingDeclaredAsRequiredButNonConstBindingRequiredErrorTag, AnnotatedT),
ConstructError(NoBindingFoundErrorTag, Type<T>));
};
template <typename T1, typename T2>
struct apply<Error<NoBindingFoundForAbstractClassErrorTag, T1, T2>> {
using type = If(IsSame(Type<T1>, AnnotatedT),
ConstructError(ConstBindingDeclaredAsRequiredButNonConstBindingRequiredErrorTag, AnnotatedT),
ConstructError(NoBindingFoundForAbstractClassErrorTag, Type<T1>, Type<T2>));
};
};
struct EnsureProvidedType {
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename AnnotatedT,
typename NonConstBindingRequired>
struct apply {
using AnnotatedC = NormalizeType(AnnotatedT);
using AnnotatedCImpl = FindInMap(typename Comp::InterfaceBindings, AnnotatedC);
using AutoRegisterResult = AutoRegister(Comp, TargetRequirements, TargetNonConstRequirements, AnnotatedC);
using ErrorHandler = EnsureProvidedTypeErrorHandler<AnnotatedT>;
using type = If(
IsInSet(AnnotatedC, typename Comp::Ps),
If(And(NonConstBindingRequired, Not(IsInSet(AnnotatedC, typename Comp::NonConstRsPs))),
ConstructError(NonConstBindingRequiredButConstBindingProvidedErrorTag, AnnotatedC),
ComponentFunctorIdentity(Comp)),
If(And(IsInSet(AnnotatedC, TargetRequirements),
Or(Not(NonConstBindingRequired), IsInSet(AnnotatedC, TargetNonConstRequirements))),
// The type is already in the target requirements with the desired constness, nothing to do.
ComponentFunctorIdentity(Comp),
If(Not(IsNone(AnnotatedCImpl)),
// Has an interface binding.
Call(ComposeFunctors(ComponentFunctor(ProcessInterfaceBinding, AnnotatedC, AnnotatedCImpl,
NonConstBindingRequired),
ComponentFunctor(EnsureProvidedType, TargetRequirements, TargetNonConstRequirements,
AnnotatedCImpl, NonConstBindingRequired)),
Comp),
// If we are about to report a NoBindingFound/NoBindingFoundForAbstractClass error for AnnotatedT and the
// target
// component has a Required<const T>, we can report a more specific error (rather than the usual
// "binding not found").
If(And(NonConstBindingRequired, IsInSet(AnnotatedC, TargetRequirements)),
Catch(Catch(AutoRegisterResult, NoBindingFoundErrorTag, ErrorHandler),
NoBindingFoundForAbstractClassErrorTag, ErrorHandler),
AutoRegisterResult))));
};
};
struct EnsureProvidedTypes {
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename TypesToProvide,
typename NonConstTypesToProvide>
struct apply {
struct Helper {
template <typename CurrentResult, typename T>
struct apply {
using type = Compose2ComponentFunctors(ComponentFunctor(EnsureProvidedType, TargetRequirements,
TargetNonConstRequirements, T,
IsInSet(T, NonConstTypesToProvide)),
CurrentResult);
};
};
using type = Call(FoldVector(TypesToProvide, Helper, ComponentFunctorIdentity), Comp);
};
};
struct ProcessBinding {
template <typename Binding>
struct apply;
template <typename I, typename C>
struct apply<fruit::impl::Bind<I, C>> {
using type = ComponentFunctor(AddDeferredInterfaceBinding, Type<I>, Type<C>);
};
template <typename Signature>
struct apply<fruit::impl::RegisterConstructor<Signature>> {
using type = ComponentFunctor(DeferredRegisterConstructor, Type<Signature>);
};
template <typename AnnotatedC, typename C>
struct apply<fruit::impl::BindInstance<AnnotatedC, C>> {
using type = ComponentFunctor(RegisterInstance, Type<AnnotatedC>, Type<C>, Bool<true>);
};
template <typename AnnotatedC, typename C>
struct apply<fruit::impl::BindConstInstance<AnnotatedC, C>> {
using type = ComponentFunctor(RegisterInstance, Type<AnnotatedC>, Type<C>, Bool<false>);
};
template <typename Lambda>
struct apply<fruit::impl::RegisterProvider<Lambda>> {
using type = ComponentFunctor(DeferredRegisterProvider, Type<Lambda>);
};
template <typename AnnotatedSignature, typename Lambda>
struct apply<fruit::impl::RegisterProvider<AnnotatedSignature, Lambda>> {
using type = ComponentFunctor(DeferredRegisterProviderWithAnnotations, Type<AnnotatedSignature>, Type<Lambda>);
};
template <typename AnnotatedC>
struct apply<fruit::impl::AddInstanceMultibinding<AnnotatedC>> {
using type = ComponentFunctorIdentity;
};
template <typename AnnotatedC>
struct apply<fruit::impl::AddInstanceVectorMultibindings<AnnotatedC>> {
using type = ComponentFunctorIdentity;
};
template <typename I, typename C>
struct apply<fruit::impl::AddMultibinding<I, C>> {
using type = ComponentFunctor(AddInterfaceMultibinding, Type<I>, Type<C>);
};
template <typename Lambda>
struct apply<fruit::impl::AddMultibindingProvider<Lambda>> {
using type = ComponentFunctor(RegisterMultibindingProvider, Type<Lambda>);
};
template <typename AnnotatedSignature, typename Lambda>
struct apply<fruit::impl::AddMultibindingProvider<AnnotatedSignature, Lambda>> {
using type = ComponentFunctor(RegisterMultibindingProviderWithAnnotations, Type<AnnotatedSignature>, Type<Lambda>);
};
template <typename DecoratedSignature, typename Lambda>
struct apply<fruit::impl::RegisterFactory<DecoratedSignature, Lambda>> {
using type = ComponentFunctor(RegisterFactory, Type<DecoratedSignature>, Type<Lambda>);
};
template <typename... Params, typename... Args>
struct apply<fruit::impl::InstallComponent<fruit::Component<Params...>(Args...)>> {
using type = ComponentFunctor(InstallComponentHelper, Type<Params>...);
};
template <typename... ComponentFunctions>
struct apply<fruit::impl::InstallComponentFunctions<ComponentFunctions...>> {
using type = ComponentFunctor(InstallComponentFunctions, Type<ComponentFunctions>...);
};
template <typename GetReplacedComponent, typename GetReplacementComponent>
struct apply<fruit::impl::ReplaceComponent<GetReplacedComponent, GetReplacementComponent>> {
using type = ComponentFunctorIdentity;
};
};
} // namespace meta
} // namespace impl
} // namespace fruit
#endif // FRUIT_COMPONENT_FUNCTORS_DEFN_H