Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright 2014 Google Inc. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef FRUIT_INJECTOR_DEFN_H
     18 #define FRUIT_INJECTOR_DEFN_H
     19 
     20 #include <fruit/component.h>
     21 
     22 // Redundant, but makes KDevelop happy.
     23 #include <fruit/injector.h>
     24 
     25 namespace fruit {
     26 
     27 template <typename... P>
     28 template <typename... FormalArgs, typename... Args>
     29 inline Injector<P...>::Injector(Component<P...> (*getComponent)(FormalArgs...), Args&&... args) {
     30   Component<P...> component = fruit::createComponent().install(getComponent, std::forward<Args>(args)...);
     31 
     32   fruit::impl::MemoryPool memory_pool;
     33   using exposed_types_t = std::vector<fruit::impl::TypeId, fruit::impl::ArenaAllocator<fruit::impl::TypeId>>;
     34   exposed_types_t exposed_types =
     35       exposed_types_t(std::initializer_list<fruit::impl::TypeId>{fruit::impl::getTypeId<P>()...},
     36                       fruit::impl::ArenaAllocator<fruit::impl::TypeId>(memory_pool));
     37   storage = std::unique_ptr<fruit::impl::InjectorStorage>(
     38       new fruit::impl::InjectorStorage(std::move(component.storage), exposed_types, memory_pool));
     39 }
     40 
     41 namespace impl {
     42 namespace meta {
     43 
     44 template <typename... P>
     45 struct InjectorImplHelper {
     46 
     47   // This performs all checks needed in the constructor of Injector that takes NormalizedComponent.
     48   template <typename NormalizedComp, typename Comp>
     49   struct CheckConstructionFromNormalizedComponent {
     50     using Op = InstallComponent(Comp, NormalizedComp);
     51 
     52     // The calculation of MergedComp will also do some checks, e.g. multiple bindings for the same type.
     53     using MergedComp = GetResult(Op);
     54 
     55     using TypesNotProvided = SetDifference(RemoveConstFromTypes(Vector<Type<P>...>), GetComponentPs(MergedComp));
     56     using MergedCompRs = SetDifference(GetComponentRsSuperset(MergedComp), GetComponentPs(MergedComp));
     57 
     58     using type = Eval<If(
     59         Not(IsEmptySet(GetComponentRsSuperset(Comp))),
     60         ConstructErrorWithArgVector(ComponentWithRequirementsInInjectorErrorTag,
     61                                     SetToVector(GetComponentRsSuperset(Comp))),
     62         If(Not(IsEmptySet(MergedCompRs)),
     63            ConstructErrorWithArgVector(UnsatisfiedRequirementsInNormalizedComponentErrorTag, SetToVector(MergedCompRs)),
     64            If(Not(IsContained(VectorToSetUnchecked(RemoveConstFromTypes(Vector<Type<P>...>)),
     65                               GetComponentPs(MergedComp))),
     66               ConstructErrorWithArgVector(TypesInInjectorNotProvidedErrorTag, SetToVector(TypesNotProvided)),
     67               If(Not(IsContained(VectorToSetUnchecked(RemoveConstTypes(Vector<Type<P>...>)),
     68                                  GetComponentNonConstRsPs(MergedComp))),
     69                  ConstructErrorWithArgVector(
     70                      TypesInInjectorProvidedAsConstOnlyErrorTag,
     71                      SetToVector(SetDifference(VectorToSetUnchecked(RemoveConstTypes(Vector<Type<P>...>)),
     72                                                GetComponentNonConstRsPs(MergedComp)))),
     73                  None))))>;
     74   };
     75 
     76   template <typename T>
     77   struct CheckGet {
     78     using Comp = ConstructComponentImpl(Type<P>...);
     79 
     80     using type = Eval<PropagateError(CheckInjectableType(RemoveAnnotations(Type<T>)),
     81                                      If(Not(IsInSet(NormalizeType(Type<T>), GetComponentPs(Comp))),
     82                                         ConstructError(TypeNotProvidedErrorTag, Type<T>),
     83                                         If(And(TypeInjectionRequiresNonConstBinding(Type<T>),
     84                                                Not(IsInSet(NormalizeType(Type<T>), GetComponentNonConstRsPs(Comp)))),
     85                                            ConstructError(TypeProvidedAsConstOnlyErrorTag, Type<T>), None)))>;
     86   };
     87 };
     88 
     89 } // namespace meta
     90 } // namespace impl
     91 
     92 template <typename... P>
     93 template <typename... NormalizedComponentParams, typename... ComponentParams, typename... FormalArgs, typename... Args>
     94 inline Injector<P...>::Injector(const NormalizedComponent<NormalizedComponentParams...>& normalized_component,
     95                                 Component<ComponentParams...> (*getComponent)(FormalArgs...), Args&&... args) {
     96   Component<ComponentParams...> component = fruit::createComponent().install(getComponent, std::forward<Args>(args)...);
     97 
     98   fruit::impl::MemoryPool memory_pool;
     99   storage = std::unique_ptr<fruit::impl::InjectorStorage>(new fruit::impl::InjectorStorage(
    100       *(normalized_component.storage.storage), std::move(component.storage), memory_pool));
    101 
    102   using NormalizedComp =
    103       fruit::impl::meta::ConstructComponentImpl(fruit::impl::meta::Type<NormalizedComponentParams>...);
    104   using Comp1 = fruit::impl::meta::ConstructComponentImpl(fruit::impl::meta::Type<ComponentParams>...);
    105   // We don't check whether the construction of NormalizedComp or Comp resulted in errors here; if they did, the
    106   // instantiation
    107   // of NormalizedComponent<NormalizedComponentParams...> or Component<ComponentParams...> would have resulted in an
    108   // error already.
    109 
    110   using E = typename fruit::impl::meta::InjectorImplHelper<P...>::template CheckConstructionFromNormalizedComponent<
    111       NormalizedComp, Comp1>::type;
    112   (void)typename fruit::impl::meta::CheckIfError<E>::type();
    113 }
    114 
    115 template <typename... P>
    116 template <typename T>
    117 inline fruit::impl::RemoveAnnotations<T> Injector<P...>::get() {
    118   using E = typename fruit::impl::meta::InjectorImplHelper<P...>::template CheckGet<T>::type;
    119   (void)typename fruit::impl::meta::CheckIfError<E>::type();
    120   return storage->template get<T>();
    121 }
    122 
    123 template <typename... P>
    124 template <typename T>
    125 inline Injector<P...>::operator T() {
    126   return get<T>();
    127 }
    128 
    129 template <typename... P>
    130 template <typename AnnotatedC>
    131 inline const std::vector<fruit::impl::RemoveAnnotations<AnnotatedC>*>& Injector<P...>::getMultibindings() {
    132 
    133   using Op = fruit::impl::meta::Eval<fruit::impl::meta::CheckNormalizedTypes(
    134       fruit::impl::meta::Vector<fruit::impl::meta::Type<AnnotatedC>>)>;
    135   (void)typename fruit::impl::meta::CheckIfError<Op>::type();
    136 
    137   return storage->template getMultibindings<AnnotatedC>();
    138 }
    139 
    140 template <typename... P>
    141 FRUIT_DEPRECATED_DEFINITION(inline void Injector<P...>::eagerlyInjectAll()) {
    142   // Eagerly inject normal bindings.
    143   void* unused[] = {reinterpret_cast<void*>(
    144       storage->template get<fruit::impl::meta::UnwrapType<
    145           fruit::impl::meta::Eval<fruit::impl::meta::AddPointerInAnnotatedType(fruit::impl::meta::Type<P>)>>>())...};
    146   (void)unused;
    147 
    148   storage->eagerlyInjectMultibindings();
    149 }
    150 
    151 } // namespace fruit
    152 
    153 #endif // FRUIT_INJECTOR_DEFN_H
    154