/* * 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 #include #include #include #include /********************************************************************************************************************************* This file contains functors that take a Comp and return a struct Op with the form: struct { using Result = Comp1; void operator()(FixedSizeVector& entries) {...} std::size_t numEntries() {...} } *********************************************************************************************************************************/ namespace fruit { namespace impl { namespace meta { struct GetResult { template struct apply { using type = typename F::Result; }; }; // Call(ComponentFunctor(F, Args...), Comp) // is equivalent to: // F(Comp, Args...) struct ComponentFunctor { template struct apply { struct type { template struct apply { using type = F(Comp, Args...); }; }; }; }; struct ComponentFunctorIdentity { template struct apply { struct type { using Result = Comp; void operator()(FixedSizeVector&) {} std::size_t numEntries() { return 0; } }; }; }; struct Compose2ComponentFunctors { template struct apply { struct type { template struct apply { using Op1 = F1(Comp); using Op2 = F2(GetResult(Op1)); struct Op { using Result = Eval; void operator()(FixedSizeVector& entries) { Eval()(entries); Eval()(entries); } std::size_t numEntries() { return Eval().numEntries() + Eval().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 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 // ReverseComposeFunctors // ReverseComposeFunctors // In that case, this implementation shares many more instantiations with previous invocations struct ReverseComposeFunctors { template struct apply { using type = ComponentFunctorIdentity; }; template struct apply { using type = Functor; }; template struct apply { 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 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), 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; void operator()(FixedSizeVector&) {} 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 struct apply { using R = If(NonConstBindingRequired, AddProvidedTypeIgnoringInterfaceBindings(Comp, AnnotatedI, NonConstBindingRequired, Vector, Vector), AddProvidedTypeIgnoringInterfaceBindings(Comp, AnnotatedI, NonConstBindingRequired, Vector, 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; void operator()(FixedSizeVector& entries) { entries.push_back( InjectorStorage::createComponentStorageEntryForConstBind, UnwrapType>()); }; 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; void operator()(FixedSizeVector& entries) { entries.push_back( InjectorStorage::createComponentStorageEntryForBind, UnwrapType>()); }; std::size_t numEntries() { return 1; } }; using type = PropagateError(R, If(NonConstBindingRequired, NonConstOp, ConstOp)); }; }; struct AddInterfaceMultibinding { template struct apply { using I = RemoveAnnotations(AnnotatedI); using C = RemoveAnnotations(AnnotatedC); using R = AddRequirements(Comp, Vector, Vector); struct Op { using Result = Eval; void operator()(FixedSizeVector& entries) { entries.push_back(InjectorStorage::createComponentStorageEntryForMultibinding, UnwrapType>()); entries.push_back( InjectorStorage::createComponentStorageEntryForMultibindingVectorCreator>()); }; std::size_t numEntries() { return 2; } }; using type = If(Not(IsBaseOf(I, C)), ConstructError(NotABaseClassOfErrorTag, I, C), Op); }; }; template struct PostProcessRegisterProviderHelper; template struct PostProcessRegisterProviderHelper; template struct PostProcessRegisterProviderHelper> { inline void operator()(FixedSizeVector& entries) { entries.push_back( InjectorStorage::createComponentStorageEntryForCompressedProvider()); entries.push_back(InjectorStorage::createComponentStorageEntryForProvider()); } std::size_t numEntries() { return 2; } }; template struct PostProcessRegisterProviderHelper { inline void operator()(FixedSizeVector& entries) { entries.push_back(InjectorStorage::createComponentStorageEntryForProvider()); } 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 struct apply { using AnnotatedC = NormalizeType(SignatureType(AnnotatedSignature)); using OptionalAnnotatedI = FindValueInMap(typename Comp::InterfaceBindings, AnnotatedC); struct Op { using Result = Comp; using Helper = PostProcessRegisterProviderHelper, UnwrapType, Eval>; void operator()(FixedSizeVector& entries) { Helper()(entries); } std::size_t numEntries() { return Helper().numEntries(); } }; using type = Op; }; }; struct PreProcessRegisterProvider { template 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, AnnotatedCDeps, Id); 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 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 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 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; void operator()(FixedSizeVector& entries) { entries.push_back( InjectorStorage::createComponentStorageEntryForMultibindingProvider, UnwrapType>()); entries.push_back(InjectorStorage::createComponentStorageEntryForMultibindingVectorCreator< UnwrapType>>()); } 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 struct apply { using type = RegisterMultibindingProviderWithAnnotations(Comp, FunctionSignature(Lambda), Lambda); }; }; // Non-assisted case. template struct GetAssistedArg { template inline Arg operator()(InjectedArgsTuple& injected_args, UserProvidedArgsTuple&) { return std::get(injected_args); } }; // Assisted case. template struct GetAssistedArg> { template inline Arg operator()(InjectedArgsTuple&, UserProvidedArgsTuple& user_provided_args) { return std::get(user_provided_args); } }; struct RegisterFactoryHelper { template 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 struct apply, Type, Vector, Vector...>, Vector> { // 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; // This is usually the same as Functor, but this might be annotated. using AnnotatedFunctor = CopyAnnotation(AnnotatedT, Type); using FunctorDeps = NormalizeTypeVector(Vector); using FunctorNonConstDeps = NormalizedNonConstTypesIn(Vector); using R = AddProvidedType(Comp, AnnotatedFunctor, Bool, FunctorDeps, FunctorNonConstDeps); struct Op { using Result = Eval; void operator()(FixedSizeVector& 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, NakedAllArgs...>( GetAssistedArg< Eval::value, getIntValue() - Eval::value, // Note that the Assisted<> wrapper (if any) remains, we just remove any wrapping Annotated<>. UnwrapType>>()(injected_args, user_provided_args)...); }; return NakedFunctor(object_provider); }; entries.push_back(InjectorStorage::createComponentStorageEntryForProvider< UnwrapType)>>, 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, FunctionSignature(Lambda))), ConstructError(FunctorSignatureDoesNotMatchErrorTag, Type, FunctionSignature(Lambda)), If(IsPointer(T), ConstructError(FactoryReturningPointerErrorTag, DecoratedSignature), PropagateError(R, Op))); }; }; struct RegisterFactory { template 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 struct PostProcessRegisterConstructorHelper; template struct PostProcessRegisterConstructorHelper; template struct PostProcessRegisterConstructorHelper> { inline void operator()(FixedSizeVector& entries) { entries.push_back( InjectorStorage::createComponentStorageEntryForCompressedConstructor()); entries.push_back(InjectorStorage::createComponentStorageEntryForConstructor()); } std::size_t numEntries() { return 2; } }; template struct PostProcessRegisterConstructorHelper { inline void operator()(FixedSizeVector& entries) { entries.push_back(InjectorStorage::createComponentStorageEntryForConstructor()); } std::size_t numEntries() { return 1; } }; struct PostProcessRegisterConstructor { template struct apply { struct type { using AnnotatedC = NormalizeType(SignatureType(AnnotatedSignature)); using Result = Comp; using Helper = PostProcessRegisterConstructorHelper, Eval>; void operator()(FixedSizeVector& entries) { Helper()(entries); } std::size_t numEntries() { return Helper().numEntries(); } }; }; }; struct PreProcessRegisterConstructor { template 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, 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 struct apply { using Comp1 = AddDeferredBinding(Comp, ComponentFunctor(PostProcessRegisterConstructor, AnnotatedSignature)); using type = PreProcessRegisterConstructor(Comp1, AnnotatedSignature); }; }; struct RegisterInstance { template struct apply { using R = AddProvidedType(Comp, AnnotatedC, IsNonConst, Vector<>, Vector<>); struct Op { using Result = Eval; void operator()(FixedSizeVector&) {} 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 > struct apply; template struct apply> { using RequiredSignature = Type; using Op1 = RegisterFactory(Comp, DecoratedSignature, RequiredSignature); struct Op { using Result = Eval; void operator()(FixedSizeVector& entries) { auto provider = [](NakedArgs... args) { return NakedT(std::forward(args)...); }; using RealOp = RegisterFactory(Comp, DecoratedSignature, Type); FruitStaticAssert(IsSame(GetResult(Op1), GetResult(RealOp))); Eval()(entries); } std::size_t numEntries() { #if FRUIT_EXTRA_DEBUG auto provider = [](NakedArgs... args) { return NakedT(std::forward(args)...); }; using RealOp = RegisterFactory(Comp, DecoratedSignature, Type); FruitAssert(Eval().numEntries() == Eval().numEntries()); #endif return Eval().numEntries(); } }; using type = PropagateError(Op1, Op); }; }; struct RegisterConstructorAsUniquePtrFactory { template > struct apply; template struct apply(NakedArgs...)>> { using RequiredSignature = Type(NakedArgs...)>; using Op1 = RegisterFactory(Comp, DecoratedSignature, RequiredSignature); struct Op { using Result = Eval; void operator()(FixedSizeVector& entries) { auto provider = [](NakedArgs... args) { return std::unique_ptr(new NakedT(std::forward(args)...)); }; using RealOp = RegisterFactory(Comp, DecoratedSignature, Type); FruitStaticAssert(IsSame(GetResult(Op1), GetResult(RealOp))); Eval()(entries); }; std::size_t numEntries() { #if FRUIT_EXTRA_DEBUG auto provider = [](NakedArgs... args) { return std::unique_ptr(new NakedT(std::forward(args)...)); }; using RealOp = RegisterFactory(Comp, DecoratedSignature, Type); FruitAssert(Eval().numEntries() == Eval().numEntries()); #endif return Eval().numEntries(); } }; using type = PropagateError(Op1, Op); }; }; struct InstallComponent { template 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; void operator()(FixedSizeVector&) {} 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 struct apply { using OtherComp = ConstructComponentImpl(OtherCompParams...); using type = InstallComponent(Comp, OtherComp); }; }; struct InstallComponentFunctions { template struct apply; template struct apply { using type = ComponentFunctorIdentity(Comp); }; template struct apply, ComponentFunctionArgs...>>, ComponentFunctions...> { using type = Call( Compose2ComponentFunctors( ComponentFunctor(InstallComponent, ConstructComponentImpl(Type...)), ComponentFunctor(InstallComponentFunctions, ComponentFunctions...)), Comp); }; template struct apply { using type = ConstructError(IncorrectArgTypePassedToInstallComponentFuntionsErrorTag, T); }; }; // CatchAll(PropagateError(Expr, Bool), IsErrorExceptionHandler) evaluates to Bool if Expr throws an error, // and Bool otherwise. struct IsErrorExceptionHandler { template struct apply { using type = Bool; }; }; struct ConvertComponent { template 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, Bool)), 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 struct apply; template struct apply> { // 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 struct AutoRegisterFactoryHelperErrorHandler { template struct apply { using type = E; }; template struct apply> { using type = If(IsSame(Type, AnnotatedCFunctor), ConstructNoBindingFoundError(AnnotatedCUniquePtrFunctor), ConstructError(NoBindingFoundErrorTag, Type)); }; template struct apply> { using type = If(IsSame(Type, AnnotatedCFunctor), ConstructNoBindingFoundError(AnnotatedCUniquePtrFunctor), ConstructError(NoBindingFoundForAbstractClassErrorTag, Type, Type)); }; }; struct AutoRegisterFactoryHelper { // General case, no way to bind it. template 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 struct apply>, AnnotatedSignature, Args...> { using AnnotatedC = SignatureType(AnnotatedSignature); using CFunctor = ConsStdFunction(RemoveAnnotationsFromSignature(AnnotatedSignature)); using AnnotatedCFunctor = CopyAnnotation(AnnotatedC, CFunctor); using type = If(IsAbstract(Type), ConstructError(NoBindingFoundForAbstractClassErrorTag, AnnotatedCFunctor, Type), 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 struct apply>, AnnotatedSignature, Args...> { using I = Type; 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); 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; void operator()(FixedSizeVector& entries) { using NakedC = UnwrapType>; auto provider = [](const UnwrapType>& fun) { return UnwrapType>([=](typename TypeUnwrapper::type... args) { NakedC* c = fun(args...).release(); NakedI* i = static_cast(c); return std::unique_ptr(i); }); }; using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type); using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type); using RealOp = Call(ComposeFunctors(F1, RealF2, RealF3), Comp); FruitStaticAssert(IsSame(GetResult(RealOp), GetResult(R))); Eval()(entries); } std::size_t numEntries() { #if FRUIT_EXTRA_DEBUG using NakedC = UnwrapType>; auto provider = [](const UnwrapType>& fun) { return UnwrapType>([=](typename TypeUnwrapper::type... args) { NakedC* c = fun(args...).release(); NakedI* i = static_cast(c); return std::unique_ptr(i); }); }; using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type); using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type); using RealOp = Call(ComposeFunctors(F1, RealF2, RealF3), Comp); FruitAssert(Eval().numEntries() == Eval().numEntries()); #endif return Eval().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(Args...)> to std::function (possibly with annotations). template struct apply, Bool, Type>, AnnotatedSignature, Args...> { using C = Type; 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); 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; void operator()(FixedSizeVector& entries) { auto provider = [](const UnwrapType>& fun) { return UnwrapType>([=](typename TypeUnwrapper::type... args) { NakedC* c = new NakedC(fun(args...)); return std::unique_ptr(c); }); }; using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type); using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type); using RealOp = Call(ComposeFunctors(F1, RealF2, RealF3), Comp); FruitStaticAssert(IsSame(GetResult(RealOp), GetResult(R))); Eval()(entries); } std::size_t numEntries() { #if FRUIT_EXTRA_DEBUG auto provider = [](const UnwrapType>& fun) { return UnwrapType>([=](typename TypeUnwrapper::type... args) { NakedC* c = new NakedC(fun(args...)); return std::unique_ptr(c); }); }; using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type); using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type); using RealOp = Call(ComposeFunctors(F1, RealF2, RealF3), Comp); FruitAssert(Eval().numEntries() == Eval().numEntries()); #endif return Eval().numEntries(); } }; using ErrorHandler = AutoRegisterFactoryHelperErrorHandler, Eval>; // If we are about to report a NoBindingFound/NoBindingFoundForAbstractClass error for AnnotatedCFunctor, // report one for std::function(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 struct apply, unused, Type>, 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 struct apply, unused, Type, 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 struct apply; // Tries to register C by looking for a typedef called Inject inside C. template 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 struct apply>> { using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements, FindInMap(typename Comp::InterfaceBindings, Type), HasInjectAnnotation(Type), IsAbstract(Type), Type, Type, Id)>...); }; template struct apply(NakedArgs...)>>> { using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements, FindInMap(typename Comp::InterfaceBindings, Type), HasInjectAnnotation(Type), IsAbstract(Type), Type>, Type(NakedArgs...)>, Id)>...); }; template struct apply>>> { using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements, FindInMap(typename Comp::InterfaceBindings, Type>), HasInjectAnnotation(Type), IsAbstract(Type), Type, Type(NakedArgs...)>, Id)>...); }; template struct apply(NakedArgs...)>>>> { using type = AutoRegisterFactoryHelper(Comp, TargetRequirements, TargetNonConstRequirements, FindInMap(typename Comp::InterfaceBindings, Type>), HasInjectAnnotation(Type), IsAbstract(Type), Type>, Type>(NakedArgs...)>, Id)>...); }; }; template struct EnsureProvidedTypeErrorHandler { template struct apply { using type = E; }; template struct apply> { using type = If(IsSame(Type, AnnotatedT), ConstructError(ConstBindingDeclaredAsRequiredButNonConstBindingRequiredErrorTag, AnnotatedT), ConstructError(NoBindingFoundErrorTag, Type)); }; template struct apply> { using type = If(IsSame(Type, AnnotatedT), ConstructError(ConstBindingDeclaredAsRequiredButNonConstBindingRequiredErrorTag, AnnotatedT), ConstructError(NoBindingFoundForAbstractClassErrorTag, Type, Type)); }; }; struct EnsureProvidedType { template struct apply { using AnnotatedC = NormalizeType(AnnotatedT); using AnnotatedCImpl = FindInMap(typename Comp::InterfaceBindings, AnnotatedC); using AutoRegisterResult = AutoRegister(Comp, TargetRequirements, TargetNonConstRequirements, AnnotatedC); using ErrorHandler = EnsureProvidedTypeErrorHandler; 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, 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 struct apply { struct Helper { template 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 struct apply; template struct apply> { using type = ComponentFunctor(AddDeferredInterfaceBinding, Type, Type); }; template struct apply> { using type = ComponentFunctor(DeferredRegisterConstructor, Type); }; template struct apply> { using type = ComponentFunctor(RegisterInstance, Type, Type, Bool); }; template struct apply> { using type = ComponentFunctor(RegisterInstance, Type, Type, Bool); }; template struct apply> { using type = ComponentFunctor(DeferredRegisterProvider, Type); }; template struct apply> { using type = ComponentFunctor(DeferredRegisterProviderWithAnnotations, Type, Type); }; template struct apply> { using type = ComponentFunctorIdentity; }; template struct apply> { using type = ComponentFunctorIdentity; }; template struct apply> { using type = ComponentFunctor(AddInterfaceMultibinding, Type, Type); }; template struct apply> { using type = ComponentFunctor(RegisterMultibindingProvider, Type); }; template struct apply> { using type = ComponentFunctor(RegisterMultibindingProviderWithAnnotations, Type, Type); }; template struct apply> { using type = ComponentFunctor(RegisterFactory, Type, Type); }; template struct apply(Args...)>> { using type = ComponentFunctor(InstallComponentHelper, Type...); }; template struct apply> { using type = ComponentFunctor(InstallComponentFunctions, Type...); }; template struct apply> { using type = ComponentFunctorIdentity; }; }; } // namespace meta } // namespace impl } // namespace fruit #endif // FRUIT_COMPONENT_FUNCTORS_DEFN_H