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