1 module skadi.container.registration;
2 
3 import skadi.container.interfaces;
4 
5 debug {
6 	import std.stdio;
7 	import std.string;
8 }
9 
10 class Registration
11 {
12 	private TypeInfo _registeredType = null;
13 	private TypeInfo_Class _instantiatableType = null;
14 	private Registration linkedRegistration;
15 
16 	public @property registeredType()
17 	{
18 		return _registeredType;
19 	}
20 
21 	public @property instantiatableType()
22 	{
23 		return _instantiatableType;
24 	}
25 
26 	public CreationScope registationScope = null;
27 
28 	this(TypeInfo registeredType, TypeInfo_Class instantiatableType)
29 	{
30 		this._registeredType = registeredType;
31 		this._instantiatableType = instantiatableType;
32 	}
33 
34 	public Object getInstance(InstantiationContext context = new InstantiationContext())
35 	{
36 		if (linkedRegistration !is null) {
37 			return linkedRegistration.getInstance(context);
38 		}
39 
40 
41 		if (registationScope is null) {
42 			throw new NoScopeDefinedException(registeredType);
43 		}
44 
45 		return registationScope.getInstance();
46 	}
47 
48 	public Registration linkTo(Registration registration)
49 	{
50 		this.linkedRegistration = registration;
51 		return this;
52 	}
53 }
54 
55 class NoScopeDefinedException : Exception
56 {
57 	this(TypeInfo type) {
58 		super("No scope defined for registration of type " ~ type.toString());
59 	}
60 }
61 
62 
63 class NullScope : CreationScope
64 {
65 	public Object getInstance()
66 	{
67 		debug(poodinisVerbose) {
68 			writeln("DEBUG: No instance created (NullScope)");
69 		}
70 		return null;
71 	}
72 }
73 
74 class SingleInstanceScope : CreationScope
75 {
76 	TypeInfo_Class instantiatableType = null;
77 	Object instance = null;
78 
79 	this(TypeInfo_Class instantiatableType) {
80 		this.instantiatableType = instantiatableType;
81 	}
82 
83 	public Object getInstance()
84 	{
85 		if (instance is null) {
86 			debug(poodinisVerbose) {
87 				writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
88 			}
89 			instance = instantiatableType.create();
90 		} else {
91 			debug(poodinisVerbose) {
92 				writeln(format("DEBUG: Existing instance returned of type %s (SingleInstanceScope)", instantiatableType.toString()));
93 			}
94 		}
95 
96 
97 		return instance;
98 	}
99 }
100 
101 /**
102  * Scopes registrations to return the same instance every time a given registration is resolved.
103  *
104  * Effectively makes the given registration a singleton.
105  */
106 public Registration singleInstance(Registration registration)
107 {
108 	registration.registationScope = new SingleInstanceScope(registration.instantiatableType);
109 	return registration;
110 }
111 
112 class NewInstanceScope : CreationScope
113 {
114 	TypeInfo_Class instantiatableType = null;
115 
116 	this(TypeInfo_Class instantiatableType) {
117 		this.instantiatableType = instantiatableType;
118 	}
119 
120 	public Object getInstance() {
121 		debug(poodinisVerbose) {
122 			writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
123 		}
124 		return instantiatableType.create();
125 	}
126 }
127 
128 /**
129  * Scopes registrations to return a new instance every time the given registration is resolved.
130  */
131 public Registration newInstance(Registration registration)
132 {
133 	registration.registationScope = new NewInstanceScope(registration.instantiatableType);
134 	return registration;
135 }
136 
137 class ExistingInstanceScope : CreationScope
138 {
139 	Object instance = null;
140 
141 	this(Object instance) {
142 		this.instance = instance;
143 	}
144 
145 	public Object getInstance() {
146 		debug(poodinisVerbose) {
147 			writeln("DEBUG: Existing instance returned (ExistingInstanceScope)");
148 		}
149 		return instance;
150 	}
151 }
152 
153 /**
154  * Scopes registrations to return the given instance every time the given registration is resolved.
155  */
156 public Registration existingInstance(Registration registration, Object instance)
157 {
158 	registration.registationScope = new ExistingInstanceScope(instance);
159 	return registration;
160 }
161 
162 public string toConcreteTypeListString(Registration[] registrations)
163 {
164 	auto concreteTypeListString = "";
165 	foreach (registration ; registrations) {
166 		if (concreteTypeListString.length > 0) {
167 			concreteTypeListString ~= ", ";
168 		}
169 		concreteTypeListString ~= registration.instantiatableType.toString();
170 	}
171 	return concreteTypeListString;
172 }
173 
174 class InstantiationContext {}