Remove Futures class, move methods to Future.

Optimize Future.forEach, Future.delay.

Review URL: https://codereview.chromium.org//11865005

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@16954 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
lrn@google.com 2013-01-11 09:46:45 +00:00
parent c80c122d5a
commit 4868ee2110
35 changed files with 115 additions and 104 deletions

View file

@ -73,7 +73,7 @@ class IOClient extends BaseClient {
reasonPhrase: response.reasonPhrase));
};
return new Future.wait([
return Future.wait([
completer.future,
pipeCompleter.future
]).then((values) => values.first);

View file

@ -111,7 +111,7 @@ class MultipartRequest extends BaseRequest {
writeLine();
});
Futures.forEach(_files.collection, (file) {
Future.forEach(_files.collection, (file) {
writeAscii('--$boundary\r\n');
writeAscii(_headerForFile(file));
return writeStreamToSink(file.finalize(), controller)

View file

@ -37,7 +37,7 @@ void setup(Function program, Function output) {
var thaiDatesFuture = initializeDateFormatting('th_TH', null);
var germanMessagesFuture = initializeMessages('de_DE');
var thaiMessagesFuture = initializeMessages('th_TH');
Futures.wait([germanDatesFuture, thaiDatesFuture, germanMessagesFuture,
Future.wait([germanDatesFuture, thaiDatesFuture, germanMessagesFuture,
thaiMessagesFuture]).then(program);
}

View file

@ -33,7 +33,7 @@ Future initializeDateFormatting(String locale, String path) {
reader2, (x) => x, availableLocalesForDateFormatting));
return initializeIndividualLocaleDateFormatting(
(symbols, patterns) {
return Futures.wait([
return Future.wait([
symbols.initLocale(locale),
patterns.initLocale(locale)]);
});

View file

@ -31,7 +31,7 @@ Future initializeDateFormatting(String locale, String url) {
reader2, (x) => x, availableLocalesForDateFormatting));
return initializeIndividualLocaleDateFormatting(
(symbols, patterns) {
return Futures.wait([
return Future.wait([
symbols.initLocale(locale),
patterns.initLocale(locale)]);
});

View file

@ -27,7 +27,7 @@ runWith([Function getSubset]) {
void runEverything(Function getSubset) {
// Initialize all locales sequentially before running tests. Be sure not
// to do it in parallel or we can run into ulimit problems on fast machines.
var futureList = Futures.forEach(DateFormat.allLocalesWithSymbols(),
var futureList = Future.forEach(DateFormat.allLocalesWithSymbols(),
(locale) => initializeDateFormatting(locale, dataDirectory));
test('Run all date formatting tests nested test', () {

View file

@ -29,7 +29,7 @@ void runEverything(_) {
var futures = DateFormat.allLocalesWithSymbols()
.mappedBy((locale) => initializeDateFormatting(locale, url))
.toList();
Futures.wait(futures).then(expectAsync1((_) {
Future.wait(futures).then(expectAsync1((_) {
runDateTests(smallSetOfLocales());
shutDown();}));
}

View file

@ -28,5 +28,5 @@ void runEverything(Function getSubset) {
var futures = DateFormat.allLocalesWithSymbols()
.mappedBy((locale) => initializeDateFormatting(locale, null))
.toList();
Futures.wait(futures).then((results) => runDateTests(getSubset()));
Future.wait(futures).then((results) => runDateTests(getSubset()));
}

View file

@ -833,7 +833,7 @@ class ReceivePortImpl implements ReceivePort {
_waitForPendingPorts(var message, void callback()) {
final finder = new _PendingSendPortFinder();
finder.traverse(message);
Futures.wait(finder.ports).then((_) => callback());
Future.wait(finder.ports).then((_) => callback());
}

View file

@ -37,7 +37,7 @@ main() {
final argParser = new ArgParser();
final Path libPath = scriptDir.append('../../../../');
Path pkgPath;
argParser.addFlag('no-code',
@ -180,14 +180,14 @@ main() {
final entrypoints = <Path>[];
try {
final option = argParser.parse(args);
// This checks to see if the root of all entrypoints is the same.
// If it is not, then we display a warning, as package imports might fail.
var entrypointRoot;
for(final arg in option.rest) {
var entrypoint = new Path.fromNative(arg);
entrypoints.add(entrypoint);
if (entrypointRoot == null) {
entrypointRoot = entrypoint.directoryPath;
} else if (entrypointRoot.toNativePath() !=
@ -208,7 +208,7 @@ main() {
print(argParser.getUsage());
exit(1);
}
if (pkgPath == null) {
pkgPath = entrypoints[0].directoryPath.append('packages/');
}
@ -221,7 +221,7 @@ main() {
Future filesCopied = copyDirectory(scriptDir.append('../static'),
dartdoc.outputDir);
Futures.wait([compiled, filesCopied]).then((_) {
Future.wait([compiled, filesCopied]).then((_) {
dartdoc.cleanup();
print('Documented ${dartdoc.totalLibraries} libraries, '
'${dartdoc.totalTypes} types, and ${dartdoc.totalMembers} members.');

View file

@ -36,17 +36,56 @@ abstract class Future<T> {
return new _FutureImpl<T>.immediateError(error, stackTrace);
}
factory Future.delayed(int milliseconds, dynamic value()) {
var completer = new Completer<T>();
new Timer(milliseconds, (_) => completer.complete(null));
return completer.future.then((_) => value());
/**
* Creates a future that completes after a delay.
*
* The future will be completed after [milliseconds] have passed with
* the result of calling [value].
*
* If calling [value] throws, the created future will complete with the
* error.
*/
factory Future.delayed(int milliseconds, T value()) {
_FutureImpl<T> future = new _ThenFuture<dynamic, T>((_) => value());
new Timer(milliseconds, (_) => future._sendValue(null));
return future;
}
// TODO(floitsch): I don't think the typing is right here.
// Otherwise new Future<int>.wait(...) would be a Future<List<int>>. Sounds
// wrong.
factory Future.wait(List<Future> futures)
=> new _FutureImpl<List<T>>.wait(futures);
/**
* Wait for all the given futures to complete and collect their values.
*
* Returns a future which will complete once all the futures in a list are
* complete. If any of the futures in the list completes with an exception,
* the resulting future also completes with an exception. Otherwise the value
* of the returned future will be a list of all the values that were produced.
*/
static Future<List> wait(Iterable<Future> futures) {
return new _FutureImpl<List>.wait(futures);
}
/**
* Perform an async operation for each element of the iterable, in turn.
*
* Runs [f] for each element in [input] in order, moving to the next element
* only when the [Future] returned by [f] completes. Returns a [Future] that
* completes when all elements have been processed.
*
* The return values of all [Future]s are discarded. Any errors will cause the
* iteration to stop and will be piped through the returned [Future].
*/
static Future forEach(Iterable input, Future f(element)) {
_FutureImpl doneSignal = new _FutureImpl();
Iterator iterator = input.iterator;
void nextElement(_) {
if (iterator.moveNext()) {
f(iterator.current).then(nextElement, onError: doneSignal._setError);
} else {
doneSignal._setValue(null);
}
}
nextElement(null);
return doneSignal;
}
/**
* When this future completes with a value, then [onValue] is called with this
@ -181,32 +220,3 @@ abstract class Completer<T> {
*/
void completeError(Object exception, [Object stackTrace]);
}
class Futures {
/**
* Returns a future which will complete once all the futures in a list are
* complete. If any of the futures in the list completes with an exception,
* the resulting future also completes with an exception. (The value of the
* returned future will be a list of all the values that were produced.)
*/
static Future<List> wait(Iterable<Future> futures) {
return new _FutureImpl<List>.wait(futures);
}
/**
* Runs [f] for each element in [input] in order, moving to the next element
* only when the [Future] returned by [f] completes. Returns a [Future] that
* completes when all elements have been processed.
*
* The return values of all [Future]s are discarded. Any errors will cause the
* iteration to stop and will be piped through the returned [Future].
*/
static Future forEach(Iterable input, Future f(element)) {
var iterator = input.iterator;
Future nextElement(_) {
if (!iterator.moveNext()) return new Future.immediate(null);
return f(iterator.current).then(nextElement);
}
return nextElement(null);
}
}

View file

@ -76,7 +76,7 @@ testCompleteManySuccessHandlers() {
futures.add(future.then((int v) { after2 = v; }));
var port = new ReceivePort();
new Future.wait(futures).then((_) {
Future.wait(futures).then((_) {
Expect.equals(3, before);
Expect.equals(3, after1);
Expect.equals(3, after2);

View file

@ -8,14 +8,14 @@ import 'dart:isolate';
Future testWaitEmpty() {
List<Future> futures = new List<Future>();
return Futures.wait(futures);
return Future.wait(futures);
}
Future testCompleteAfterWait() {
List<Future> futures = new List<Future>();
Completer<Object> c = new Completer<Object>();
futures.add(c.future);
Future future = Futures.wait(futures);
Future future = Future.wait(futures);
c.complete(null);
return future;
}
@ -25,7 +25,7 @@ Future testCompleteBeforeWait() {
Completer c = new Completer();
futures.add(c.future);
c.complete(null);
return Futures.wait(futures);
return Future.wait(futures);
}
Future testWaitWithMultipleValues() {
@ -36,7 +36,7 @@ Future testWaitWithMultipleValues() {
futures.add(c2.future);
c1.complete(1);
c2.complete(2);
return Futures.wait(futures).then((values) {
return Future.wait(futures).then((values) {
Expect.listEquals([1, 2], values);
});
}
@ -50,7 +50,7 @@ Future testWaitWithSingleError() {
c1.complete();
c2.completeError('correct error');
return Futures.wait(futures).then((_) {
return Future.wait(futures).then((_) {
throw 'incorrect error';
}).catchError((e) {
Expect.equals('correct error', e.error);
@ -66,7 +66,7 @@ Future testWaitWithMultipleErrors() {
c1.completeError('correct error');
c2.completeError('incorrect error 1');
return Futures.wait(futures).then((_) {
return Future.wait(futures).then((_) {
throw 'incorrect error 2';
}).catchError((e) {
Expect.equals('correct error', e.error);
@ -74,14 +74,14 @@ Future testWaitWithMultipleErrors() {
}
Future testForEachEmpty() {
return Futures.forEach([], (_) {
return Future.forEach([], (_) {
throw 'should not be called';
});
}
Future testForEach() {
var seen = <int>[];
return Futures.forEach([1, 2, 3, 4, 5], (n) {
return Future.forEach([1, 2, 3, 4, 5], (n) {
seen.add(n);
return new Future.immediate(null);
}).then((_) => Expect.listEquals([1, 2, 3, 4, 5], seen));
@ -89,7 +89,7 @@ Future testForEach() {
Future testForEachWithException() {
var seen = <int>[];
return Futures.forEach([1, 2, 3, 4, 5], (n) {
return Future.forEach([1, 2, 3, 4, 5], (n) {
if (n == 4) throw 'correct exception';
seen.add(n);
return new Future.immediate(null);
@ -115,7 +115,7 @@ main() {
// Use a receive port for blocking the test.
// Note that if the test fails, the program will not end.
ReceivePort port = new ReceivePort();
Futures.wait(futures).then((List list) {
Future.wait(futures).then((List list) {
Expect.equals(8, list.length);
port.close();
});

View file

@ -15,7 +15,7 @@ void testCreateRecursiveRace() {
var keepAlive = new ReceivePort();
var temp = new Directory('').createTempSync();
var d = new Directory('${temp.path}/a/b/c/d/e');
Futures.wait([
Future.wait([
d.create(recursive: true),
d.create(recursive: true),
d.create(recursive: true),

View file

@ -59,7 +59,7 @@ fuzzAsyncMethods() {
futures.add(doItAsync(() => d.rename(v2)));
});
});
Futures.wait(futures).then((ignore) => port.close());
Future.wait(futures).then((ignore) => port.close());
}
main() {

View file

@ -59,7 +59,7 @@ fuzzAsyncMethods() {
});
});
});
Futures.wait(futures).then((ignore) => port.close());
Future.wait(futures).then((ignore) => port.close());
}
@ -112,7 +112,7 @@ fuzzAsyncRandomAccessMethods() {
futures.add(doItAsync(() => opened.writeList(p[0], p[1], p[2])));
}
}
Futures.wait(futures).then((ignore) {
Future.wait(futures).then((ignore) {
for (var opened in openedFiles) {
opened.closeSync();
}

View file

@ -113,7 +113,7 @@ void testBasicNoCredentials() {
makeRequest(
new Uri.fromString("http://127.0.0.1:${server.port}/test$i/xxx")));
}
Futures.wait(futures).then((_) {
Future.wait(futures).then((_) {
server.shutdown();
client.shutdown();
});
@ -150,7 +150,7 @@ void testBasicCredentials() {
makeRequest(
new Uri.fromString("http://127.0.0.1:${server.port}/test$i/xxx")));
}
Futures.wait(futures).then((_) {
Future.wait(futures).then((_) {
server.shutdown();
client.shutdown();
});
@ -201,12 +201,12 @@ void testBasicAuthenticateCallback() {
return futures;
}
Futures.wait(makeRequests()).then((_) {
Future.wait(makeRequests()).then((_) {
makeRequest(
new Uri.fromString(
"http://127.0.0.1:${server.port}/passwdchg")).then((_) {
passwordChanged = true;
Futures.wait(makeRequests()).then((_) {
Future.wait(makeRequests()).then((_) {
server.shutdown();
client.shutdown();
});

View file

@ -61,7 +61,7 @@ void testSessions(int sessionCount) {
});
}));
}
Futures.wait(futures).then((clientSessions) {
Future.wait(futures).then((clientSessions) {
Expect.equals(sessions.length, sessionCount);
Expect.setEquals(new Set.from(clientSessions), sessions);
server.close();
@ -86,8 +86,8 @@ void testTimeout(int sessionCount) {
for (int i = 0; i < sessionCount; i++) {
futures.add(connectGetSession(server.port));
}
Futures.wait(futures).then((clientSessions) {
Futures.wait(timeouts).then((_) {
Future.wait(futures).then((clientSessions) {
Future.wait(timeouts).then((_) {
futures = [];
for (var id in clientSessions) {
futures.add(connectGetSession(server.port, id).then((session) {
@ -95,7 +95,7 @@ void testTimeout(int sessionCount) {
Expect.notEquals(id, session);
}));
}
Futures.wait(futures).then((_) {
Future.wait(futures).then((_) {
server.close();
});
});

View file

@ -37,7 +37,7 @@ bool _anyErrors = false;
*/
Future<bool> convert(Path htmlPath, Path jsonPath) {
var completer = new Completer();
// TODO(amouravski): make this transform once I know what I want this file to
// return.
_convertFiles(htmlPath).then((convertedJson) {
@ -105,7 +105,7 @@ Future<Object> _convertFiles(Path htmlPath) {
// Combine all JSON objects
lister.onDone = (_) {
Futures.wait(fileFutures).then((jsonList) {
Future.wait(fileFutures).then((jsonList) {
var convertedJson = {};
jsonList.forEach((json) {
final k = json.keys[0];
@ -270,7 +270,7 @@ bool _listsEqual(List list1, List list2) {
* Print JSON in a much nicer format.
*
* For example:
*
*
* {"foo":["bar","baz"],"boo":{"far:"faz"}}
*
* becomes:
@ -293,7 +293,7 @@ String prettyPrintJson(Object json, [String indentation = '']) {
if (json is List) {
var recursiveOutput =
Strings.join(json.map((e) =>
Strings.join(json.map((e) =>
prettyPrintJson(e, '$indentation ')), ',\n');
output = '$indentation[\n'
'$recursiveOutput'

View file

@ -216,7 +216,7 @@ Future doMultitest(Path filePath, String outputDir, Path suiteDir,
}
// Wait until all imports are copied before scheduling test cases.
return Futures.wait(futureCopies).then((_) {
return Future.wait(futureCopies).then((_) {
String baseFilename = filePath.filenameWithoutExtension;
for (String key in tests.keys) {
final Path multitestFilename =

View file

@ -1667,6 +1667,7 @@ class ProcessQueue {
futures.add(runner.terminate());
}
}
// Change to Future.wait when updating binaries.
return Futures.wait(futures);
}

View file

@ -146,12 +146,12 @@ void main() {
apidoc.includeApi = true;
apidoc.includedLibraries = includedLibraries;
Futures.wait([copiedStatic, copiedApiDocStatic]).then((_) {
Future.wait([copiedStatic, copiedApiDocStatic]).then((_) {
apidoc.documentLibraries(apidocLibraries, libPath, pkgPath);
final compiled = doc.compileScript(mode, outputDir, libPath);
Futures.wait([compiled, copiedStatic, copiedApiDocStatic]).then((_) {
Future.wait([compiled, copiedStatic, copiedApiDocStatic]).then((_) {
apidoc.cleanup();
});
});

View file

@ -214,7 +214,7 @@ class ArchiveEntry {
stream.onError = completer.completeError;
stream.onClosed = () => completer.complete(buffer);
return Futures.wait([call(CLONE, _id), completer.future])
return Future.wait([call(CLONE, _id), completer.future])
.then((list) => new CompleteArchiveEntry._(list[0], list[1]));
}

View file

@ -75,7 +75,7 @@ class ArchiveInputStream {
this.onError = (e, stack) => completer.completeError(e, stack);
this.onClosed = () => completer.complete(result);
return completer.future.then(Futures.wait);
return completer.future.then(Future.wait);
}
/**

View file

@ -150,7 +150,7 @@ class ArchiveReader {
addOption(SET_OPTION, option);
}
return Futures.wait(pending);
return Future.wait(pending);
}
}

View file

@ -117,7 +117,7 @@ class LishCommand extends PubCommand {
Future<List<String>> get _filesToPublish {
var rootDir = entrypoint.root.dir;
return Futures.wait([
return Future.wait([
dirExists(join(rootDir, '.git')),
git.isInstalled
]).then((results) {
@ -129,7 +129,7 @@ class LishCommand extends PubCommand {
}
return listDir(rootDir, recursive: true).then((entries) {
return Futures.wait(entries.mappedBy((entry) {
return Future.wait(entries.mappedBy((entry) {
return fileExists(entry).then((isFile) {
// Skip directories.
if (!isFile) return null;

View file

@ -136,7 +136,7 @@ class CurlClient extends http.BaseClient {
// prints the headers to stdout instead of the body. We want to wait until
// all the headers are received to read them from the header file.
if (!expectBody) {
return Futures.wait([
return Future.wait([
consumeInputStream(process.stdout),
completer.future
]);

View file

@ -131,7 +131,7 @@ class Entrypoint {
/// [packageVersions], and writes a [LockFile].
Future _installDependencies(List<PackageId> packageVersions) {
return cleanDir(path).then((_) {
return Futures.wait(packageVersions.mappedBy((id) {
return Future.wait(packageVersions.mappedBy((id) {
if (id.source is RootSource) return new Future.immediate(id);
return install(id);
}));
@ -208,7 +208,7 @@ class Entrypoint {
return _linkSecondaryPackageDir(dir)
.then((_) => _listDirWithoutPackages(dir))
.then((files) {
return Futures.wait(files.mappedBy((file) {
return Future.wait(files.mappedBy((file) {
return dirExists(file).then((isDir) {
if (!isDir) return new Future.immediate(null);
return _linkSecondaryPackageDir(file);
@ -223,7 +223,7 @@ class Entrypoint {
/// files and `package` files.
Future<List<String>> _listDirWithoutPackages(dir) {
return listDir(dir).then((files) {
return Futures.wait(files.mappedBy((file) {
return Future.wait(files.mappedBy((file) {
if (basename(file) == 'packages') return new Future.immediate([]);
return dirExists(file).then((isDir) {
if (!isDir) return new Future.immediate([]);

View file

@ -72,7 +72,7 @@ class HostedSource extends Source {
// Download and extract the archive to a temp directory.
var tempDir;
return Futures.wait([
return Future.wait([
httpClient.send(new http.Request("GET", new Uri.fromString(fullUrl)))
.then((response) => response.stream),
systemCache.createTempDir()

View file

@ -59,7 +59,7 @@ String relativeTo(target, base) => path.relative(target, from: base);
/// completes with the result.
Future<bool> exists(path) {
path = _getPath(path);
return Futures.wait([fileExists(path), dirExists(path)]).then((results) {
return Future.wait([fileExists(path), dirExists(path)]).then((results) {
return results[0] || results[1];
});
}
@ -284,7 +284,7 @@ Future<List<String>> listDir(dir,
};
return completer.future.then((contents) {
return Futures.wait(children).then((childContents) {
return Future.wait(children).then((childContents) {
contents.addAll(flatten(childContents));
return contents;
});

View file

@ -57,7 +57,7 @@ abstract class Validator {
// 3356, which causes a bug if all validators are (synchronously) using
// Future.immediate and an error is thrown before a handler is set up.
return sleep(0).then((_) {
return Futures.wait(
return Future.wait(
validators.mappedBy((validator) => validator.validate()));
}).then((_) {
var errors =

View file

@ -20,7 +20,7 @@ class DependencyValidator extends Validator {
: super(entrypoint);
Future validate() {
return Futures.forEach(entrypoint.root.pubspec.dependencies, (dependency) {
return Future.forEach(entrypoint.root.pubspec.dependencies, (dependency) {
if (dependency.source is! HostedSource) {
return _warnAboutSource(dependency);
}

View file

@ -19,7 +19,7 @@ class DirectoryValidator extends Validator {
Future validate() {
return listDir(entrypoint.root.dir).then((dirs) {
return Futures.wait(dirs.mappedBy((dir) {
return Future.wait(dirs.mappedBy((dir) {
return dirExists(dir).then((exists) {
if (!exists) return;

View file

@ -254,7 +254,7 @@ class ChangeVersion implements WorkItem {
// The dependencies between the old and new version may be different. Walk
// them both and update any constraints that differ between the two.
return Futures.wait([
return Future.wait([
getDependencyRefs(solver, oldVersion),
getDependencyRefs(solver, version)]).then((list) {
var oldDependencyRefs = list[0];

View file

@ -574,7 +574,7 @@ void confirmPublish(ScheduledProcess pub) {
Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) {
String pathInSandbox(path) => join(getFullPath(sandboxDir), path);
return Futures.wait([
return Future.wait([
ensureDir(pathInSandbox(appPath)),
_awaitObject(args),
tokenEndpoint == null ? new Future.immediate(null) : tokenEndpoint
@ -915,7 +915,7 @@ class DirectoryDescriptor extends Descriptor {
final childFutures =
contents.mappedBy((child) => child.create(dir)).toList();
// Only complete once all of the children have been created too.
return Futures.wait(childFutures).then((_) => dir);
return Future.wait(childFutures).then((_) => dir);
});
}
@ -936,7 +936,7 @@ class DirectoryDescriptor extends Descriptor {
contents.mappedBy((entry) => entry.validate(dir)).toList();
// If they are all valid, the directory is valid.
return Futures.wait(entryFutures).then((entries) => null);
return Future.wait(entryFutures).then((entries) => null);
});
}
@ -1072,7 +1072,7 @@ class TarFileDescriptor extends Descriptor {
var tempDir;
return createTempDir().then((_tempDir) {
tempDir = _tempDir;
return Futures.wait(contents.mappedBy((child) => child.create(tempDir)));
return Future.wait(contents.mappedBy((child) => child.create(tempDir)));
}).then((createdContents) {
return consumeInputStream(createTarGz(createdContents, baseDir: tempDir));
}).then((bytes) {
@ -1482,7 +1482,7 @@ Future _awaitObject(object) {
// Unroll nested futures.
if (object is Future) return object.then(_awaitObject);
if (object is Collection) {
return Futures.wait(object.mappedBy(_awaitObject).toList());
return Future.wait(object.mappedBy(_awaitObject).toList());
}
if (object is! Map) return new Future.immediate(object);
@ -1491,7 +1491,7 @@ Future _awaitObject(object) {
pairs.add(_awaitObject(value)
.then((resolved) => new Pair(key, resolved)));
});
return Futures.wait(pairs).then((resolvedPairs) {
return Future.wait(pairs).then((resolvedPairs) {
var map = {};
for (var pair in resolvedPairs) {
map[pair.first] = pair.last;