| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- // Copyright 2018 The Fuchsia Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- class DartInScope {
- final String _name;
- /// Constructor
- const DartInScope(this._name);
- @override
- String toString() {
- return "Scope ('$_name')";
- }
- }
- /// DartIns are the values passed to the [DartInNodes].
- ///
- /// DartIns can be added to using either convenience functions such as
- /// [provideValue] or by passing in DartIns.
- class DartIns {
- // The DartIn for each given [Type] should return that type, but we can't
- // enforce that here directly. We can use APIs to make sure it's type-safe.
- final Map<DartInScope, Map<Type, DartIn<dynamic>>> _providers = {};
- /// Creates a new empty provider.
- DartIns();
- /// The default scope in which any type not with a defined scope resides.
- static const DartInScope defaultScope = DartInScope('_default');
- /// Creates a provider with the included providers.
- ///
- /// If a scope is provided, the values will be under that scope.
- factory DartIns.withDartIns(Map<Type, DartIn<dynamic>> providers, {DartInScope scope}) => DartIns()..provideAll(providers, scope: scope);
- /// Add a provider for a single type.
- ///
- /// Will override any existing provider of that type in this node with the
- /// given scope. If no [scope] is passed in, the default one will be used.
- void provide<T>(DartIn<T> provider, {DartInScope scope}) {
- // This should never happen.
- // assert(provider.type == T);
- _providersForScope(scope)[provider.type] = provider;
- }
- /// Provide many providers at once.
- ///
- /// Prefer using [provide] and [provideFrom] because that catches type
- /// errors at compile-time.
- void provideAll(Map<Type, DartIn> providers, {DartInScope scope}) {
- for (var entry in providers.entries) {
- if (entry.key != entry.value.type) {
- if (entry.value.type == dynamic) {
- throw ArgumentError('Not able to infer the type of provider for'
- ' ${entry.key} automatically. Add type argument to provider.');
- }
- throw ArgumentError('Type mismatch between ${entry.key} and provider '
- 'of ${entry.value.type}.');
- }
- }
- _providersForScope(scope).addAll(providers);
- }
- /// Add in all the providers from another DartIns.
- void provideFrom(DartIns other) {
- for (final scope in other._providers.keys) {
- provideAll(other._providersForScope(scope), scope: scope);
- }
- }
- /// Syntactic sugar around adding a value based provider.
- ///
- /// If this value is [Listenable], widgets that use this value can be rebuilt
- /// on change. If no [scope] is passed in, the default one will be used.
- void provideValue<T>(T value, {DartInScope scope}) {
- provide(DartIn._value(value), scope: scope);
- }
- DartIn<T> getFromType<T>({DartInScope scope}) {
- return _providersForScope(scope)[T];
- }
- T value<T>({DartInScope scope, List values}) {
- return getFromType<T>(scope: scope)?.get(values: values);
- }
- Map<Type, DartIn<dynamic>> _providersForScope(scope) => _providers[scope ?? defaultScope] ??= {};
- }
- /// A DartIn provides a value on request.
- ///
- /// If a provider implements [Listenable], it will be listened to by the
- /// [Provide] widget to rebuild on change. Other than the built in providers,
- /// one can implement DartIn to provide caching or linkages.
- ///
- /// When a DartIn is instantiated within a [providers.provide] call, the type
- /// can be inferred and therefore the type can be ommited, but otherwise,
- /// [T] is required.
- ///
- /// DartIn should be implemented and not extended.
- abstract class DartIn<T> {
- /// Returns the value provided by the provider.
- ///
- /// Because providers could potentially initialize the value each time [get]
- /// is called, this should be called as infrequently as possible.
- T get({List values});
- /// The type that is provided by the provider.
- Type get type;
- /// Creates a provider with the value provided to it.
- factory DartIn._value(T value) => _ValueDartIn(value);
- /// Creates a provider which will initialize using the [_DartInFunction]
- /// the first time the value is requested.
- ///
- /// The context can be used to obtain other values from the provider. However,
- /// care should be taken with this to not have circular dependencies.
- factory DartIn._lazy(_DartInFunction<T> function) => _LazyDartIn<T>(function);
- /// Creates a provider that provides a new value for each
- /// requestor of the value.
- factory DartIn._withFactory(_DartInFunction<T> function) => _FactoryDartIn<T>(function);
- }
- /// Base mixin for providers.
- abstract class _TypedDartIn<T> implements DartIn<T> {
- /// The type of the provider
- @override
- Type get type => T;
- }
- /// Contains a value which will never be disposed.
- class _ValueDartIn<T> extends _TypedDartIn<T> {
- final T _value;
- @override
- T get({List values}) => _value;
- _ValueDartIn(this._value);
- }
- /// Function that returns an instance of T when called.
- typedef _DartInFunction<T> = T Function({_ParameterList params});
- /// Is initialized on demand, and disposed when no longer needed
- /// if [dispose] is set to true.
- /// When obtained statically, the value will never be disposed.
- class _LazyDartIn<T> with _TypedDartIn<T> {
- final _DartInFunction<T> _initalizer;
- T _value;
- _LazyDartIn(this._initalizer);
- @override
- T get({List values}) {
- // Need to have a local copy for casting because
- // dart requires it.
- T value;
- if (_value == null) {
- value = _value ??= _initalizer(params: _ParameterList.parametersOf(values));
- }
- return _value;
- }
- }
- /// A provider who's value is obtained from providerFunction for each time the
- /// value is requested.
- ///
- /// This provider doesn't keep any values itself, so those values are disposed
- /// when the containing widget is disposed.
- class _FactoryDartIn<T> with _TypedDartIn<T> {
- final _DartInFunction<T> providerFunction;
- _FactoryDartIn(this.providerFunction);
- @override
- T get({List values}) => providerFunction(params: _ParameterList.parametersOf(values));
- }
- class Module {
- final List<DartIn> providerIns;
- Module(this.providerIns);
- }
- class _ParameterList {
- final List<Object> values;
- get(int i) {
- if (values == null || i > values.length - 1 || i < 0) {
- return null;
- }
- return values[i];
- }
- _ParameterList.parametersOf(this.values);
- }
- DartIn<T> factory<T>(_DartInFunction<T> value,{String scope }) => DartIn<T>._withFactory(value);
- DartIn<T> single<T>(T value) => DartIn<T>._value(value);
- DartIn<T> lazy<T>(_DartInFunction<T> value) => DartIn<T>._lazy(value);
- T get<T>({DartInScope scope, List params}) {
- assert(_dartIns != null);
- return _dartIns.value<T>(scope: scope, values: params);
- }
- T inject<T>({DartInScope scope, List params}) => get<T>(scope: scope, params: params);
- DartIns _dartIns;
- startDartIn(List<Module> modules) {
- _dartIns = DartIns();
- for (var module in modules) {
- for (var providerIn in module.providerIns) {
- _dartIns.provide(providerIn);
- }
- }
- }
|