dartin.dart 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright 2018 The Fuchsia Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. class DartInScope {
  5. final String _name;
  6. /// Constructor
  7. const DartInScope(this._name);
  8. @override
  9. String toString() {
  10. return "Scope ('$_name')";
  11. }
  12. }
  13. /// DartIns are the values passed to the [DartInNodes].
  14. ///
  15. /// DartIns can be added to using either convenience functions such as
  16. /// [provideValue] or by passing in DartIns.
  17. class DartIns {
  18. // The DartIn for each given [Type] should return that type, but we can't
  19. // enforce that here directly. We can use APIs to make sure it's type-safe.
  20. final Map<DartInScope, Map<Type, DartIn<dynamic>>> _providers = {};
  21. /// Creates a new empty provider.
  22. DartIns();
  23. /// The default scope in which any type not with a defined scope resides.
  24. static const DartInScope defaultScope = DartInScope('_default');
  25. /// Creates a provider with the included providers.
  26. ///
  27. /// If a scope is provided, the values will be under that scope.
  28. factory DartIns.withDartIns(Map<Type, DartIn<dynamic>> providers, {DartInScope scope}) => DartIns()..provideAll(providers, scope: scope);
  29. /// Add a provider for a single type.
  30. ///
  31. /// Will override any existing provider of that type in this node with the
  32. /// given scope. If no [scope] is passed in, the default one will be used.
  33. void provide<T>(DartIn<T> provider, {DartInScope scope}) {
  34. // This should never happen.
  35. // assert(provider.type == T);
  36. _providersForScope(scope)[provider.type] = provider;
  37. }
  38. /// Provide many providers at once.
  39. ///
  40. /// Prefer using [provide] and [provideFrom] because that catches type
  41. /// errors at compile-time.
  42. void provideAll(Map<Type, DartIn> providers, {DartInScope scope}) {
  43. for (var entry in providers.entries) {
  44. if (entry.key != entry.value.type) {
  45. if (entry.value.type == dynamic) {
  46. throw ArgumentError('Not able to infer the type of provider for'
  47. ' ${entry.key} automatically. Add type argument to provider.');
  48. }
  49. throw ArgumentError('Type mismatch between ${entry.key} and provider '
  50. 'of ${entry.value.type}.');
  51. }
  52. }
  53. _providersForScope(scope).addAll(providers);
  54. }
  55. /// Add in all the providers from another DartIns.
  56. void provideFrom(DartIns other) {
  57. for (final scope in other._providers.keys) {
  58. provideAll(other._providersForScope(scope), scope: scope);
  59. }
  60. }
  61. /// Syntactic sugar around adding a value based provider.
  62. ///
  63. /// If this value is [Listenable], widgets that use this value can be rebuilt
  64. /// on change. If no [scope] is passed in, the default one will be used.
  65. void provideValue<T>(T value, {DartInScope scope}) {
  66. provide(DartIn._value(value), scope: scope);
  67. }
  68. DartIn<T> getFromType<T>({DartInScope scope}) {
  69. return _providersForScope(scope)[T];
  70. }
  71. T value<T>({DartInScope scope, List values}) {
  72. return getFromType<T>(scope: scope)?.get(values: values);
  73. }
  74. Map<Type, DartIn<dynamic>> _providersForScope(scope) => _providers[scope ?? defaultScope] ??= {};
  75. }
  76. /// A DartIn provides a value on request.
  77. ///
  78. /// If a provider implements [Listenable], it will be listened to by the
  79. /// [Provide] widget to rebuild on change. Other than the built in providers,
  80. /// one can implement DartIn to provide caching or linkages.
  81. ///
  82. /// When a DartIn is instantiated within a [providers.provide] call, the type
  83. /// can be inferred and therefore the type can be ommited, but otherwise,
  84. /// [T] is required.
  85. ///
  86. /// DartIn should be implemented and not extended.
  87. abstract class DartIn<T> {
  88. /// Returns the value provided by the provider.
  89. ///
  90. /// Because providers could potentially initialize the value each time [get]
  91. /// is called, this should be called as infrequently as possible.
  92. T get({List values});
  93. /// The type that is provided by the provider.
  94. Type get type;
  95. /// Creates a provider with the value provided to it.
  96. factory DartIn._value(T value) => _ValueDartIn(value);
  97. /// Creates a provider which will initialize using the [_DartInFunction]
  98. /// the first time the value is requested.
  99. ///
  100. /// The context can be used to obtain other values from the provider. However,
  101. /// care should be taken with this to not have circular dependencies.
  102. factory DartIn._lazy(_DartInFunction<T> function) => _LazyDartIn<T>(function);
  103. /// Creates a provider that provides a new value for each
  104. /// requestor of the value.
  105. factory DartIn._withFactory(_DartInFunction<T> function) => _FactoryDartIn<T>(function);
  106. }
  107. /// Base mixin for providers.
  108. abstract class _TypedDartIn<T> implements DartIn<T> {
  109. /// The type of the provider
  110. @override
  111. Type get type => T;
  112. }
  113. /// Contains a value which will never be disposed.
  114. class _ValueDartIn<T> extends _TypedDartIn<T> {
  115. final T _value;
  116. @override
  117. T get({List values}) => _value;
  118. _ValueDartIn(this._value);
  119. }
  120. /// Function that returns an instance of T when called.
  121. typedef _DartInFunction<T> = T Function({_ParameterList params});
  122. /// Is initialized on demand, and disposed when no longer needed
  123. /// if [dispose] is set to true.
  124. /// When obtained statically, the value will never be disposed.
  125. class _LazyDartIn<T> with _TypedDartIn<T> {
  126. final _DartInFunction<T> _initalizer;
  127. T _value;
  128. _LazyDartIn(this._initalizer);
  129. @override
  130. T get({List values}) {
  131. // Need to have a local copy for casting because
  132. // dart requires it.
  133. T value;
  134. if (_value == null) {
  135. value = _value ??= _initalizer(params: _ParameterList.parametersOf(values));
  136. }
  137. return _value;
  138. }
  139. }
  140. /// A provider who's value is obtained from providerFunction for each time the
  141. /// value is requested.
  142. ///
  143. /// This provider doesn't keep any values itself, so those values are disposed
  144. /// when the containing widget is disposed.
  145. class _FactoryDartIn<T> with _TypedDartIn<T> {
  146. final _DartInFunction<T> providerFunction;
  147. _FactoryDartIn(this.providerFunction);
  148. @override
  149. T get({List values}) => providerFunction(params: _ParameterList.parametersOf(values));
  150. }
  151. class Module {
  152. final List<DartIn> providerIns;
  153. Module(this.providerIns);
  154. }
  155. class _ParameterList {
  156. final List<Object> values;
  157. get(int i) {
  158. if (values == null || i > values.length - 1 || i < 0) {
  159. return null;
  160. }
  161. return values[i];
  162. }
  163. _ParameterList.parametersOf(this.values);
  164. }
  165. DartIn<T> factory<T>(_DartInFunction<T> value,{String scope }) => DartIn<T>._withFactory(value);
  166. DartIn<T> single<T>(T value) => DartIn<T>._value(value);
  167. DartIn<T> lazy<T>(_DartInFunction<T> value) => DartIn<T>._lazy(value);
  168. T get<T>({DartInScope scope, List params}) {
  169. assert(_dartIns != null);
  170. return _dartIns.value<T>(scope: scope, values: params);
  171. }
  172. T inject<T>({DartInScope scope, List params}) => get<T>(scope: scope, params: params);
  173. DartIns _dartIns;
  174. startDartIn(List<Module> modules) {
  175. _dartIns = DartIns();
  176. for (var module in modules) {
  177. for (var providerIn in module.providerIns) {
  178. _dartIns.provide(providerIn);
  179. }
  180. }
  181. }