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