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 {}