DependencyInjection
Loading...
Searching...
No Matches
DependencyInjection.hpp
Go to the documentation of this file.
1/**
2 * MIT License
3 *
4 * Copyright (c) 2023 Rikarnto Bariampa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#pragma once
26
27#ifdef __cplusplus
28
29#include <any>
30#include <cstdint>
31#include <functional>
32#include <map>
33#include <ranges>
34#include <typeinfo>
35#include <typeindex>
36#include <utility>
37#include <vector>
38
40{
41 enum class ServiceLifetime : std::uint8_t;
42 class IServiceProvider;
44
45 typedef std::function<std::any(IServiceProvider&)> ServiceFactory;
46
47 /**
48 * @enum ServiceLifetime
49 * @brief The lifetime of a service.
50 *
51 * @details This enum determines how often a service is created within the application.
52 * Singleton services are created once and reused, while Transient services are created
53 * each time they are requested.
54 *
55 * @version 1.0
56 */
57 enum class ServiceLifetime : std::uint8_t
58 {
59 Singleton = 0, /*!< The service is created once and reused. */
60 // Scoped = 1, /*!< The service is created once per scope. */
61 Transient = 2, /*!< The service is created each time it is requested. */
62 };
63
65 {
66 private:
67 const std::type_info& _typeInfo;
70
71 public:
73 ServiceDescriptor(const std::type_info& typeInfo, ServiceFactory factory, const ServiceLifetime lifetime) :
74 _typeInfo{ typeInfo },
75 _factory{ std::move(factory) },
76 _lifetime{ lifetime } { }
77 ServiceDescriptor(const ServiceDescriptor& obj) = default;
78 ServiceDescriptor(ServiceDescriptor&& deadObj) noexcept = default;
79
80 [[nodiscard]] auto& GetTypeInfo() const
81 {
82 return _typeInfo;
83 }
84 [[nodiscard]] auto GetFactory() const
85 {
86 return _factory;
87 }
88 [[nodiscard]] auto GetLifetime() const
89 {
90 return _lifetime;
91 }
92
95 };
96
98 {
99 public:
100 virtual std::any GetService(const std::type_info& type) = 0;
101 };
102
104 {
105 private:
106 std::map<std::type_index, std::vector<ServiceDescriptor>> _services;
107
108 explicit ServiceProvider(const std::vector<ServiceDescriptor>& descriptors)
109 {
110 using std::ranges::reverse_view;
111
112 for (const auto& descriptor : reverse_view(descriptors))
113 {
114 const auto& typeInfo = descriptor.GetTypeInfo();
115 bool serviceExists = _services.contains(typeInfo);
116 if (serviceExists)
117 {
118 _services[typeInfo].push_back(descriptor);
119 }
120 else
121 {
122 _services.insert({ typeInfo, { descriptor }});
123 }
124 }
125 }
126
127 public:
128 ServiceProvider() = delete;
129
130 [[nodiscard]] std::any GetService(const std::type_info& type) final
131 {
132 const auto position = _services.find(type);
133 const auto notFound = (position == _services.end());
134 if (notFound)
135 {
136 return {};
137 }
138
139 const auto descriptorList = position->second;
140 const auto& descriptor = descriptorList[0];
141 const auto factory = descriptor.GetFactory();
142 auto service = factory(*this);
143
144 return service;
145 }
146
147
148 template<class T>
150 {
151 auto service = GetService(typeid(T));
152 return std::any_cast<T>(service);
153 }
154
155 friend class ServiceCollection;
156 };
157
159 {
160 public:
161 virtual IServiceCollection& Add(const ServiceDescriptor& descriptor) = 0;
162 };
163
165 {
166 private:
167 std::vector<ServiceDescriptor> _descriptors;
168
169 public:
170 ServiceCollection& Add(const ServiceDescriptor& descriptor) final
171 {
172 _descriptors.push_back(descriptor);
173 return *this;
174 }
175
176 template<class TService, class TImplementation = TService>
178 {
179 const auto factory = [] (IServiceProvider&)
180 {
181 static const auto& service = TImplementation();
182 return service;
183 };
184 return AddSingleton<TService, TImplementation>(factory);
185 }
186
187 template<class TService, class TImplementation = TService>
189 {
190 const ServiceDescriptor descriptor {
191 typeid(TService),
192 factory,
193 ServiceLifetime::Singleton
194 };
195 return Add(descriptor);
196 }
197
198 template<class TService, class TImplementation = TService>
200 {
201 const auto factory = [] (IServiceProvider&)
202 {
203 TImplementation service;
204 return service;
205 };
206 return AddTransient<TService, TImplementation>(factory);
207 }
208
209 template<class TService, class TImplementation = TService>
211 {
212 const ServiceDescriptor descriptor {
213 typeid(TService),
214 factory,
215 ServiceLifetime::Transient
216 };
217 return Add(descriptor);
218 }
219
221 {
222 return ServiceProvider(_descriptors);
223 }
224 };
225}
226
227#endif
Definition: DependencyInjection.hpp:159
virtual IServiceCollection & Add(const ServiceDescriptor &descriptor)=0
Definition: DependencyInjection.hpp:98
virtual std::any GetService(const std::type_info &type)=0
Definition: DependencyInjection.hpp:165
ServiceCollection & AddSingleton(const ServiceFactory &factory)
Definition: DependencyInjection.hpp:188
ServiceProvider BuildServiceProvider() const
Definition: DependencyInjection.hpp:220
std::vector< ServiceDescriptor > _descriptors
Definition: DependencyInjection.hpp:167
ServiceCollection & AddTransient()
Definition: DependencyInjection.hpp:199
ServiceCollection & Add(const ServiceDescriptor &descriptor) final
Definition: DependencyInjection.hpp:170
ServiceCollection & AddTransient(const ServiceFactory &factory)
Definition: DependencyInjection.hpp:210
ServiceCollection & AddSingleton()
Definition: DependencyInjection.hpp:177
Definition: DependencyInjection.hpp:65
const ServiceLifetime _lifetime
Definition: DependencyInjection.hpp:69
auto & GetTypeInfo() const
Definition: DependencyInjection.hpp:80
auto GetFactory() const
Definition: DependencyInjection.hpp:84
ServiceFactory & operator=(const ServiceFactory &)=delete
const ServiceFactory _factory
Definition: DependencyInjection.hpp:68
ServiceFactory & operator=(ServiceFactory &&) noexcept=delete
ServiceDescriptor(const ServiceDescriptor &obj)=default
auto GetLifetime() const
Definition: DependencyInjection.hpp:88
const std::type_info & _typeInfo
Definition: DependencyInjection.hpp:67
ServiceDescriptor(ServiceDescriptor &&deadObj) noexcept=default
ServiceDescriptor(const std::type_info &typeInfo, ServiceFactory factory, const ServiceLifetime lifetime)
Definition: DependencyInjection.hpp:73
Definition: DependencyInjection.hpp:104
std::map< std::type_index, std::vector< ServiceDescriptor > > _services
Definition: DependencyInjection.hpp:106
auto GetService()
Definition: DependencyInjection.hpp:149
std::any GetService(const std::type_info &type) final
Definition: DependencyInjection.hpp:130
ServiceProvider(const std::vector< ServiceDescriptor > &descriptors)
Definition: DependencyInjection.hpp:108
Definition: DependencyInjection.hpp:40
std::function< std::any(IServiceProvider &)> ServiceFactory
Definition: DependencyInjection.hpp:45
ServiceLifetime
The lifetime of a service.
Definition: DependencyInjection.hpp:58