Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
depend-inject.hpp
Go to the documentation of this file.
1/*
2 DEPEND-INJECT.hpp - managing the lifecycle of singletons and dependencies
3
4 Copyright (C)
5 2018, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
105#ifndef LIB_DEPEND_INJECT_H
106#define LIB_DEPEND_INJECT_H
107
108
109
110#include "lib/error.hpp"
111#include "lib/nocopy.hpp"
112#include "lib/depend.hpp"
113#include "lib/meta/trait.hpp"
114#include "lib/meta/function.hpp"
115#include "lib/sync-classlock.hpp"
116
117#include <type_traits>
118#include <utility>
119#include <memory>
120
121
122namespace lib {
123 namespace error = lumiera::error;
124
125 using std::forward;
126 using std::move;
127
128
129
130
147 template<class SRV>
150 {
153
154 public:
161 template<class SUB>
162 static void
164 {
165 __assert_compatible<SUB>();
166 installFactory<SUB>();
167 }
168
177 template<class FUN>
178 static void
179 useSingleton (FUN&& ctor)
180 {
183
184 __assert_compatible<Sub>();
185 installFactory<Sub,Fun> (forward<FUN> (ctor));
186 }
187
188
201 template<class IMP =SRV>
204 {
205 std::unique_ptr<IMP> instance_;
206
207 public:
208 template<typename...ARGS>
209 ServiceInstance(ARGS&& ...ctorArgs)
210 : instance_{new IMP(forward<ARGS> (ctorArgs)...)}
211 {
212 __assert_compatible<IMP>();
214 }
215
217
220 : instance_{}
221 {
222 __assert_compatible<IMP>();
223 }
224
226 {
227 shutdown();
228 }
229
230 template<typename...ARGS>
231 IMP&
232 createInstance(ARGS&& ...ctorArgs)
233 {
234 instance_.reset (new IMP(forward<ARGS> (ctorArgs)...));
236 return *instance_;
237 }
238
239 void
240 shutdown() noexcept
241 {
242 if (instance_)
243 {
245 instance_.reset();
246 }
247 }
248
249
250 explicit
251 operator bool() const
252 {
253 return bool(instance_);
254 }
255
256 IMP&
258 {
259 ENSURE (instance_);
260 return *instance_;
261 }
262
263 IMP*
265 {
266 ENSURE (instance_);
267 return instance_.get();
268 }
269 };
270
271
280 template<class MOC =SRV>
281 class Local
283 {
284 std::unique_ptr<MOC> mock_;
285
288
289 public:
291 : Local([]{ return new MOC{}; })
292 { }
293
294 template<class FUN>
295 explicit
296 Local (FUN&& _buildInstance)
297 {
298 __assert_compatible<MOC>();
299 __assert_compatible<typename SubclassFactoryType<FUN>::Subclass>();
300
302 ,[this, buildInstance=forward<FUN> (_buildInstance)]
303 {
304 mock_.reset (buildInstance());
305 return mock_.get();
306 });
307 }
312
313 explicit
314 operator bool() const
315 {
316 return bool(mock_);
317 }
318
320 MOC&
322 {
323 Depend<SRV>{}.operator()();
324 ENSURE (mock_);
325 return *mock_;
326 }
327
328 MOC&
330 {
331 REQUIRE (mock_);
332 return *mock_;
333 }
334
335 MOC*
337 {
338 REQUIRE (mock_);
339 return mock_.get();
340 }
341 };
342
343
344
345 protected: /* ======= internal access-API for those configurations to manipulate Depend<SRV> ======= */
346 template<class IMP>
347 friend class ServiceInstance;
348 template<class MOC>
349 friend class Local;
350
351
352 template<class SUB>
353 static void
355 {
356 static_assert (meta::is_Subclass<SUB,SRV>()
357 ,"Installed implementation class must be compatible to the interface.");
358 }
359
360 static void
362 {
364 throw error::Logic("Attempt to reconfigure dependency injection after the fact. "
365 "The previously installed factory (typically Singleton) was already used."
366 , error::LUMIERA_ERROR_LIFECYCLE);
367 }
368
369 template<typename FUN>
371 {
372 static_assert (meta::_Fun<FUN>(),
373 "Need a Lambda or Function object to create a heap allocated instance");
374
375 using Functor = meta::_Fun<FUN>::Functor; // suitable type to store for later invocation
378
379 static_assert (std::is_pointer<ResultVal>::value,
380 "Function must yield a pointer to a heap allocated instance");
381 };
382
383
384 template<class SUB, typename FUN>
385 static void
386 installFactory (FUN&& ctor)
387 {
388 Lock guard;
389 if (std::is_same<SRV,SUB>())
390 {
392 Depend<SRV>::factory().defineCreatorAndManage (forward<FUN> (ctor));
393 }
394 else
395 {
397 Depend<SRV>::factory().defineCreator ([]{ return & Depend<SUB>{}(); });
398 DependInject<SUB>::useSingleton (forward<FUN> (ctor));
399 } // delegate actual instance creation to Depend<SUB>
400 }
401
402 template<class SUB>
403 static void
405 {
406 if (not std::is_same<SRV,SUB>())
407 {
408 Lock guard;
410 Depend<SRV>::factory().defineCreator ([]{ return & Depend<SUB>{}(); });
411 }
412 // note: we do not install an actual factory; rather we use the default for SUB
413 }
414
415
416 template<typename FUN>
417 static void
418 temporarilyInstallAlternateFactory (SRV*& stashInstance, Factory& stashFac, FUN&& newFac)
419 {
420 Lock guard;
421 stashFac.transferDefinition (move (Depend<SRV>::factory()));
422 stashInstance = Depend<SRV>::instance;
423 Depend<SRV>::factory().defineCreator (forward<FUN>(newFac));
424 Depend<SRV>::instance = nullptr;
425 }
426
427 static void
428 restoreOriginalFactory (SRV*& stashInstance, Factory&& stashFac)
429 {
430 Lock guard;
431 Depend<SRV>::factory().transferDefinition (move (stashFac));
432 Depend<SRV>::instance = stashInstance;
433 }
434
435 static void
436 activateServiceAccess (SRV& newInstance)
437 {
438 Lock guard;
440 throw error::Logic("Attempt to activate an external service implementation, "
441 "but another instance has already been dependency-injected."
442 , error::LUMIERA_ERROR_LIFECYCLE);
443 Depend<SRV>::instance = &newInstance;
444 Depend<SRV>::factory().disable();
445 }
446
447 static void
449 {
450 Lock guard;
451 Depend<SRV>::instance = nullptr;
452 Depend<SRV>::factory().disable();
453 }
454 };
455
456
457
458} // namespace lib
459#endif /*LIB_DEPEND_INJECT_H*/
Configuration handle for temporarily shadowing a dependency by a test mock instance.
Local(FUN &&_buildInstance)
MOC & triggerCreate()
trigger lazy service object instantiation
std::unique_ptr< MOC > mock_
Configuration handle to expose a service implementation through the Depend<SRV> front-end.
ServiceInstance(StartMode)
create in deactivated state.
IMP & createInstance(ARGS &&...ctorArgs)
This framework allows to (re)configure the lib::Depend front-end for dependency-injection.
meta::Strip< ResultVal >::TypePlain Subclass
static void __assert_compatible()
static void restoreOriginalFactory(SRV *&stashInstance, Factory &&stashFac)
static void useSingleton(FUN &&ctor)
configure dependency-injection for type SRV to manage a subclass singleton, which is created lazily o...
static void installFactory()
static void __ensure_pristine()
static void installFactory(FUN &&ctor)
static void deactivateServiceAccess()
Depend< SRV >::Factory Factory
Depend< SRV >::Lock Lock
static void temporarilyInstallAlternateFactory(SRV *&stashInstance, Factory &stashFac, FUN &&newFac)
static void activateServiceAccess(SRV &newInstance)
static void useSingleton()
configure dependency-injection for type SRV to build a subclass singleton.
Access point to singletons and other kinds of dependencies designated by type.
Definition depend.hpp:281
ClassLock< SRV, NonrecursiveLock_NoWait > Lock
Definition depend.hpp:284
DependencyFactory< SRV > Factory
Definition depend.hpp:283
static Factory & factory()
Definition depend.hpp:290
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
Not meant to be instantiated in any way.
Definition nocopy.hpp:113
Singleton services and Dependency Injection.
Lumiera error handling (C++ interface).
Metaprogramming tools for detecting and transforming function types.
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
remove_cv_t< TypePointee > TypePlain
Definition trait.hpp:259
Implementation namespace for support and library code.
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Trait template for uniform access to function signature types.
Definition function.hpp:144
A special implementation of lib::Sync, where the storage of the object monitor is associated directly...
Helpers for type detection, type rewriting and metaprogramming.