| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 
|  | 2 // for details. All rights reserved. Use of this source code is governed by a | 
|  | 3 // BSD-style license that can be found in the LICENSE file. | 
|  | 4 | 
|  | 5 // TODO(lrn): This should be in package:async? | 
|  | 6 /** | 
|  | 7  * Helper functions for working with errors. | 
|  | 8  * | 
|  | 9  * The [MultiError] class combines multiple errors into one object, | 
|  | 10  * and the [MultiError.wait] function works like [Future.wait] except | 
|  | 11  * that it returns all the errors. | 
|  | 12  */ | 
|  | 13 library pkg.isolate.errors; | 
|  | 14 | 
|  | 15 import "dart:async"; | 
|  | 16 | 
|  | 17 class MultiError extends Error { | 
|  | 18   // Limits the number of lines included from each error's error message. | 
|  | 19   // A best-effort attempt is made at keeping below this number of lines | 
|  | 20   // in the output. | 
|  | 21   // If there are too many errors, they will all get at least one line. | 
|  | 22   static const int _MAX_LINES = 55; | 
|  | 23   // Minimum number of lines in the toString for each error. | 
|  | 24   static const int _MIN_LINES_PER_ERROR = 1; | 
|  | 25 | 
|  | 26   /** The actual errors. */ | 
|  | 27   final List errors; | 
|  | 28 | 
|  | 29   /** | 
|  | 30    * Create a `MultiError` based on a list of errors. | 
|  | 31    * | 
|  | 32    * The errors represent errors of a number of individual operations. | 
|  | 33    * | 
|  | 34    * The list may contain `null` values, if the index of the error in the | 
|  | 35    * list is useful. | 
|  | 36    */ | 
|  | 37   MultiError(this.errors); | 
|  | 38 | 
|  | 39   /** | 
|  | 40    * Waits for all [futures] to complete, like [Future.wait]. | 
|  | 41    * | 
|  | 42    * Where `Future.wait` only reports one error, even if multiple | 
|  | 43    * futures complete with errors, this function will complete | 
|  | 44    * with a [MultiError] if more than one future completes with an error. | 
|  | 45    * | 
|  | 46    * The order of values is not preserved (if that is needed, use | 
|  | 47    * [wait]). | 
|  | 48    */ | 
|  | 49   static Future<List> waitUnordered(Iterable<Future> futures, | 
|  | 50                                     {cleanUp(successResult)}) { | 
|  | 51     Completer completer; | 
|  | 52     int count = 0; | 
|  | 53     int errors = 0; | 
|  | 54     int values = 0; | 
|  | 55     // Initilized to `new List(count)` when count is known. | 
|  | 56     // Filled up with values on the left, errors on the right. | 
|  | 57     // Order is not preserved. | 
|  | 58     List results; | 
|  | 59     void checkDone() { | 
|  | 60       if (errors + values < count) return; | 
|  | 61       if (errors == 0) { | 
|  | 62         completer.complete(results); | 
|  | 63         return; | 
|  | 64       } | 
|  | 65       var errorList = results.sublist(results.length - errors); | 
|  | 66       completer.completeError(new MultiError(errorList)); | 
|  | 67     }; | 
|  | 68     var handleValue = (v) { | 
|  | 69       // If this fails because [results] is null, there is a future | 
|  | 70       // which breaks the Future API by completing immediately when | 
|  | 71       // calling Future.then, probably by misusing a synchronous completer. | 
|  | 72       results[values++] = v; | 
|  | 73       if (errors > 0 && cleanUp != null) { | 
|  | 74         new Future.sync(() => cleanUp(v)); | 
|  | 75       } | 
|  | 76       checkDone(); | 
|  | 77     }; | 
|  | 78     var handleError = (e, s) { | 
|  | 79       if (errors == 0 && cleanUp != null) { | 
|  | 80         for (int i = 0; i < values; i++) { | 
|  | 81           var value = results[i]; | 
|  | 82           if (value != null) new Future.sync(() => cleanUp(value)); | 
|  | 83         } | 
|  | 84       } | 
|  | 85       results[results.length - ++errors] = e; | 
|  | 86       checkDone(); | 
|  | 87     }; | 
|  | 88     for (Future future in futures) { | 
|  | 89       count++; | 
|  | 90       future.then(handleValue, onError: handleError); | 
|  | 91     } | 
|  | 92     if (count == 0) return new Future.value(new List(0)); | 
|  | 93     results = new List(count); | 
|  | 94     completer = new Completer(); | 
|  | 95     return completer.future; | 
|  | 96   } | 
|  | 97 | 
|  | 98   /** | 
|  | 99    * Waits for all [futures] to complete, like [Future.wait]. | 
|  | 100    * | 
|  | 101    * Where `Future.wait` only reports one error, even if multiple | 
|  | 102    * futures complete with errors, this function will complete | 
|  | 103    * with a [MultiError] if more than one future completes with an error. | 
|  | 104    * | 
|  | 105    * The order of values is preserved, and if any error occurs, the | 
|  | 106    * [MultiError.errors] list will have errors in the corresponding slots, | 
|  | 107    * and `null` for non-errors. | 
|  | 108    */ | 
|  | 109   Future<List> wait(Iterable<Future> futures, | 
|  | 110                     {cleanUp(successResult)}) { | 
|  | 111     Completer completer; | 
|  | 112     int count = 0; | 
|  | 113     bool hasError = false; | 
|  | 114     int completed = 0; | 
|  | 115     // Initalized to `new List(count)` when count is known. | 
|  | 116     // Filled with values until the first error, then cleared | 
|  | 117     // and filled with errors. | 
|  | 118     List results; | 
|  | 119     void checkDone() { | 
|  | 120       completed++; | 
|  | 121       if (completed < count) return; | 
|  | 122       if (!hasError) { | 
|  | 123         completer.complete(results); | 
|  | 124         return; | 
|  | 125       } | 
|  | 126       completer.completeError(new MultiError(results)); | 
|  | 127     }; | 
|  | 128     for (Future future in futures) { | 
|  | 129       int i = count; | 
|  | 130       count++; | 
|  | 131       future.then((v) { | 
|  | 132         if (!hasError) { | 
|  | 133           results[i] = v; | 
|  | 134         } else if (cleanUp != null) { | 
|  | 135           new Future.sync(() => cleanUp(v)); | 
|  | 136         } | 
|  | 137         checkDone(); | 
|  | 138       }, onError: (e, s) { | 
|  | 139         if (!hasError) { | 
|  | 140           if (cleanUp != null) { | 
|  | 141             for (int i = 0; i < results.length; i++) { | 
|  | 142               var result = results[i]; | 
|  | 143               if (result != null) new Future.sync(() => cleanUp(result)); | 
|  | 144             } | 
|  | 145           } | 
|  | 146           results.fillRange(0, results.length, null); | 
|  | 147           hasError = true; | 
|  | 148         } | 
|  | 149         results[i] = e; | 
|  | 150         checkDone(); | 
|  | 151       }); | 
|  | 152     } | 
|  | 153     if (count == 0) return new Future.value(new List(0)); | 
|  | 154     results = new List(count); | 
|  | 155     completer = new Completer(); | 
|  | 156     return completer.future; | 
|  | 157   } | 
|  | 158 | 
|  | 159 | 
|  | 160   String toString() { | 
|  | 161     StringBuffer buffer = new StringBuffer(); | 
|  | 162     buffer.write("Multiple Errors:\n"); | 
|  | 163     int linesPerError = _MAX_LINES ~/ errors.length; | 
|  | 164     if (linesPerError < _MIN_LINES_PER_ERROR) { | 
|  | 165       linesPerError = _MIN_LINES_PER_ERROR; | 
|  | 166     } | 
|  | 167 | 
|  | 168     for (int index = 0; index < errors.length; index++) { | 
|  | 169       var error = errors[index]; | 
|  | 170       if (error == null) continue; | 
|  | 171       String errorString = error.toString(); | 
|  | 172       int end = 0; | 
|  | 173       for (int i = 0; i < linesPerError; i++) { | 
|  | 174         end = errorString.indexOf('\n', end) + 1; | 
|  | 175         if (end == 0) { | 
|  | 176           end = errorString.length; | 
|  | 177           break; | 
|  | 178         } | 
|  | 179       } | 
|  | 180       buffer.write("#$index: "); | 
|  | 181       buffer.write(errorString.substring(0, end)); | 
|  | 182       if (end < errorString.length) { | 
|  | 183         buffer.write("...\n"); | 
|  | 184       } | 
|  | 185     } | 
|  | 186     return buffer.toString(); | 
|  | 187   } | 
|  | 188 } | 
| OLD | NEW | 
|---|