blob: 928c5c33642a0572576ec7763ea00b20ba9c4e1e [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 fruit::impl::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<fruit::impl::RemoveAnnotations<AnnotatedC>*>& 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>
FRUIT_DEPRECATED_DEFINITION(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