blob: ee7bb0da849e2e20c16e960c0333c426e367fd46 [file] [log] [blame]
/*
* 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_INJECTOR_DEFN_H
#define FRUIT_INJECTOR_DEFN_H
#include <fruit/component.h>
// Redundant, but makes KDevelop happy.
#include <fruit/injector.h>
namespace fruit {
template <typename... P>
template <typename... FormalArgs, typename... Args>
inline Injector<P...>::Injector(Component<P...>(*getComponent)(FormalArgs...), Args&&... args) {
Component<P...> component = fruit::createComponent().install(getComponent, std::forward<Args>(args)...);
fruit::impl::MemoryPool memory_pool;
using exposed_types_t = std::vector<fruit::impl::TypeId, fruit::impl::ArenaAllocator<fruit::impl::TypeId>>;
exposed_types_t exposed_types =
exposed_types_t(
std::initializer_list<fruit::impl::TypeId>{fruit::impl::getTypeId<P>()...},
fruit::impl::ArenaAllocator<fruit::impl::TypeId>(memory_pool));
storage =
std::unique_ptr<fruit::impl::InjectorStorage>(
new fruit::impl::InjectorStorage(
std::move(component.storage),
exposed_types,
memory_pool));
}
namespace impl {
namespace meta {
template <typename... P>
struct InjectorImplHelper {
// This performs all checks needed in the constructor of Injector that takes NormalizedComponent.
template <typename NormalizedComp, typename Comp>
struct CheckConstructionFromNormalizedComponent {
using Op = InstallComponent(Comp, NormalizedComp);
// The calculation of MergedComp will also do some checks, e.g. multiple bindings for the same type.
using MergedComp = GetResult(Op);
using TypesNotProvided = SetDifference(RemoveConstFromTypes(Vector<Type<P>...>),
GetComponentPs(MergedComp));
using MergedCompRs = SetDifference(GetComponentRsSuperset(MergedComp),
GetComponentPs(MergedComp));
using type = Eval<
If(Not(IsEmptySet(GetComponentRsSuperset(Comp))),
ConstructErrorWithArgVector(ComponentWithRequirementsInInjectorErrorTag, SetToVector(GetComponentRsSuperset(Comp))),
If(Not(IsEmptySet(MergedCompRs)),
ConstructErrorWithArgVector(UnsatisfiedRequirementsInNormalizedComponentErrorTag, SetToVector(MergedCompRs)),
If(Not(IsContained(VectorToSetUnchecked(RemoveConstFromTypes(Vector<Type<P>...>)), GetComponentPs(MergedComp))),
ConstructErrorWithArgVector(TypesInInjectorNotProvidedErrorTag, SetToVector(TypesNotProvided)),
If(Not(IsContained(VectorToSetUnchecked(RemoveConstTypes(Vector<Type<P>...>)),
GetComponentNonConstRsPs(MergedComp))),
ConstructErrorWithArgVector(TypesInInjectorProvidedAsConstOnlyErrorTag,
SetToVector(SetDifference(VectorToSetUnchecked(RemoveConstTypes(Vector<Type<P>...>)),
GetComponentNonConstRsPs(MergedComp)))),
None))))>;
};
template <typename T>
struct CheckGet {
using Comp = ConstructComponentImpl(Type<P>...);
using type = Eval<
PropagateError(CheckInjectableType(RemoveAnnotations(Type<T>)),
If(Not(IsInSet(NormalizeType(Type<T>), GetComponentPs(Comp))),
ConstructError(TypeNotProvidedErrorTag, Type<T>),
If(And(TypeInjectionRequiresNonConstBinding(Type<T>),
Not(IsInSet(NormalizeType(Type<T>), GetComponentNonConstRsPs(Comp)))),
ConstructError(TypeProvidedAsConstOnlyErrorTag, Type<T>),
None)))>;
};
};
} // namespace meta
} // namespace impl
template <typename... P>
template <typename... NormalizedComponentParams, typename... ComponentParams, typename... FormalArgs, typename... Args>
inline Injector<P...>::Injector(const NormalizedComponent<NormalizedComponentParams...>& normalized_component,
Component<ComponentParams...>(*getComponent)(FormalArgs...), Args&&... args) {
Component<ComponentParams...> component = fruit::createComponent().install(getComponent, std::forward<Args>(args)...);
fruit::impl::MemoryPool memory_pool;
storage =
std::unique_ptr<fruit::impl::InjectorStorage>(
new fruit::impl::InjectorStorage(
*(normalized_component.storage.storage),
std::move(component.storage),
memory_pool));
using NormalizedComp = fruit::impl::meta::ConstructComponentImpl(fruit::impl::meta::Type<NormalizedComponentParams>...);
using Comp1 = fruit::impl::meta::ConstructComponentImpl(fruit::impl::meta::Type<ComponentParams>...);
// We don't check whether the construction of NormalizedComp or Comp resulted in errors here; if they did, the instantiation
// of NormalizedComponent<NormalizedComponentParams...> or Component<ComponentParams...> would have resulted in an error already.
using E = typename fruit::impl::meta::InjectorImplHelper<P...>::template CheckConstructionFromNormalizedComponent<NormalizedComp, Comp1>::type;
(void)typename fruit::impl::meta::CheckIfError<E>::type();
}
template <typename... P>
template <typename T>
inline typename Injector<P...>::template RemoveAnnotations<T> Injector<P...>::get() {
using E = typename fruit::impl::meta::InjectorImplHelper<P...>::template CheckGet<T>::type;
(void)typename fruit::impl::meta::CheckIfError<E>::type();
return storage->template get<T>();
}
template <typename... P>
template <typename T>
inline Injector<P...>::operator T() {
return get<T>();
}
template <typename... P>
template <typename AnnotatedC>
inline const std::vector<
typename fruit::Injector<P...>::template RemoveAnnotationsHelper<AnnotatedC>::type
*>& Injector<P...>::getMultibindings() {
using Op = fruit::impl::meta::Eval<
fruit::impl::meta::CheckNormalizedTypes(
fruit::impl::meta::Vector<
fruit::impl::meta::Type<AnnotatedC>>)>;
(void)typename fruit::impl::meta::CheckIfError<Op>::type();
return storage->template getMultibindings<AnnotatedC>();
}
template <typename... P>
inline void Injector<P...>::eagerlyInjectAll() {
// Eagerly inject normal bindings.
void* unused[] = {reinterpret_cast<void*>(storage->template get<fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::AddPointerInAnnotatedType(fruit::impl::meta::Type<P>)>>>())...};
(void)unused;
storage->eagerlyInjectMultibindings();
}
} // namespace fruit
#endif // FRUIT_INJECTOR_DEFN_H