/* * 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::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 Op { using Result = Eval<R>; void operator()(FixedSizeVector<ComponentStorageEntry>& entries) { auto function_provider = [](NakedInjectedArgs... args) { auto injected_args = std::make_tuple(args...); auto object_provider = [injected_args](NakedUserProvidedArgs... params) mutable { auto user_provided_args = std::tie(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)...); }; return NakedFunctor(object_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), 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)...)); }; 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 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)>; void operator()(FixedSizeVector<ComponentStorageEntry>& entries) { using NakedC = UnwrapType<Eval<C>>; auto provider = [](const UnwrapType<Eval<CFunctor>>& fun) { return UnwrapType<Eval<IFunctor>>([=](typename TypeUnwrapper<Args>::type... args) { NakedC* c = fun(args...).release(); NakedI* i = static_cast<NakedI*>(c); return std::unique_ptr<NakedI>(i); }); }; 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 using NakedC = UnwrapType<Eval<C>>; auto provider = [](const UnwrapType<Eval<CFunctor>>& fun) { return UnwrapType<Eval<IFunctor>>([=](typename TypeUnwrapper<Args>::type... args) { NakedC* c = fun(args...).release(); NakedI* i = static_cast<NakedI*>(c); return std::unique_ptr<NakedI>(i); }); }; 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 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