| // Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | /// An implementation of [Pipeline] that runs in-memory. | 
 | /// | 
 | /// To define a step, implement [MemoryModularStep]. | 
 | library; | 
 |  | 
 | import 'pipeline.dart'; | 
 | import 'suite.dart'; | 
 |  | 
 | /// A hook to fetch data previously computed for a dependency. | 
 | typedef ModuleDataProvider = Object? Function(Module, DataId); | 
 | typedef SourceProvider = String? Function(Uri); | 
 |  | 
 | abstract class MemoryModularStep extends ModularStep { | 
 |   Future<Map<DataId, Object>> execute( | 
 |       Module module, | 
 |       SourceProvider sourceProvider, | 
 |       ModuleDataProvider dataProvider, | 
 |       List<String> flags); | 
 | } | 
 |  | 
 | class MemoryPipeline extends Pipeline<MemoryModularStep> { | 
 |   final Map<Uri, String> _sources; | 
 |  | 
 |   /// Internal state to hold the current results as they are computed by the | 
 |   /// pipeline. Expected to be null before and after the pipeline runs. | 
 |   Map<Module, Map<DataId, Object>>? _results; | 
 |  | 
 |   /// A copy of [_result] at the time the pipeline last finished running. | 
 |   Map<Module, Map<DataId, Object>>? resultsForTesting; | 
 |  | 
 |   final ConfigurationRegistry? _registry; | 
 |  | 
 |   /// Cache of results when [cacheSharedModules] is true | 
 |   final List<Map<Module, Map<DataId, Object>>> _resultCache; | 
 |  | 
 |   MemoryPipeline(this._sources, List<MemoryModularStep> steps, | 
 |       {bool cacheSharedModules = false}) | 
 |       : _registry = cacheSharedModules ? ConfigurationRegistry() : null, | 
 |         _resultCache = cacheSharedModules ? [] : const [], | 
 |         super(steps, cacheSharedModules); | 
 |  | 
 |   @override | 
 |   Future<void> run(ModularTest test) async { | 
 |     var results = _results = {}; | 
 |     Map<Module, Map<DataId, Object>>? cache; | 
 |     if (cacheSharedModules) { | 
 |       int id = _registry!.computeConfigurationId(test); | 
 |       if (id < _resultCache.length) { | 
 |         cache = _resultCache[id]; | 
 |       } else { | 
 |         assert(id == _resultCache.length); | 
 |         _resultCache.add(cache = {}); | 
 |       } | 
 |       results.addAll(cache); | 
 |     } | 
 |     await super.run(test); | 
 |     resultsForTesting = results; | 
 |     if (cacheSharedModules) { | 
 |       for (var module in results.keys) { | 
 |         if (module.isShared) { | 
 |           cache![module] = results[module]!; | 
 |         } | 
 |       } | 
 |     } | 
 |     _results = null; | 
 |   } | 
 |  | 
 |   @override | 
 |   Future<void> runStep(MemoryModularStep step, Module module, | 
 |       Map<Module, Set<DataId>> visibleData, List<String> flags) async { | 
 |     final results = _results!; | 
 |     if (cacheSharedModules && module.isShared) { | 
 |       bool allCachedResultsFound = true; | 
 |       for (var dataId in step.resultData) { | 
 |         if (results[module] == null || results[module]![dataId] == null) { | 
 |           allCachedResultsFound = false; | 
 |           break; | 
 |         } | 
 |       } | 
 |       if (allCachedResultsFound) { | 
 |         step.notifyCached(module); | 
 |         return; | 
 |       } | 
 |     } | 
 |  | 
 |     Map<Module, Map<DataId, Object>> inputData = {}; | 
 |     visibleData.forEach((module, dataIdSet) { | 
 |       inputData[module] = {}; | 
 |       for (var dataId in dataIdSet) { | 
 |         inputData[module]![dataId] = results[module]![dataId]!; | 
 |       } | 
 |     }); | 
 |     Map<Uri, String> inputSources = {}; | 
 |     if (step.needsSources) { | 
 |       for (var relativeUri in module.sources) { | 
 |         var uri = module.rootUri.resolveUri(relativeUri); | 
 |         inputSources[uri] = _sources[uri]!; | 
 |       } | 
 |     } | 
 |     Map<DataId, Object> result = await step.execute( | 
 |         module, | 
 |         (Uri uri) => inputSources[uri], | 
 |         (Module m, DataId id) => inputData[m]![id], | 
 |         flags); | 
 |     for (var dataId in step.resultData) { | 
 |       (results[module] ??= {})[dataId] = result[dataId]!; | 
 |     } | 
 |   } | 
 | } |