Index: third_party/pkg/di/lib/src/base_injector.dart |
diff --git a/third_party/pkg/di/lib/src/base_injector.dart b/third_party/pkg/di/lib/src/base_injector.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b251cc1a973373ab1fa315b14aae3b052b3c875c |
--- /dev/null |
+++ b/third_party/pkg/di/lib/src/base_injector.dart |
@@ -0,0 +1,221 @@ |
+library di.base_injector; |
+ |
+import 'provider.dart'; |
+import 'error_helper.dart'; |
+ |
+import 'package:collection/collection.dart'; |
+import 'package:di/di.dart'; |
+ |
+List<Key> _PRIMITIVE_TYPES = new UnmodifiableListView(<Key>[ |
+ new Key(num), new Key(int), new Key(double), new Key(String), |
+ new Key(bool) |
+]); |
+ |
+bool _defaultVisibility(_, __) => true; |
+ |
+const ResolutionContext _ZERO_DEPTH_RESOLVING = |
+ const ResolutionContext(0, null, null); |
+ |
+abstract class BaseInjector implements Injector, ObjectFactory { |
+ |
+ @override |
+ final String name; |
+ |
+ @override |
+ final BaseInjector parent; |
+ |
+ Injector _root; |
+ |
+ List<Provider> _providers; |
+ int _providersLen = 0; |
+ |
+ final Map<Key, Object> _instances = <Key, Object>{}; |
+ |
+ @override |
+ final bool allowImplicitInjection; |
+ |
+ Iterable<Type> _typesCache; |
+ |
+ Iterable<Type> get _types { |
+ if (_providers == null) return []; |
+ |
+ if (_typesCache == null) { |
+ _typesCache = _providers |
+ .where((p) => p != null) |
+ .map((p) => p.type); |
+ } |
+ return _typesCache; |
+ } |
+ |
+ BaseInjector({List<Module> modules, String name, |
+ bool allowImplicitInjection: false}) |
+ : this.fromParent(modules, null, |
+ name: name, allowImplicitInjection: allowImplicitInjection); |
+ |
+ BaseInjector.fromParent(List<Module> modules, |
+ BaseInjector this.parent, {this.name, this.allowImplicitInjection}) { |
+ _root = parent == null ? this : parent._root; |
+ var injectorId = new Key(Injector).id; |
+ _providers = new List(lastKeyId + 1); |
+ _providersLen = lastKeyId + 1; |
+ if (modules != null) { |
+ modules.forEach((module) { |
+ module.bindings.forEach((k, v) { |
+ _providers[k] = v; |
+ }); |
+ }); |
+ } |
+ _providers[injectorId] = new ValueProvider(Injector, this); |
+ } |
+ |
+ @override |
+ Injector get root => _root; |
+ |
+ @override |
+ Set<Type> get types { |
+ var types = new Set.from(_types); |
+ var parent = this.parent; |
+ while (parent != null) { |
+ types.addAll(parent._types); |
+ parent = parent.parent; |
+ } |
+ return types; |
+ } |
+ |
+ Object getInstanceByKey(Key key, Injector requester, ResolutionContext resolving) { |
+ assert(_checkKeyConditions(key, resolving)); |
+ |
+ // Do not bother checking the array until we are fairly deep. |
+ if (resolving.depth > 30 && resolvedTypes(resolving).contains(key)) { |
+ throw new CircularDependencyError( |
+ error(resolving, 'Cannot resolve a circular dependency!', key)); |
+ } |
+ |
+ var providerWithInjector = _getProviderWithInjectorForKey(key, resolving); |
+ var provider = providerWithInjector.provider; |
+ var injector = providerWithInjector.injector; |
+ var visible = provider.visibility != null ? |
+ provider.visibility(requester, injector) : |
+ _defaultVisibility(requester, injector); |
+ |
+ if (visible && _instances.containsKey(key)) return _instances[key]; |
+ |
+ if (providerWithInjector.injector != this || !visible) { |
+ if (!visible) { |
+ if (injector.parent == null) { |
+ throw new NoProviderError( |
+ error(resolving, 'No provider found for ${key}!', key)); |
+ } |
+ injector = injector.parent |
+ ._getProviderWithInjectorForKey(key, resolving).injector; |
+ } |
+ return injector.getInstanceByKey(key, requester, resolving); |
+ } |
+ |
+ resolving = new ResolutionContext(resolving.depth + 1, key, resolving); |
+ var value = provider.get(this, requester, this, resolving); |
+ |
+ // cache the value. |
+ providerWithInjector.injector._instances[key] = value; |
+ return value; |
+ } |
+ |
+ /// Returns a pair for provider and the injector where it's defined. |
+ _ProviderWithDefiningInjector _getProviderWithInjectorForKey( |
+ Key key, ResolutionContext resolving) { |
+ if (key.id < _providersLen) { |
+ var provider = _providers[key.id]; |
+ if (provider != null) { |
+ return new _ProviderWithDefiningInjector(provider, this); |
+ } |
+ } |
+ |
+ if (parent != null) { |
+ return parent._getProviderWithInjectorForKey(key, resolving); |
+ } |
+ |
+ if (allowImplicitInjection) { |
+ return new _ProviderWithDefiningInjector( |
+ new TypeProvider(key.type), this); |
+ } |
+ |
+ throw new NoProviderError( |
+ error(resolving, 'No provider found for ${key}!', key)); |
+ } |
+ |
+ bool _checkKeyConditions(Key key, ResolutionContext resolving) { |
+ if (_PRIMITIVE_TYPES.contains(key)) { |
+ throw new NoProviderError( |
+ error(resolving, |
+ 'Cannot inject a primitive type of ${key.type}!', key)); |
+ } |
+ return true; |
+ } |
+ |
+ @override |
+ dynamic get(Type type, [Type annotation]) => |
+ getInstanceByKey(new Key(type, annotation), this, _ZERO_DEPTH_RESOLVING); |
+ |
+ @override |
+ dynamic getByKey(Key key) => |
+ getInstanceByKey(key, this, _ZERO_DEPTH_RESOLVING); |
+ |
+ @override |
+ Injector createChild(List<Module> modules, |
+ {List forceNewInstances, String name}) => |
+ createChildWithResolvingHistory(modules, _ZERO_DEPTH_RESOLVING, |
+ forceNewInstances: forceNewInstances, |
+ name: name); |
+ |
+ Injector createChildWithResolvingHistory( |
+ List<Module> modules, |
+ resolving, |
+ {List forceNewInstances, String name}) { |
+ if (forceNewInstances != null) { |
+ Module forceNew = new Module(); |
+ forceNewInstances.forEach((key) { |
+ if (key is Type) { |
+ key = new Key(key); |
+ } else if (key is! Key) { |
+ throw 'forceNewInstances must be List<Key|Type>'; |
+ } |
+ assert(key is Key); |
+ var providerWithInjector = |
+ _getProviderWithInjectorForKey(key, resolving); |
+ var provider = providerWithInjector.provider; |
+ forceNew.factoryByKey(key, (Injector inj) => provider.get(this, |
+ inj, inj as ObjectFactory, resolving), |
+ visibility: provider.visibility); |
+ }); |
+ |
+ modules = modules.toList(); // clone |
+ modules.add(forceNew); |
+ } |
+ |
+ return newFromParent(modules, name); |
+ } |
+ |
+ newFromParent(List<Module> modules, String name); |
+ |
+ Object newInstanceOf(Type type, ObjectFactory factory, Injector requestor, |
+ resolving); |
+} |
+ |
+class _ProviderWithDefiningInjector { |
+ final Provider provider; |
+ final BaseInjector injector; |
+ _ProviderWithDefiningInjector(this.provider, this.injector); |
+} |
+ |
+/** |
+ * Information about the context in which the [key] is being resolved, including |
+ * dependency tree [depth] at which the key is being resolved, as well as |
+ * [parent] context (used to determine circular dependencies). |
+ */ |
+class ResolutionContext { |
+ final int depth; |
+ final Key key; |
+ final ResolutionContext parent; |
+ |
+ const ResolutionContext(this.depth, this.key, this.parent); |
+} |