1 /+
2 	== oceandrift/di ==
3 	Copyright Elias Batek 2024.
4 	Distributed under the Boost Software License, Version 1.0.
5  +/
6 /++
7 	Lightweight Dependency Injection (DI) framework
8 
9 		$(LIST
10 		* Inversion of Control (IoC).
11 		* Convention over configuration.
12 		* Injects dependencies via constructor parameters.
13 		* Supports structs as well (… as classes and interfaces).
14 		* No clutter – this library is a single, readily comprehensible file.
15 		* No external dependencies. $(I Only the D standard library is used.)
16 	)
17 
18 
19 	### About Dependency Injection
20 
21 	$(SIDEBAR
22 		Dependency Injection is commonly abbreviated as $(B DI).
23 	)
24 
25 	$(BLOCKQUOTE
26 		How does it work?
27 	)
28 
29 	Dependency instances only need to be created once and can be used for all other dependent objects.
30 	As there is only one object of each type, these instances can be called “singletons”.
31 
32 	They can be stored in one big repository, the [DIContainer|dependency container],
33 	and retrieved later as needed.
34 
35 	#### Declaration of dependencies
36 
37 	One of the most useful ways to specify the dependencies of a type (as in `class` or `struct`)
38 	is to declare a constructor with them as parameters.
39 
40 	---
41 	// Example: `LoginService` depends on `PasswordHashUtil`, `DatabaseClient` and `Logger`.
42 	class LoginService {
43 		public this(
44 			PasswordHashUtil passwordHashUtil,
45 			DatabaseClient databaseClient,
46 			Logger logger,
47 		) {
48 			// …
49 		}
50 	}
51 	---
52 
53 	#### Retrieval of dependencies
54 
55 	Getting the dependencies from the container into the service object is where the DI framework comes in.
56 	While the user could manually retrieve them from the container and pass them to the constructor
57 	(i.e. `new LoginService( container.get!PasswordHashUtil(), container.get!Logger(), container.get!DatabaseClient() )`,
58 	this would get tedious quickly.
59 	The framework comes to the resuce.
60 
61 	---
62 	auto di = new DI();
63 	// …
64 
65 	LoginService service = di.resolve!LoginService();
66 	---
67 
68 	#### Registration of dependencies
69 
70 	But where did the `PasswordHashUtil`, the `Logger` and the `DatabaseClient` come from?
71 	How did they get into the DI container?
72 
73 	##### Standalone dependencies
74 
75 	Let’s assume the `PasswordHashUtil` has zero dependencies itself – it is a self-contained service class.
76 	Its constructor has either no parameters
77 	or isn’t declared explicitly (and it uses the implicit default constructor).
78 
79 	The DI framework can easily construct a singleton instance (of the dependency type) on the fly.
80 	This happens automatically the first time one is needed.
81 
82 	---
83 	class PasswordHashUtil {
84 		public string hash(string password) { /* … */ }
85 		public bool verify(string hash, string userPassword) { /* … */ }
86 	}
87 	---
88 
89 	###### Custom dependency registrations
90 
91 	In case a user-provided `PasswordHashUtil` instance has been registered in advance,
92 	the framework will skip the construction and use that one instead.
93 
94 	##### Transitive dependencies
95 
96 	Aka $(I dependencies of a dependency).
97 
98 	The 2nd dependency of the aforementioned `LoginService` is `Logger`.
99 	For illustration purposes, we’ll assume the `Logger` class depends on `Formatter`,
100 	a type that implements formatting facilities.
101 	`Logger` is dependency-less class (like `PasswordHashUtil` was).
102 
103 	The DI framework will retrieve a `Formatter` before it can construct the `Logger`.
104 	Since `Formatter` has not dependencies, the framework can construct it as mentioned in the previous chapter.
105 	If it there is one in the dependency container already, it will be used instead
106 	(and the construction will be skipped).
107 
108 	The next step is to construct a `Logger` which receives the `Formatter` through its constructor.
109 
110 	---
111 	class Logger {
112 		public this(Formatter formatter) {
113 			// …
114 		}
115 		public void log(string message) { /* … */ }
116 	}
117 	---
118 
119 	###### Custom dependency registrations
120 
121 	In case a user-provided `Logger` instance has been registered in advance,
122 	the framework will skip all construction steps and use that one instead.
123 
124 	$(NOTE
125 		If the user-provided `Logger` uses a $(B different) `Formatter` than the one in the dependency container,
126 		the `Logger` of the resulting `LoginService` will use said different `Formatter`,
127 		not the one from the container.
128 
129 		This has no impact on a direct dependencies of `Logger`.
130 		If `Logger` itself depended on `Formatter`, it would still receive the one from the dependency container.
131 		Which in turn would lead to `LoginService.formatter` being different to `Logger.formatter`.
132 
133 		Logically, this distinction would be no longer relevant, if the user registered their `Formatter` instance
134 		with the framework in addition to their custom `Logger` one.
135 	)
136 
137 	##### Complex dependencies
138 
139 	Unlike the dependencies shown in the previous two chapters, however,
140 	the `DatabaseClient` doesn’t depend on a bunch of other services.
141 	Instead it is constructed from four strings (socket, username, password, database name).
142 
143 	While the injection of a `DatabaseClient` into dependent services principally works like before,
144 	the framework cannot instantiate a new one by itself.
145 	Hence it is that an instance has to be registered with the framework in advance.
146 	A user-created `DatabaseClient` can provided by passing it to [oceandrift.di.DI.register|register()].
147 
148 	The framework will pick up on it later, when it constructs `LoginService`
149 	or, failing that, if no custom instance has been registered beforehand,
150 	crash the program as soon as it falls back to instantiating one on its own.
151 
152 	---
153 	class DatabaseClient {
154 		public this(
155 			string socket,
156 			string username,
157 			string password,
158 			string databaseName,
159 		) {
160 			// …
161 		}
162 		public Statement prepare(string sql) { /* … */ }
163 		public void disconnect() { /* … */ }
164 	}
165 
166 	// Construct a DatabaseClient and register it with the DI framework.
167 	auto databaseClient = new DatabaseClient(cfg.socket, cfg,username, cfg.password, cfg.dbName);
168 	di.register(databaseClient);
169 	---
170 
171 
172 	### Unconventional use
173 
174 	This chapter deals with solutions to overcome the conventions of the framework.
175 	(Malicious gossip has it that these are “design limitations”. Don’t listen to them…)
176 
177 	#### Injecting non-singleton instances
178 
179 	Non-singleton objects are sometimes also called “transient” or “prototype”.
180 
181 	By default, the framework will instantiate a singleton instance for each dependency type
182 	and use it for all dependent objects.
183 
184 	When this behavior is not desired, it’s recommended to instantiate a new object in the constructor.
185 	Check out [oceandrift.di.DI.makeNew|makeNew!(T)].
186 
187 	$(TIP
188 		The DI framework can inject a reference to itself.
189 
190 		---
191 		public this(
192 			DI di,
193 		) {
194 			this.dependency = di.makeNew!Dependency();
195 		}
196 		---
197 	)
198 
199 	Alternatively, one could also create a factory type and use that as a dependency instead.
200 
201 	#### Injecting dependencies that are primitive/unsupported types
202 
203 	The recommended way to inject primitives types (like integers, booleans, floating-point numbers, or enums)
204 	or other unsupported types (e.g. strings, other arrays, associative arrays, class pointers or pointers in general)
205 	is to wrap them in a struct.
206 
207 	For pointers, deferencing them might also be an option.
208 
209 
210 
211 
212 	Examples:
213 
214 	### Bootstrapping
215 
216 	Bootstrapping the framework is as simple as:
217 
218 	---
219 	auto di = new DI();
220 	---
221  +/
222 module oceandrift.di;
223 
224 /++
225 	### Extended version of the front-page example
226  +/
227 @safe unittest {
228 	static  // exclude from docs
229 	class Dependency {
230 	}
231 
232 	static  // exclude from docs
233 	class Foo {
234 		private Dependency d;
235 
236 		public this(Dependency d) {
237 			this.d = d;
238 		}
239 	}
240 
241 	// Bootstrap the DI framework.
242 	auto di = new DI();
243 
244 	// Then let it resolve the whole dependency tree
245 	// and construct dependencies as needed.
246 	Foo foo = di.resolve!Foo();
247 
248 	// The DI framework has constructed a new instance of `Dependency`
249 	// and supplied it to the constructor of `Foo`.
250 	assert(foo.d !is null);
251 }
252 
253 /++
254 	### User-supplied dependency instances
255 
256 	$(BLOCKQUOTE
257 		How about types the framework cannot construct on its own?
258 
259 		… or instaces that have been constructed in before and could be reused?
260 	)
261  +/
262 @safe unittest {
263 	static  // exclude from docs
264 	class Dependency {
265 		private int number;
266 
267 		public this(int number) {
268 			this.number = number;
269 		}
270 	}
271 
272 	static  // exclude from docs
273 	class Foo {
274 		private Dependency d;
275 
276 		public this(Dependency d) {
277 			this.d = d;
278 		}
279 	}
280 
281 	auto di = new DI(); // exclude from docs
282 
283 	// Construct an instance of the dependency manually.
284 	// Then register it with the framework.
285 	auto dep = new Dependency(128);
286 	di.register(dep);
287 
288 	// alternative syntax variants (They all come down to the same thing.):
289 	di.register!Dependency(dep);
290 	di.register!Dependency = dep;
291 
292 	// Resolve dependencies of `Foo` and create instance.
293 	Foo foo = di.resolve!Foo();
294 
295 	// The DI framework constructed a new instance of `Dependency`
296 	// and supplied it to the constructor of `Foo`.
297 	assert(foo.d !is null);
298 }
299 
300 /++
301 	### Injecting dependencies that are interfaces
302 
303 	It’s really straightforward:
304 	Tell the framework which implementation type to use for dependencies of an interface type.
305  +/
306 @system unittest {
307 	static  // exclude from docs
308 	interface Logger {
309 		void log(string message);
310 	}
311 
312 	static  // exclude from docs
313 	class StdLogger : Logger {
314 		private int lines = 0;
315 
316 		void log(string message) {
317 			++lines;
318 			// …writeln(message);…
319 		}
320 	}
321 
322 	static  // exclude from docs
323 	class Service {
324 		private Logger logger;
325 
326 		this(Logger logger) {
327 			this.logger = logger;
328 		}
329 
330 		void doSomething() {
331 			this.logger.log("Did something.");
332 		}
333 
334 	}
335 
336 	auto di = new DI(); // exclude from docs
337 
338 	// Register `StdLogger` as the implementation to construct for the
339 	// `Logger` interface.
340 	di.registerInterface!(Logger, StdLogger);
341 
342 	// Now the framework is set up to
343 	// construct an instance of the `Service` class.
344 	Service service1 = di.resolve!Service();
345 
346 	// Our service instance is using the `StdLogger` implementation
347 	// that has been registered a few lines above.
348 	service1.doSomething();
349 	service1.doSomething();
350 	assert(di.resolve!StdLogger().lines == 2);
351 }
352 
353 /++
354 	### Injecting dependencies that are interfaces (Part II)
355 
356 	What if we had a type with a complex constructor,
357 	one that the framework cannot instantiate on its own?
358  +/
359 @system unittest {
360 	static  // exclude from docs
361 	interface Logger {
362 		void log(string message);
363 	}
364 
365 	static  // exclude from docs
366 	class FileLogger : Logger {
367 		private int lines = 0;
368 
369 		this(string logFilePath) {
370 			// …
371 		}
372 
373 		void log(string message) {
374 			++lines;
375 			// …
376 		}
377 	}
378 
379 	static  // exclude from docs
380 	class Service {
381 		private Logger logger;
382 
383 		this(Logger logger) {
384 			this.logger = logger;
385 		}
386 
387 		void doSomething() {
388 			this.logger.log("Did something.");
389 		}
390 
391 	}
392 
393 	auto di = new DI(); // exclude from docs
394 
395 	// Easy. Construct one and register it with the framework.
396 	auto fileLogger = new FileLogger("/dev/null");
397 	di.registerInterface!Logger(fileLogger);
398 
399 	// Now the framework is set up to
400 	// retrieve an instance of the `Service` class.
401 	Service service2 = di.resolve!Service();
402 
403 	// Just for the record:
404 	// The file logger starts with a line count of `0`.
405 	assert(fileLogger.lines == 0);
406 
407 	// Let’s use the service and see whether the supplied logger is used.
408 	service2.doSomething();
409 	assert(fileLogger.lines == 1); // alright!
410 }
411 
412 /++
413 	### DI-constructor generator
414 
415 	> All that typing gets tedious quickly, doesn’t it?
416 
417 	The framework can generate all the constructor boilerplate.
418 	It’s as easy as:
419 
420 	$(NUMBERED_LIST
421 		* Annotate all dependency fields with [dependency|@dependency].
422 		* Add `mixin` [DIConstructor] to your type.
423 		  This generates a constructor with a parameter for each `@dependency` field
424 		  and a body that assigns the values to the corresponding fields.
425 	)
426  +/
427 @safe unittest {
428 	static  // exclude from docs
429 	class Dependency1 {
430 	}
431 
432 	static  // exclude from docs
433 	class Dependency2 {
434 	}
435 
436 	static  // exclude from docs
437 	class Foo {
438 		// Mark dependencies with the attribute `@dependency`:
439 		private @dependency {
440 			Dependency1 d1;
441 			Dependency2 d2;
442 		}
443 
444 		// Let the framework generate the constructor:
445 		mixin DIConstructor;
446 	}
447 
448 	auto di = new DI();
449 	Foo foo = di.resolve!Foo();
450 
451 	// It works:
452 	assert(foo.d1 !is null);
453 	assert(foo.d2 !is null);
454 }
455 
456 import std.conv : to;
457 import std.traits : Parameters;
458 
459 private enum bool isClass(T) = (is(T == class));
460 private enum bool isInterface(T) = (is(T == interface));
461 private enum bool isStruct(T) = (is(T == struct));
462 private enum bool isStructPointer(T) = (is(typeof(*T) == struct));
463 
464 private enum bool hasConstructors(T) = __traits(hasMember, T, "__ctor");
465 
466 private template getConstructors(T) if (hasConstructors!T) {
467 	alias getConstructors = __traits(getOverloads, T, "__ctor");
468 }
469 
470 private template hasParentClass(T) if (isClass!T) {
471 	static if (is(T Parents == super) && Parents.length)
472 		enum hasParentClass = true;
473 	else
474 		enum hasParentClass = false;
475 }
476 
477 private template ParentClass(T) if (isClass!T) {
478 	static if (is(T Parents == super) && Parents.length)
479 		alias ParentClass = Parents[0];
480 	else
481 		static assert(0, "No parent class for type `" ~ T.stringof ~ "`.");
482 }
483 
484 unittest {
485 	static class Parent {
486 	}
487 
488 	static class Child : Parent {
489 	}
490 
491 	static class GrandChild : Child {
492 	}
493 
494 	static assert(hasParentClass!Parent);
495 	static assert(hasParentClass!Child);
496 	static assert(hasParentClass!GrandChild);
497 
498 	static assert(is(ParentClass!Parent == Object));
499 	static assert(is(ParentClass!Child == Parent));
500 	static assert(is(ParentClass!GrandChild == Child));
501 }
502 
503 private template MemberSymbols(alias T, args...) {
504 	import std.meta;
505 
506 	alias MemberSymbols = AliasSeq!();
507 	static foreach (arg; args) {
508 		MemberSymbols = AliasSeq!(MemberSymbols, __traits(getMember, T, arg));
509 	}
510 }
511 
512 unittest {
513 	static class Dings {
514 		int x;
515 		string y;
516 	}
517 
518 	alias mSyms = MemberSymbols!(Dings, "x", "y");
519 	assert(mSyms.length == 2);
520 	assert(is(typeof(mSyms[0]) == int));
521 	assert(is(typeof(mSyms[1]) == string));
522 }
523 
524 private template DerivedMemberSymbols(T, args...) {
525 	alias DerivedMemberSymbols = MemberSymbols!(T, __traits(derivedMembers, T));
526 }
527 
528 unittest {
529 	static class Dings {
530 		int x;
531 		string y;
532 	}
533 
534 	alias mSyms = DerivedMemberSymbols!(Dings);
535 	assert(mSyms.length == 2);
536 	assert(is(typeof(mSyms[0]) == int));
537 	assert(is(typeof(mSyms[1]) == string));
538 }
539 
540 private template callerParameterListString(params...) {
541 	private string impl() {
542 		string r = "";
543 		foreach (idx, P; params) {
544 			static if (isStruct!P) {
545 				r ~= '*';
546 			}
547 			r ~= "param" ~ idx.to!string() ~ ',';
548 		}
549 		return r;
550 	}
551 
552 	enum callerParameterListString = impl();
553 }
554 
555 private {
556 	template keyOf(T) if (isClass!T || isInterface!T || isStructPointer!T) {
557 		private static immutable string keyOf = T.mangleof;
558 	}
559 
560 	template keyOf(T) if (isStruct!T) {
561 		private static immutable string keyOf = keyOf!(T*);
562 	}
563 }
564 
565 /++
566 	Determines whether a type `T` is supported to be used as dependency by the framework.
567 
568 	Currently this includes:
569 	$(LIST
570 		* Classes – `class`
571 		* Interfaces – `interface`
572 		* Structs – `struct`
573 		* Struct pointers – `struct*`
574 	)
575 
576 	See_Also:
577 		[isConstructableByDI] that determines whether a type can be constructed by the framework on its own.
578  +/
579 public enum bool isSupportedDependencyType(T) = (isClass!T || isInterface!T || isStruct!T || isStructPointer!T);
580 
581 /++
582 	Determines whether a type `T` is denied for user registration.
583  +/
584 public enum bool isForbiddenType(T) = is(T == Container) || is(T == DI);
585 
586 /++
587 	Determines whether a type `T` is applicable for user registration.
588  +/
589 public enum bool isntForbiddenType(T) = !(isForbiddenType!T);
590 
591 /++
592 	Determines $(I why) a type `T` is not constructable by the DI framework.
593 
594 	Returns:
595 	$(LIST
596 		* `string` = reason
597 		* `null` = is constructable, in fact
598 	)
599  +/
600 public template determineWhyNotConstructableByDI(T) {
601 
602 	/// ditto
603 	public static immutable string determineWhyNotConstructableByDI = impl();
604 
605 	private string impl() {
606 		static if (isSupportedDependencyType!T == false) {
607 			return "DI cannot construct an instance of type `"
608 				~ T.stringof
609 				~ "` that is not a supported dependency type in the first place.";
610 		} else static if (isInterface!T) {
611 			return "DI cannot construct an instance of type `"
612 				~ T.stringof
613 				~ "` that is an `interface`.";
614 		} else static if (hasConstructors!T == false) {
615 			return null;
616 		} else {
617 			alias ctors = getConstructors!T;
618 			if (ctors.length > 1) {
619 				return "DI cannot construct an instance of type `"
620 					~ T.stringof
621 					~ "` with multiple constructors.";
622 			}
623 
624 			alias params = Parameters!(ctors[0]);
625 			foreach (idx, P; params) {
626 				if (isSupportedDependencyType!P == false) {
627 					// Trick the detection of unreachable statements found in older compilers.
628 					bool neverTrue = false;
629 					if (neverTrue) {
630 						break;
631 					}
632 
633 					return "DI cannot construct an instance of type `"
634 						~ T.stringof
635 						~ "` because its dependency #"
636 						~ idx.to!string
637 						~ " `"
638 						~ P.stringof
639 						~ "` is not a supported type.";
640 				}
641 			}
642 
643 			return null;
644 		}
645 	}
646 }
647 
648 /++
649 	Determines whether a type `T` is constructable by the DI framework.
650 
651 	See_Also:
652 		[isSupportedDependencyType] that determines whether a type can be used as a dependency.
653  +/
654 public enum bool isConstructableByDI(T) = (determineWhyNotConstructableByDI!T is null);
655 
656 @safe unittest {
657 	class Class {
658 	}
659 
660 	class ClassWithIntegerParamCtor {
661 		this(int) {
662 		}
663 	}
664 
665 	interface Interface {
666 	}
667 
668 	struct Struct {
669 	}
670 
671 	assert(isConstructableByDI!Class);
672 	assert(isConstructableByDI!ClassWithIntegerParamCtor == false);
673 	assert(isConstructableByDI!Interface == false);
674 	assert(isConstructableByDI!Struct);
675 	assert(isConstructableByDI!int == false);
676 	assert(isConstructableByDI!string == false);
677 	assert(isConstructableByDI!(int[]) == false);
678 }
679 
680 /++
681 	Dependency Container
682 
683 	Used to store singleton instances of dependency types.
684 	This is the underlying container implementation used by [DI].
685  +/
686 private final class Container {
687 @safe pure nothrow:
688 
689 	private {
690 		alias voidptr = void*;
691 		voidptr[string] _data;
692 	}
693 
694 	///
695 	public this() {
696 		this.setSelf();
697 	}
698 
699 	/++
700 		Returns a stored value by key
701 	 +/
702 	void* get(string key) @nogc {
703 		void** ptrptr = (key in _data);
704 		if (ptrptr is null) {
705 			return null;
706 		}
707 
708 		return *ptrptr;
709 	}
710 
711 	private T getTImpl(T)() @nogc {
712 		void* ptr = this.get(keyOf!T);
713 		return (function(void* ptr) @trusted => cast(T) ptr)(ptr);
714 	}
715 
716 	/++
717 		Returns a stored value by class, interface or struct-pointer type
718 	 +/
719 	T get(T)() @nogc if (isClass!T || isInterface!T || isStructPointer!T) {
720 		return getTImpl!T();
721 	}
722 
723 	/++
724 		Returns a stored value by struct
725 	 +/
726 	T* get(T)() @nogc if (isStruct!T) {
727 		return getTImpl!(T*)();
728 	}
729 
730 	/++
731 		Determines whether a value matching the provided key is stored
732 	 +/
733 	bool has(string key) @nogc {
734 		return (this.get(key) !is null);
735 	}
736 
737 	/// ditto
738 	bool has(T)() @nogc {
739 		return this.has(keyOf!T);
740 	}
741 
742 	// CAUTION: This function cannot be exposed publicly for @safe-ty guarantees
743 	private void set(string key, void* value) {
744 		_data[key] = value;
745 	}
746 
747 	private void setTImpl(T)(T value) {
748 		pragma(inline, true);
749 		void* ptr = (function(T value) @trusted => cast(void*) value)(value);
750 		this.set(keyOf!T, ptr);
751 	}
752 
753 	/++
754 		Stores the provided class instance
755 	 +/
756 	void set(T)(T value) if ((isClass!T || isInterface!T) && (isntForbiddenType!T)) {
757 		this.setTImpl!T(value);
758 	}
759 
760 	/++
761 		Stores the provided pointer to a struct instance
762 	 +/
763 	void set(T)(T* value) if (isStruct!T) {
764 		this.setTImpl!(T*)(value);
765 	}
766 
767 	private void setSelf() {
768 		this.setTImpl!Container(this);
769 	}
770 
771 	private void setDI(DI value) {
772 		this.setTImpl!DI(value);
773 	}
774 }
775 
776 /// ditto
777 public alias DIContainer = Container;
778 
779 /++
780 	Dependency Injection
781 
782 	This is the flagship class of the framework.
783  +/
784 final class DI {
785 	private {
786 		Container _container;
787 	}
788 
789 	///
790 	this(DIContainer container) @safe pure nothrow {
791 		// main ctor
792 		_container = container;
793 		_container.setDI = this;
794 	}
795 
796 	///
797 	this() @safe pure nothrow {
798 		this(new Container());
799 	}
800 
801 	private auto resolveImpl(T)() if (isSupportedDependencyType!T) {
802 		pragma(inline, true);
803 
804 		auto instance = _container.get!T();
805 
806 		if (instance is null) {
807 			instance = this.makeNew!T();
808 			this.register!T = instance;
809 		}
810 
811 		return instance;
812 	}
813 
814 	/++
815 		Returns the singleton instance of the requested type.
816 
817 		Automatically constructs a new one if needed.
818 	 +/
819 	T resolve(T)() if (isClass!T || isInterface!T || isStructPointer!T) {
820 		return this.resolveImpl!T();
821 	}
822 
823 	/// ditto
824 	T* resolve(T)() if (isStruct!T) {
825 		return this.resolveImpl!(T*)();
826 	}
827 
828 	/++
829 		Stores the provided instance of type `T` in the DI container.
830 		This registered instance will be injected for dependencies of type `T`.
831 
832 		$(TIP
833 			This function can be used to supply instances of types the DI framework cannot construct on its own
834 			for further use by the DI.
835 
836 			Nonetheless, types must be [isSupportedDependencyType|supported dependency types].
837 		)
838 
839 		$(NOTE
840 			Overrides a previously stored instance if applicable.
841 		)
842 
843 		See_Also:
844 			[registerInterface] to setup which implementation class (resp. instance)
845 			to inject for dependencies that specify an $(I interface) instead of a concrete type.
846 	 +/
847 	void register(T)(T value) @safe pure nothrow {
848 		static assert(
849 			isClass!T || isInterface!T || isStructPointer!T,
850 			"Cannot store instance of type `" ~ T.stringof ~ "`. Not a class, interface or struct-pointer."
851 		);
852 		static assert(
853 			isntForbiddenType!T,
854 			"Cannot override the referenced framework instance of type `" ~ T.stringof ~ "`."
855 		);
856 
857 		_container.set(value);
858 	}
859 
860 	/++
861 		Stores the provided instance of type `TClass` in the DI container
862 		to be injected for dependencies of both types `TInterface` and `TClass` later.
863 	 +/
864 	void registerInterface(TInterface, TClass)(TClass value) @safe pure nothrow {
865 		this.register!TClass(value);
866 		this.register!TInterface(value);
867 	}
868 
869 	/// ditto
870 	void registerInterface(TInterface, TClass)() {
871 		this.registerInterface!(TInterface, TClass)(
872 			this.resolve!TClass()
873 		);
874 	}
875 
876 	private T* makeNew(T)() if (isStruct!T) {
877 		return new T();
878 	}
879 
880 	private T makeNew(T)() if (isStructPointer!T) {
881 		return new typeof(*T)();
882 	}
883 
884 	/++
885 		Instantiates a new instance of the specified type `T`.
886 
887 		Dependencies will be assigned from the underlying container.
888 	 +/
889 	T makeNew(T)() if (isClass!T || isInterface!T) {
890 		static if (isConstructableByDI!T == false) {
891 			// not constructable --> crash
892 			assert(false, determineWhyNotConstructableByDI!T);
893 		} else {
894 			// construct
895 			return this.makeNewImpl!T();
896 		}
897 	}
898 
899 	private {
900 		T makeNewImplWithDependencies(T)() {
901 			pragma(inline, true);
902 
903 			alias ctors = getConstructors!T;
904 			static assert(ctors.length == 1, "Seems like there's a bug in `isConstructableByDI`.");
905 			alias ctorParams = Parameters!(ctors[0]);
906 
907 			static foreach (idx, P; ctorParams) {
908 				static if (isStruct!P) {
909 					version (diNoPassByValue) {
910 						static assert(
911 							false,
912 							"Passing dependency #"
913 								~ idx.to!string()
914 								~ " `"
915 								~ P.stringof
916 								~ "` by value (copy) to `"
917 								~ T.stringof
918 								~ "`.\n            Use a pointer (`"
919 								~ P.stringof
920 								~ "*`) instead. [`-version=diNoPassByValue`]"
921 						);
922 					}
923 					mixin(`P* param` ~ idx.to!string() ~ ';');
924 				} else {
925 					mixin(`P param` ~ idx.to!string() ~ ';');
926 				}
927 
928 				mixin(`param` ~ idx.to!string()) = this.resolve!P();
929 			}
930 
931 			return mixin(`new T(` ~ callerParameterListString!(ctorParams) ~ `)`);
932 		}
933 
934 		T makeNewImpl(T)() {
935 			pragma(inline, true);
936 
937 			static if (hasConstructors!T) {
938 				return this.makeNewImplWithDependencies!T();
939 			} else {
940 				// There is no explicit ctor available, use default one.
941 				return new T();
942 			}
943 		}
944 	}
945 }
946 
947 /++
948 	UDA to mark fields as dependency for $(I Field Assignment Constructor Application).
949  +/
950 enum dependency;
951 
952 private template hasDependencyUDA(alias T) {
953 	import std.traits : hasUDA;
954 
955 	enum hasDependencyUDA = hasUDA!(T, dependency);
956 }
957 
958 // undocumented
959 enum _diConstructorUDA;
960 
961 /++
962 	Generates a constructor with a parameter for each [dependency|@dependency] field
963 	and assigns the passed value to the corresponding field.
964  +/
965 mixin template DIConstructor() {
966 	import oceandrift.di : dependency, diConstructorString, _diConstructorUDA;
967 
968 	mixin(diConstructorString!(typeof(this)));
969 }
970 
971 /++
972 	Generates code for a constructor with a parameter for each [dependency|@dependency] field
973 	and assigns the passed value to the corresponding field.
974 
975 	---
976 	class MyType {
977 		mixin(diConstructorString!(typeof(this)));
978 	}
979 	---
980 
981 	See_Also: [DIConstructor]
982  +/
983 template diConstructorString(T) {
984 	private string impl() {
985 		import std.meta;
986 		import std.traits;
987 
988 		alias deps = Filter!(hasDependencyUDA, DerivedMemberSymbols!T);
989 
990 		static if (isStruct!T && (deps.length == 0)) {
991 			return "";
992 		} else {
993 			string r = "public this(";
994 
995 			// determine parent dependencies
996 			static if (isClass!T && hasParentClass!T) {
997 				alias parentCtor = getSymbolsByUDA!(ParentClass!T, _diConstructorUDA);
998 				static assert(parentCtor.length <= 1, "Misuse of @_diConstructorUDA detected.");
999 
1000 				static if (parentCtor.length == 1) {
1001 					alias depsParent = ParameterIdentifierTuple!parentCtor;
1002 				} else {
1003 					enum depsParent = [];
1004 				}
1005 			} else {
1006 				enum depsParent = [];
1007 			}
1008 
1009 			// parent ctor params
1010 			static foreach (d; depsParent) {
1011 				r ~= "typeof(super." ~ d ~ ")" ~ d ~ ",";
1012 			}
1013 
1014 			// params
1015 			static foreach (d; deps) {
1016 				r ~= "typeof(this." ~ __traits(identifier, d) ~ ")" ~ __traits(identifier, d) ~ ",";
1017 			}
1018 
1019 			r ~= ")@_diConstructorUDA @safe pure nothrow @nogc{";
1020 
1021 			// parent ctor
1022 			static if (depsParent.length > 0) {
1023 				r ~= "super(";
1024 				static foreach (d; depsParent) {
1025 					r ~= d ~ ',';
1026 				}
1027 				r ~= ");";
1028 			}
1029 
1030 			// assignments
1031 			static foreach (d; deps) {
1032 				r ~= "this." ~ __traits(identifier, d) ~ '=' ~ __traits(identifier, d) ~ ';';
1033 			}
1034 
1035 			r ~= '}';
1036 
1037 			return r;
1038 		}
1039 	}
1040 
1041 	// undocumented
1042 	enum string diConstructorString = impl();
1043 }
1044 
1045 @safe unittest {
1046 	static class Point {
1047 		mixin DIConstructor;
1048 	@dependency:
1049 		int x;
1050 		int y;
1051 	}
1052 
1053 	const p = new Point(12, 24);
1054 	assert(p.x == 12);
1055 	assert(p.y == 24);
1056 }
1057 
1058 @safe unittest {
1059 	static class Point {
1060 		mixin DIConstructor;
1061 		int x;
1062 		int y;
1063 	}
1064 
1065 	const p = new Point();
1066 }
1067 
1068 @safe unittest {
1069 	static struct Point {
1070 		mixin DIConstructor;
1071 	private @dependency:
1072 		int x;
1073 		int y;
1074 	}
1075 
1076 	const p = Point(12, 24);
1077 	assert(p.x == 12);
1078 	assert(p.y == 24);
1079 }
1080 
1081 @safe unittest {
1082 	static struct Point {
1083 		mixin DIConstructor;
1084 		int x;
1085 		int y;
1086 	}
1087 
1088 	const p = Point();
1089 }
1090 
1091 @safe unittest {
1092 	static class Point {
1093 		mixin DIConstructor;
1094 		int x;
1095 		int y;
1096 	}
1097 
1098 	const p = new Point();
1099 }
1100 
1101 @safe unittest {
1102 	static class Point {
1103 		mixin DIConstructor;
1104 	@dependency:
1105 		const int x;
1106 		const int y;
1107 	}
1108 
1109 	const p = new Point(1, 2);
1110 	assert(p.x == 1);
1111 	assert(p.y == 2);
1112 }
1113 
1114 @safe unittest {
1115 	static class Dimension1 {
1116 		mixin DIConstructor;
1117 	@dependency:
1118 		int x;
1119 	}
1120 
1121 	static class Dimension2 : Dimension1 {
1122 		mixin DIConstructor;
1123 	@dependency:
1124 		int y;
1125 	}
1126 
1127 	static class Dimension3 : Dimension2 {
1128 		mixin DIConstructor;
1129 	@dependency:
1130 		int z;
1131 	}
1132 
1133 	const d1 = new Dimension1(8);
1134 	assert(d1.x == 8);
1135 
1136 	const d2 = new Dimension2(12, 24);
1137 	assert(d2.x == 12);
1138 	assert(d2.y == 24);
1139 
1140 	const d3 = new Dimension3(1, 5, 9);
1141 	assert(d3.x == 1);
1142 	assert(d3.y == 5);
1143 	assert(d3.z == 9);
1144 }
1145 
1146 // == Container Tests
1147 
1148 @safe unittest {
1149 	static struct Foo {
1150 		int i = 10;
1151 	}
1152 
1153 	static class Bar {
1154 		int i = 10;
1155 	}
1156 
1157 	auto c = new Container();
1158 	assert(c.has!Foo() == false);
1159 	assert(c.has!Bar() == false);
1160 	assert(c.get!Foo() is null);
1161 	assert(c.get!Bar() is null);
1162 
1163 	auto origFoo = new Foo();
1164 	origFoo.i = 2;
1165 	auto origBar = new Bar();
1166 	origBar.i = 3;
1167 
1168 	c.set(origFoo);
1169 	c.set(origBar);
1170 	assert(c.has!Foo());
1171 	assert(c.has!Bar());
1172 	assert(c.get!Foo() !is null);
1173 	assert(c.get!Bar() !is null);
1174 
1175 	auto cFoo = c.get!Foo();
1176 	auto cBar = c.get!Bar();
1177 	assert(cFoo.i == 2);
1178 	assert(cBar.i == 3);
1179 	assert(cFoo is origFoo);
1180 	assert(cBar is origBar);
1181 
1182 	cFoo.i = 4;
1183 	assert(origFoo.i == 4);
1184 
1185 	c.set!Foo(null);
1186 	assert(c.has!Foo() == false);
1187 
1188 	c.set!Bar(null);
1189 	assert(c.has!Bar() == false);
1190 }
1191 
1192 // == DI Tests
1193 
1194 @safe unittest {
1195 	static class Bar {
1196 		int i = 10;
1197 	}
1198 
1199 	static class Foo {
1200 		Bar bar;
1201 
1202 		this(Bar bar) {
1203 			this.bar = bar;
1204 		}
1205 	}
1206 
1207 	auto di = new DI();
1208 	Foo foo = di.resolve!Foo();
1209 	assert(foo !is null);
1210 	assert(foo.bar !is null);
1211 
1212 	// Test singleton behavior
1213 	assert(foo.bar.i == 10);
1214 	Bar bar = di.resolve!Bar();
1215 	bar.i = 2;
1216 	assert(foo.bar.i == 2);
1217 }
1218 
1219 @safe unittest {
1220 	static struct Bar {
1221 		int i = 10;
1222 	}
1223 
1224 	static class Foo {
1225 		Bar bar;
1226 
1227 		this(Bar bar) {
1228 			this.bar = bar;
1229 		}
1230 	}
1231 
1232 	auto di = new DI();
1233 	Bar* bar = di.resolve!Bar();
1234 	bar.i = 2;
1235 
1236 	Foo foo = di.resolve!Foo();
1237 	bar.i = 3;
1238 	assert(foo.bar.i == 2);
1239 }
1240 
1241 @safe unittest {
1242 	static class H1 {
1243 	}
1244 
1245 	static class H2 {
1246 		this(H1 d) {
1247 		}
1248 	}
1249 
1250 	static class H3 {
1251 		this(H2 d) {
1252 		}
1253 	}
1254 
1255 	static class H4 {
1256 		this(H3 d) {
1257 		}
1258 	}
1259 
1260 	static class H5 {
1261 		this(H4 d, H1 d2) {
1262 		}
1263 	}
1264 
1265 	static class H6 {
1266 		this(H5 d) {
1267 		}
1268 	}
1269 
1270 	auto di = new DI();
1271 	H6 h6 = di.resolve!H6();
1272 	assert(h6 !is null);
1273 }