| OLD | NEW |
| (Empty) |
| 1 library di.base_injector; | |
| 2 | |
| 3 import 'provider.dart'; | |
| 4 import 'error_helper.dart'; | |
| 5 | |
| 6 import 'package:collection/collection.dart'; | |
| 7 import 'package:di/di.dart'; | |
| 8 | |
| 9 List<Key> _PRIMITIVE_TYPES = new UnmodifiableListView(<Key>[ | |
| 10 new Key(num), new Key(int), new Key(double), new Key(String), | |
| 11 new Key(bool) | |
| 12 ]); | |
| 13 | |
| 14 bool _defaultVisibility(_, __) => true; | |
| 15 | |
| 16 const ResolutionContext _ZERO_DEPTH_RESOLVING = | |
| 17 const ResolutionContext(0, null, null); | |
| 18 | |
| 19 abstract class BaseInjector implements Injector, ObjectFactory { | |
| 20 | |
| 21 @override | |
| 22 final String name; | |
| 23 | |
| 24 @override | |
| 25 final BaseInjector parent; | |
| 26 | |
| 27 Injector _root; | |
| 28 | |
| 29 List<Provider> _providers; | |
| 30 int _providersLen = 0; | |
| 31 | |
| 32 final Map<Key, Object> _instances = <Key, Object>{}; | |
| 33 | |
| 34 @override | |
| 35 final bool allowImplicitInjection; | |
| 36 | |
| 37 Iterable<Type> _typesCache; | |
| 38 | |
| 39 Iterable<Type> get _types { | |
| 40 if (_providers == null) return []; | |
| 41 | |
| 42 if (_typesCache == null) { | |
| 43 _typesCache = _providers | |
| 44 .where((p) => p != null) | |
| 45 .map((p) => p.type); | |
| 46 } | |
| 47 return _typesCache; | |
| 48 } | |
| 49 | |
| 50 BaseInjector({List<Module> modules, String name, | |
| 51 bool allowImplicitInjection: false}) | |
| 52 : this.fromParent(modules, null, | |
| 53 name: name, allowImplicitInjection: allowImplicitInjection); | |
| 54 | |
| 55 BaseInjector.fromParent(List<Module> modules, | |
| 56 BaseInjector this.parent, {this.name, this.allowImplicitInjection}) { | |
| 57 _root = parent == null ? this : parent._root; | |
| 58 var injectorId = new Key(Injector).id; | |
| 59 _providers = new List(lastKeyId + 1); | |
| 60 _providersLen = lastKeyId + 1; | |
| 61 if (modules != null) { | |
| 62 modules.forEach((module) { | |
| 63 module.bindings.forEach((k, v) { | |
| 64 _providers[k] = v; | |
| 65 }); | |
| 66 }); | |
| 67 } | |
| 68 _providers[injectorId] = new ValueProvider(Injector, this); | |
| 69 } | |
| 70 | |
| 71 @override | |
| 72 Injector get root => _root; | |
| 73 | |
| 74 @override | |
| 75 Set<Type> get types { | |
| 76 var types = new Set.from(_types); | |
| 77 var parent = this.parent; | |
| 78 while (parent != null) { | |
| 79 types.addAll(parent._types); | |
| 80 parent = parent.parent; | |
| 81 } | |
| 82 return types; | |
| 83 } | |
| 84 | |
| 85 Object getInstanceByKey(Key key, Injector requester, ResolutionContext resolvi
ng) { | |
| 86 assert(_checkKeyConditions(key, resolving)); | |
| 87 | |
| 88 // Do not bother checking the array until we are fairly deep. | |
| 89 if (resolving.depth > 30 && resolvedTypes(resolving).contains(key)) { | |
| 90 throw new CircularDependencyError( | |
| 91 error(resolving, 'Cannot resolve a circular dependency!', key)); | |
| 92 } | |
| 93 | |
| 94 var providerWithInjector = _getProviderWithInjectorForKey(key, resolving); | |
| 95 var provider = providerWithInjector.provider; | |
| 96 var injector = providerWithInjector.injector; | |
| 97 var visible = provider.visibility != null ? | |
| 98 provider.visibility(requester, injector) : | |
| 99 _defaultVisibility(requester, injector); | |
| 100 | |
| 101 if (visible && _instances.containsKey(key)) return _instances[key]; | |
| 102 | |
| 103 if (providerWithInjector.injector != this || !visible) { | |
| 104 if (!visible) { | |
| 105 if (injector.parent == null) { | |
| 106 throw new NoProviderError( | |
| 107 error(resolving, 'No provider found for ${key}!', key)); | |
| 108 } | |
| 109 injector = injector.parent | |
| 110 ._getProviderWithInjectorForKey(key, resolving).injector; | |
| 111 } | |
| 112 return injector.getInstanceByKey(key, requester, resolving); | |
| 113 } | |
| 114 | |
| 115 resolving = new ResolutionContext(resolving.depth + 1, key, resolving); | |
| 116 var value = provider.get(this, requester, this, resolving); | |
| 117 | |
| 118 // cache the value. | |
| 119 providerWithInjector.injector._instances[key] = value; | |
| 120 return value; | |
| 121 } | |
| 122 | |
| 123 /// Returns a pair for provider and the injector where it's defined. | |
| 124 _ProviderWithDefiningInjector _getProviderWithInjectorForKey( | |
| 125 Key key, ResolutionContext resolving) { | |
| 126 if (key.id < _providersLen) { | |
| 127 var provider = _providers[key.id]; | |
| 128 if (provider != null) { | |
| 129 return new _ProviderWithDefiningInjector(provider, this); | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 if (parent != null) { | |
| 134 return parent._getProviderWithInjectorForKey(key, resolving); | |
| 135 } | |
| 136 | |
| 137 if (allowImplicitInjection) { | |
| 138 return new _ProviderWithDefiningInjector( | |
| 139 new TypeProvider(key.type), this); | |
| 140 } | |
| 141 | |
| 142 throw new NoProviderError( | |
| 143 error(resolving, 'No provider found for ${key}!', key)); | |
| 144 } | |
| 145 | |
| 146 bool _checkKeyConditions(Key key, ResolutionContext resolving) { | |
| 147 if (_PRIMITIVE_TYPES.contains(key)) { | |
| 148 throw new NoProviderError( | |
| 149 error(resolving, | |
| 150 'Cannot inject a primitive type of ${key.type}!', key)); | |
| 151 } | |
| 152 return true; | |
| 153 } | |
| 154 | |
| 155 @override | |
| 156 dynamic get(Type type, [Type annotation]) => | |
| 157 getInstanceByKey(new Key(type, annotation), this, _ZERO_DEPTH_RESOLVING); | |
| 158 | |
| 159 @override | |
| 160 dynamic getByKey(Key key) => | |
| 161 getInstanceByKey(key, this, _ZERO_DEPTH_RESOLVING); | |
| 162 | |
| 163 @override | |
| 164 Injector createChild(List<Module> modules, | |
| 165 {List forceNewInstances, String name}) => | |
| 166 createChildWithResolvingHistory(modules, _ZERO_DEPTH_RESOLVING, | |
| 167 forceNewInstances: forceNewInstances, | |
| 168 name: name); | |
| 169 | |
| 170 Injector createChildWithResolvingHistory( | |
| 171 List<Module> modules, | |
| 172 resolving, | |
| 173 {List forceNewInstances, String name}) { | |
| 174 if (forceNewInstances != null) { | |
| 175 Module forceNew = new Module(); | |
| 176 forceNewInstances.forEach((key) { | |
| 177 if (key is Type) { | |
| 178 key = new Key(key); | |
| 179 } else if (key is! Key) { | |
| 180 throw 'forceNewInstances must be List<Key|Type>'; | |
| 181 } | |
| 182 assert(key is Key); | |
| 183 var providerWithInjector = | |
| 184 _getProviderWithInjectorForKey(key, resolving); | |
| 185 var provider = providerWithInjector.provider; | |
| 186 forceNew.factoryByKey(key, (Injector inj) => provider.get(this, | |
| 187 inj, inj as ObjectFactory, resolving), | |
| 188 visibility: provider.visibility); | |
| 189 }); | |
| 190 | |
| 191 modules = modules.toList(); // clone | |
| 192 modules.add(forceNew); | |
| 193 } | |
| 194 | |
| 195 return newFromParent(modules, name); | |
| 196 } | |
| 197 | |
| 198 newFromParent(List<Module> modules, String name); | |
| 199 | |
| 200 Object newInstanceOf(Type type, ObjectFactory factory, Injector requestor, | |
| 201 resolving); | |
| 202 } | |
| 203 | |
| 204 class _ProviderWithDefiningInjector { | |
| 205 final Provider provider; | |
| 206 final BaseInjector injector; | |
| 207 _ProviderWithDefiningInjector(this.provider, this.injector); | |
| 208 } | |
| 209 | |
| 210 /** | |
| 211 * Information about the context in which the [key] is being resolved, including | |
| 212 * dependency tree [depth] at which the key is being resolved, as well as | |
| 213 * [parent] context (used to determine circular dependencies). | |
| 214 */ | |
| 215 class ResolutionContext { | |
| 216 final int depth; | |
| 217 final Key key; | |
| 218 final ResolutionContext parent; | |
| 219 | |
| 220 const ResolutionContext(this.depth, this.key, this.parent); | |
| 221 } | |
| OLD | NEW |