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