• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
Injector(Component<P...> (* getComponent)(FormalArgs...),Args &&...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>
Injector(const NormalizedComponent<NormalizedComponentParams...> & normalized_component,Component<ComponentParams...> (* getComponent)(FormalArgs...),Args &&...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>
get()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>
T()125 inline Injector<P...>::operator T() {
126   return get<T>();
127 }
128 
129 template <typename... P>
130 template <typename AnnotatedC>
getMultibindings()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>
FRUIT_DEPRECATED_DEFINITION(inline void Injector<P...>::eagerlyInjectAll ())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