You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1303 lines
64 KiB
1303 lines
64 KiB
/*
|
|
* 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::move(std::get<numAssistedBefore>(user_provided_args));
|
|
}
|
|
};
|
|
|
|
struct RegisterFactoryHelper {
|
|
|
|
template <typename Comp, typename DecoratedSignature, typename Lambda,
|
|
// std::function<InjectedSignature> is the injected type (possibly with an Annotation<> wrapping it)
|
|
typename InjectedSignature, typename RequiredLambdaSignature, typename InjectedAnnotatedArgs,
|
|
// The types that are injected, unwrapped from any Annotation<>.
|
|
typename InjectedArgs, typename IndexSequence>
|
|
struct apply;
|
|
|
|
template <typename Comp, typename DecoratedSignature, typename Lambda, typename NakedC,
|
|
typename... NakedUserProvidedArgs, typename... NakedAllArgs, typename... InjectedAnnotatedArgs,
|
|
typename... NakedInjectedArgs, typename... Indexes>
|
|
struct apply<Comp, DecoratedSignature, Lambda, Type<NakedC(NakedUserProvidedArgs...)>, Type<NakedC(NakedAllArgs...)>,
|
|
Vector<InjectedAnnotatedArgs...>, Vector<Type<NakedInjectedArgs>...>, Vector<Indexes...>> {
|
|
// Here we call "decorated" the types that might be wrapped in Annotated<> or Assisted<>,
|
|
// while we call "annotated" the ones that might only be wrapped in Annotated<> (but not Assisted<>).
|
|
using AnnotatedT = SignatureType(DecoratedSignature);
|
|
using T = RemoveAnnotations(AnnotatedT);
|
|
using DecoratedArgs = SignatureArgs(DecoratedSignature);
|
|
using NakedInjectedSignature = NakedC(NakedUserProvidedArgs...);
|
|
using NakedRequiredSignature = NakedC(NakedAllArgs...);
|
|
using NakedFunctor = std::function<NakedInjectedSignature>;
|
|
// This is usually the same as Functor, but this might be annotated.
|
|
using AnnotatedFunctor = CopyAnnotation(AnnotatedT, Type<NakedFunctor>);
|
|
using FunctorDeps = NormalizeTypeVector(Vector<InjectedAnnotatedArgs...>);
|
|
using FunctorNonConstDeps = NormalizedNonConstTypesIn(Vector<InjectedAnnotatedArgs...>);
|
|
using R = AddProvidedType(Comp, AnnotatedFunctor, Bool<true>, FunctorDeps, FunctorNonConstDeps);
|
|
struct Op {
|
|
using Result = Eval<R>;
|
|
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
|
|
auto function_provider = [](NakedInjectedArgs... args) {
|
|
std::tuple<NakedInjectedArgs...> injected_args{args...};
|
|
auto object_provider = [=](NakedUserProvidedArgs... params) mutable {
|
|
std::tuple<NakedUserProvidedArgs...> user_provided_args{std::move(params)...};
|
|
// These are unused if they are 0-arg tuples. Silence the unused-variable warnings anyway.
|
|
(void)injected_args;
|
|
(void)user_provided_args;
|
|
|
|
return LambdaInvoker::invoke<UnwrapType<Lambda>, NakedAllArgs...>(
|
|
GetAssistedArg<
|
|
Eval<NumAssistedBefore(Indexes, DecoratedArgs)>::value,
|
|
getIntValue<Indexes>() - Eval<NumAssistedBefore(Indexes, DecoratedArgs)>::value,
|
|
// Note that the Assisted<> wrapper (if any) remains, we just remove any wrapping Annotated<>.
|
|
UnwrapType<Eval<RemoveAnnotations(GetNthType(Indexes, DecoratedArgs))>>>()(injected_args,
|
|
user_provided_args)...);
|
|
};
|
|
return NakedFunctor(object_provider);
|
|
};
|
|
entries.push_back(InjectorStorage::createComponentStorageEntryForProvider<
|
|
UnwrapType<Eval<ConsSignatureWithVector(AnnotatedFunctor, Vector<InjectedAnnotatedArgs...>)>>,
|
|
decltype(function_provider)>());
|
|
}
|
|
std::size_t numEntries() {
|
|
return 1;
|
|
}
|
|
};
|
|
// The first two IsValidSignature checks are a bit of a hack, they are needed to make the F2/RealF2 split
|
|
// work in the caller (we need to allow Lambda to be a function type).
|
|
using type = If(Not(IsSame(Type<NakedRequiredSignature>, FunctionSignature(Lambda))),
|
|
ConstructError(FunctorSignatureDoesNotMatchErrorTag, Type<NakedRequiredSignature>,
|
|
FunctionSignature(Lambda)),
|
|
If(IsPointer(T), ConstructError(FactoryReturningPointerErrorTag, DecoratedSignature),
|
|
PropagateError(R, Op)));
|
|
};
|
|
};
|
|
|
|
struct RegisterFactory {
|
|
template <typename Comp, typename DecoratedSignature, typename Lambda>
|
|
struct apply {
|
|
using LambdaReturnType = SignatureType(FunctionSignature(Lambda));
|
|
using type =
|
|
If(Not(IsValidSignature(DecoratedSignature)), ConstructError(NotASignatureErrorTag, DecoratedSignature),
|
|
PropagateError(
|
|
CheckInjectableType(RemoveAnnotations(SignatureType(DecoratedSignature))),
|
|
PropagateError(
|
|
CheckInjectableTypeVector(
|
|
RemoveAnnotationsFromVector(RemoveAssisted(SignatureArgs(DecoratedSignature)))),
|
|
If(IsAbstract(RemoveAnnotations(SignatureType(DecoratedSignature))),
|
|
// We error out early in this case. Calling RegisterFactoryHelper would also produce an error, but
|
|
// it'd be
|
|
// much less user-friendly.
|
|
ConstructError(CannotConstructAbstractClassErrorTag,
|
|
RemoveAnnotations(SignatureType(DecoratedSignature))),
|
|
If(Not(Or(IsEmpty(Lambda), IsValidSignature(Lambda))),
|
|
ConstructError(LambdaWithCapturesErrorTag, Lambda),
|
|
If(Not(Or(IsTriviallyCopyable(Lambda), IsValidSignature(Lambda))),
|
|
ConstructError(NonTriviallyCopyableLambdaErrorTag, Lambda),
|
|
If(And(IsUniquePtr(LambdaReturnType),
|
|
And(IsAbstract(RemoveUniquePtr(LambdaReturnType)),
|
|
Not(HasVirtualDestructor(RemoveUniquePtr(LambdaReturnType))))),
|
|
ConstructError(RegisterFactoryForUniquePtrOfAbstractClassWithNoVirtualDestructorErrorTag,
|
|
RemoveUniquePtr(LambdaReturnType)),
|
|
RegisterFactoryHelper(
|
|
Comp, DecoratedSignature, Lambda,
|
|
InjectedSignatureForAssistedFactory(DecoratedSignature),
|
|
RequiredLambdaSignatureForAssistedFactory(DecoratedSignature),
|
|
RemoveAssisted(SignatureArgs(DecoratedSignature)),
|
|
RemoveAnnotationsFromVector(RemoveAssisted(SignatureArgs(DecoratedSignature))),
|
|
GenerateIntSequence(
|
|
VectorSize(RequiredLambdaArgsForAssistedFactory(DecoratedSignature)))))))))));
|
|
};
|
|
};
|
|
|
|
struct PostProcessRegisterConstructor;
|
|
|
|
template <typename AnnotatedSignature, typename OptionalAnnotatedI>
|
|
struct PostProcessRegisterConstructorHelper;
|
|
|
|
template <typename AnnotatedSignature, typename AnnotatedI>
|
|
struct PostProcessRegisterConstructorHelper;
|
|
|
|
template <typename AnnotatedSignature, typename AnnotatedI>
|
|
struct PostProcessRegisterConstructorHelper<AnnotatedSignature, Type<AnnotatedI>> {
|
|
inline void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
|
|
entries.push_back(
|
|
InjectorStorage::createComponentStorageEntryForCompressedConstructor<AnnotatedSignature, AnnotatedI>());
|
|
entries.push_back(InjectorStorage::createComponentStorageEntryForConstructor<AnnotatedSignature>());
|
|
}
|
|
std::size_t numEntries() {
|
|
return 2;
|
|
}
|
|
};
|
|
|
|
template <typename AnnotatedSignature>
|
|
struct PostProcessRegisterConstructorHelper<AnnotatedSignature, None> {
|
|
inline void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
|
|
entries.push_back(InjectorStorage::createComponentStorageEntryForConstructor<AnnotatedSignature>());
|
|
}
|
|
std::size_t numEntries() {
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
struct PostProcessRegisterConstructor {
|
|
template <typename Comp, typename AnnotatedSignature>
|
|
struct apply {
|
|
struct type {
|
|
using AnnotatedC = NormalizeType(SignatureType(AnnotatedSignature));
|
|
using Result = Comp;
|
|
using Helper =
|
|
PostProcessRegisterConstructorHelper<UnwrapType<AnnotatedSignature>,
|
|
Eval<FindValueInMap(typename Comp::InterfaceBindings, AnnotatedC)>>;
|
|
void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
|
|
Helper()(entries);
|
|
}
|
|
std::size_t numEntries() {
|
|
return Helper().numEntries();
|
|
}
|
|
};
|
|
};
|
|
};
|
|
|
|
struct PreProcessRegisterConstructor {
|
|
template <typename Comp, typename AnnotatedSignature>
|
|
struct apply {
|
|
using Signature = RemoveAnnotationsFromSignature(AnnotatedSignature);
|
|
using C = SignatureType(Signature);
|
|
using Args = SignatureArgs(Signature);
|
|
using AnnotatedT = SignatureType(AnnotatedSignature);
|
|
using AnnotatedArgs = SignatureArgs(AnnotatedSignature);
|
|
using AnnotatedC = NormalizeType(AnnotatedT);
|
|
using CDeps = NormalizeTypeVector(AnnotatedArgs);
|
|
using CNonConstDeps = NormalizedNonConstTypesIn(AnnotatedArgs);
|
|
using R = AddProvidedType(Comp, AnnotatedC, Bool<true>, CDeps, CNonConstDeps);
|
|
using type = If(Not(IsValidSignature(AnnotatedSignature)), ConstructError(NotASignatureErrorTag, AnnotatedSignature),
|
|
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)...));
|
|
};
|
|
using RealOp = RegisterFactory(Comp, DecoratedSignature, Type<decltype(provider)>);
|
|
FruitStaticAssert(IsSame(GetResult(Op1), GetResult(RealOp)));
|
|
Eval<RealOp>()(entries);
|
|
};
|
|
std::size_t numEntries() {
|
|
#if FRUIT_EXTRA_DEBUG
|
|
auto provider = [](NakedArgs... args) {
|
|
return std::unique_ptr<NakedT>(new NakedT(std::forward<NakedArgs>(args)...));
|
|
};
|
|
using RealOp = RegisterFactory(Comp, DecoratedSignature, Type<decltype(provider)>);
|
|
FruitAssert(Eval<Op1>().numEntries() == Eval<RealOp>().numEntries());
|
|
#endif
|
|
return Eval<Op1>().numEntries();
|
|
}
|
|
};
|
|
|
|
using type = PropagateError(Op1, Op);
|
|
};
|
|
};
|
|
|
|
struct InstallComponent {
|
|
template <typename Comp, typename OtherComp>
|
|
struct apply {
|
|
using new_RsSuperset = SetUnion(typename OtherComp::RsSuperset, typename Comp::RsSuperset);
|
|
using new_Ps = SetUncheckedUnion(typename OtherComp::Ps, typename Comp::Ps);
|
|
using new_NonConstRsPs = SetUnion(typename OtherComp::NonConstRsPs, typename Comp::NonConstRsPs);
|
|
#if !FRUIT_NO_LOOP_CHECK
|
|
using new_Deps = ConcatVectors(typename OtherComp::Deps, typename Comp::Deps);
|
|
#endif
|
|
FruitStaticAssert(IsSame(typename OtherComp::InterfaceBindings, Vector<>));
|
|
using new_InterfaceBindings = typename Comp::InterfaceBindings;
|
|
|
|
FruitStaticAssert(IsSame(typename OtherComp::DeferredBindingFunctors, EmptyList));
|
|
using new_DeferredBindingFunctors = typename Comp::DeferredBindingFunctors;
|
|
|
|
using R = ConsComp(new_RsSuperset, new_Ps, new_NonConstRsPs,
|
|
#if !FRUIT_NO_LOOP_CHECK
|
|
new_Deps,
|
|
#endif
|
|
new_InterfaceBindings, new_DeferredBindingFunctors);
|
|
struct Op {
|
|
using Result = Eval<R>;
|
|
void operator()(FixedSizeVector<ComponentStorageEntry>&) {}
|
|
std::size_t numEntries() {
|
|
return 0;
|
|
}
|
|
};
|
|
using InterfacePs = VectorToSetUnchecked(GetMapKeys(typename Comp::InterfaceBindings));
|
|
using AllPs = SetUncheckedUnion(InterfacePs, typename Comp::Ps);
|
|
using DuplicateTypes = SetIntersection(typename OtherComp::Ps, AllPs);
|
|
using CompConstPs = SetDifference(typename Comp::Ps, typename Comp::NonConstRsPs);
|
|
using CompRs = SetDifference(typename Comp::RsSuperset, typename Comp::Ps);
|
|
using CompNonConstRs = SetIntersection(CompRs, typename Comp::NonConstRsPs);
|
|
|
|
using OtherCompConstPs = SetDifference(typename OtherComp::Ps, typename OtherComp::NonConstRsPs);
|
|
using OtherCompRs = SetDifference(typename OtherComp::RsSuperset, typename OtherComp::Ps);
|
|
using OtherCompNonConstRs = SetIntersection(OtherCompRs, typename OtherComp::NonConstRsPs);
|
|
|
|
using type = If(Not(IsDisjoint(typename OtherComp::Ps, AllPs)),
|
|
ConstructErrorWithArgVector(DuplicateTypesInComponentErrorTag, SetToVector(DuplicateTypes)),
|
|
If(Not(IsDisjoint(CompConstPs, OtherCompNonConstRs)),
|
|
ConstructError(NonConstBindingRequiredButConstBindingProvidedErrorTag,
|
|
GetArbitrarySetElement(SetIntersection(CompConstPs, OtherCompNonConstRs))),
|
|
If(Not(IsDisjoint(CompNonConstRs, OtherCompConstPs)),
|
|
ConstructError(NonConstBindingRequiredButConstBindingProvidedErrorTag,
|
|
GetArbitrarySetElement(SetIntersection(CompNonConstRs, OtherCompConstPs))),
|
|
Op)));
|
|
};
|
|
};
|
|
|
|
struct InstallComponentHelper {
|
|
template <typename Comp, typename... OtherCompParams>
|
|
struct apply {
|
|
using OtherComp = ConstructComponentImpl(OtherCompParams...);
|
|
using type = InstallComponent(Comp, OtherComp);
|
|
};
|
|
};
|
|
|
|
struct InstallComponentFunctions {
|
|
template <typename Comp, typename... ComponentFunctions>
|
|
struct apply;
|
|
|
|
template <typename Comp>
|
|
struct apply<Comp> {
|
|
using type = ComponentFunctorIdentity(Comp);
|
|
};
|
|
|
|
template <typename Comp, typename... ComponentParams, typename... ComponentFunctionArgs, typename... ComponentFunctions>
|
|
struct apply<Comp, Type<fruit::ComponentFunction<fruit::Component<ComponentParams...>, ComponentFunctionArgs...>>, ComponentFunctions...> {
|
|
using type =
|
|
Call(
|
|
Compose2ComponentFunctors(
|
|
ComponentFunctor(InstallComponent, ConstructComponentImpl(Type<ComponentParams>...)),
|
|
ComponentFunctor(InstallComponentFunctions, ComponentFunctions...)),
|
|
Comp);
|
|
};
|
|
|
|
template <typename Comp, typename T, typename... ComponentFunctions>
|
|
struct apply<Comp, T, ComponentFunctions...> {
|
|
using type = ConstructError(IncorrectArgTypePassedToInstallComponentFuntionsErrorTag, T);
|
|
};
|
|
};
|
|
|
|
// CatchAll(PropagateError(Expr, Bool<false>), IsErrorExceptionHandler) evaluates to Bool<true> if Expr throws an error,
|
|
// and Bool<false> otherwise.
|
|
struct IsErrorExceptionHandler {
|
|
template <typename E>
|
|
struct apply {
|
|
using type = Bool<true>;
|
|
};
|
|
};
|
|
|
|
struct ConvertComponent {
|
|
template <typename SourceComp, typename DestComp>
|
|
struct apply {
|
|
using SourcePs = typename SourceComp::Ps;
|
|
using DestPs = typename DestComp::Ps;
|
|
using SourceRs = SetDifference(typename SourceComp::RsSuperset, typename SourceComp::Ps);
|
|
using DestRs = SetDifference(typename DestComp::RsSuperset, typename DestComp::Ps);
|
|
using NonConstSourceRs = SetIntersection(SourceRs, typename SourceComp::NonConstRsPs);
|
|
using NonConstDestPs = SetIntersection(DestPs, typename DestComp::NonConstRsPs);
|
|
using NonConstDestRs = SetIntersection(DestRs, typename DestComp::NonConstRsPs);
|
|
|
|
using ConstSourcePs = SetDifference(SourcePs, typename SourceComp::NonConstRsPs);
|
|
using ConstDestRs = SetDifference(DestRs, typename DestComp::NonConstRsPs);
|
|
|
|
// We need to register:
|
|
// * All the types provided by the new component
|
|
// * All the types required by the old component
|
|
// except:
|
|
// * The ones already provided by the old component (if they have the right constness).
|
|
// * The ones required by the new one (if they have the right constness).
|
|
using ToRegister = SetUnion(
|
|
// The types that we must provide and aren't currently provided
|
|
SetDifference(SetUnion(DestPs, SourceRs), SetUnion(DestRs, SourcePs)),
|
|
// And the ones that are currently provided as const but that we need to provide as non-const
|
|
SetIntersection(SetUnion(NonConstDestPs, NonConstSourceRs), SetUnion(ConstDestRs, ConstSourcePs)));
|
|
using NonConstTypesToRegister = SetIntersection(ToRegister, SetUnion(typename SourceComp::NonConstRsPs,
|
|
typename DestComp::NonConstRsPs));
|
|
using type = EnsureProvidedTypes(SourceComp, DestRs, NonConstDestRs, SetToVector(ToRegister),
|
|
NonConstTypesToRegister);
|
|
|
|
// Not needed, just double-checking.
|
|
// Uses FruitStaticAssert instead of FruitDelegateCheck so that it's checked only in debug mode.
|
|
#if FRUIT_EXTRA_DEBUG
|
|
FruitDelegateCheck(
|
|
If(CatchAll(PropagateError(type, PropagateError(Id<GetResult(type)>, Bool<false>)), IsErrorExceptionHandler),
|
|
// We're going to return an error soon anyway, we don't want to interfere by reporting this one.
|
|
None, CheckComponentEntails(GetResult(type), DestComp)));
|
|
#endif // FRUIT_EXTRA_DEBUG
|
|
};
|
|
};
|
|
|
|
struct ProcessDeferredBindings {
|
|
template <typename Comp>
|
|
struct apply;
|
|
|
|
template <typename RsSupersetParam, typename PsParam, typename NonConstRsPsParam,
|
|
#if !FRUIT_NO_LOOP_CHECK
|
|
typename DepsParam,
|
|
#endif
|
|
typename InterfaceBindingsParam, typename DeferredBindingFunctors>
|
|
struct apply<Comp<RsSupersetParam, PsParam, NonConstRsPsParam,
|
|
#if !FRUIT_NO_LOOP_CHECK
|
|
DepsParam,
|
|
#endif
|
|
InterfaceBindingsParam, DeferredBindingFunctors>> {
|
|
// Comp1 is the same as Comp, but without the DeferredBindingFunctors.
|
|
using Comp1 = ConsComp(RsSupersetParam, PsParam, NonConstRsPsParam,
|
|
#if !FRUIT_NO_LOOP_CHECK
|
|
DepsParam,
|
|
#endif
|
|
InterfaceBindingsParam, EmptyList);
|
|
using type = Call(FoldList(DeferredBindingFunctors, Compose2ComponentFunctors, ComponentFunctorIdentity), Comp1);
|
|
};
|
|
};
|
|
|
|
template <typename AnnotatedCFunctor, typename AnnotatedCUniquePtrFunctor>
|
|
struct AutoRegisterFactoryHelperErrorHandler {
|
|
template <typename E>
|
|
struct apply {
|
|
using type = E;
|
|
};
|
|
|
|
template <typename T>
|
|
struct apply<Error<NoBindingFoundErrorTag, T>> {
|
|
using type = If(IsSame(Type<T>, AnnotatedCFunctor), ConstructNoBindingFoundError(AnnotatedCUniquePtrFunctor),
|
|
ConstructError(NoBindingFoundErrorTag, Type<T>));
|
|
};
|
|
|
|
template <typename T1, typename T2>
|
|
struct apply<Error<NoBindingFoundForAbstractClassErrorTag, T1, T2>> {
|
|
using type = If(IsSame(Type<T1>, AnnotatedCFunctor), ConstructNoBindingFoundError(AnnotatedCUniquePtrFunctor),
|
|
ConstructError(NoBindingFoundForAbstractClassErrorTag, Type<T1>, Type<T2>));
|
|
};
|
|
};
|
|
|
|
struct AutoRegisterFactoryHelper {
|
|
|
|
// General case, no way to bind it.
|
|
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename InterfaceBinding,
|
|
typename has_inject_annotation, typename is_abstract, typename C, typename AnnotatedSignature,
|
|
typename... Args>
|
|
struct apply {
|
|
using AnnotatedC = SignatureType(AnnotatedSignature);
|
|
using CFunctor = ConsStdFunction(RemoveAnnotationsFromSignature(AnnotatedSignature));
|
|
using AnnotatedCFunctor = CopyAnnotation(AnnotatedC, CFunctor);
|
|
using type = If(IsAbstract(C), ConstructError(NoBindingFoundForAbstractClassErrorTag, AnnotatedCFunctor, C),
|
|
ConstructError(NoBindingFoundErrorTag, AnnotatedCFunctor));
|
|
};
|
|
|
|
// No way to bind it (we need this specialization too to ensure that the specialization below
|
|
// is not chosen for AnnotatedC=None).
|
|
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename unused1,
|
|
typename unused2, typename NakedI, typename AnnotatedSignature, typename... Args>
|
|
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, None, unused1, unused2,
|
|
Type<std::unique_ptr<NakedI>>, AnnotatedSignature, Args...> {
|
|
using AnnotatedC = SignatureType(AnnotatedSignature);
|
|
using CFunctor = ConsStdFunction(RemoveAnnotationsFromSignature(AnnotatedSignature));
|
|
using AnnotatedCFunctor = CopyAnnotation(AnnotatedC, CFunctor);
|
|
using type = If(IsAbstract(Type<NakedI>),
|
|
ConstructError(NoBindingFoundForAbstractClassErrorTag, AnnotatedCFunctor, Type<NakedI>),
|
|
ConstructError(NoBindingFoundErrorTag, AnnotatedCFunctor));
|
|
};
|
|
|
|
// AnnotatedI has an interface binding, use it and look for a factory that returns the type that AnnotatedI is bound
|
|
// to.
|
|
template <typename Comp, typename TargetRequirements, typename TargetNonConstRequirements, typename AnnotatedC,
|
|
typename unused1, typename unused2, typename NakedI, typename AnnotatedSignature, typename... Args>
|
|
struct apply<Comp, TargetRequirements, TargetNonConstRequirements, AnnotatedC, unused1, unused2,
|
|
Type<std::unique_ptr<NakedI>>, AnnotatedSignature, Args...> {
|
|
using I = Type<NakedI>;
|
|
using AnnotatedI = CopyAnnotation(SignatureType(AnnotatedSignature), I);
|
|
using C = RemoveAnnotations(AnnotatedC);
|
|
using IFunctor = ConsStdFunction(ConsSignature(ConsUniquePtr(I), Args...));
|
|
using CFunctor = ConsStdFunction(ConsSignature(ConsUniquePtr(C), Args...));
|
|
using AnnotatedIFunctor = CopyAnnotation(AnnotatedI, IFunctor);
|
|
using AnnotatedCFunctor = CopyAnnotation(AnnotatedC, CFunctor);
|
|
|
|
using ProvidedSignature = ConsSignature(AnnotatedIFunctor,
|
|
CopyAnnotation(AnnotatedC, ConsConstReference(CFunctor)));
|
|
using LambdaSignature = ConsSignature(IFunctor, ConsConstReference(CFunctor));
|
|
|
|
using F1 = ComponentFunctor(EnsureProvidedType, TargetRequirements, TargetNonConstRequirements, AnnotatedCFunctor,
|
|
Bool<false>);
|
|
using F2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, LambdaSignature);
|
|
using F3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, LambdaSignature);
|
|
using R = Call(ComposeFunctors(F1, F2, F3), Comp);
|
|
struct Op {
|
|
using Result = Eval<GetResult(R)>;
|
|
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
|