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