From e35f00234b0e87579483d7063fd67b82cd5a7c90 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sun, 29 Sep 2024 10:08:46 -0400 Subject: [PATCH] Add standard convenience functions for creating Promises to resolve groups of Futures. --- src/lime/app/Promises.hx | 156 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 src/lime/app/Promises.hx diff --git a/src/lime/app/Promises.hx b/src/lime/app/Promises.hx new file mode 100644 index 000000000..4de31ac9f --- /dev/null +++ b/src/lime/app/Promises.hx @@ -0,0 +1,156 @@ +package lime.app; + +import lime.app.Promise; +import lime.app.Future; + +/** + * A set of static utility functions for working with Promises. + * This includes functions which resolve groups of Futures. + */ +class Promises { + /** + * Creates a promise which fulfills when all the input promises resolve successfully, + * with an array of the result values. + * Rejects when any of the input promises reject, with the first rejection reason. + * @param futures A list of Futures to resolve. + * @return A Future for a list of result values. + */ + public static function all(futures:Array>):Future> { + var promise:Promise> = new Promise>(); + var results:Array = []; + + for (future in futures) { + future.onComplete(function(result) { + results.push(result); + if (results.length == futures.length) { + promise.complete(results); + } + }); + future.onError(function(error) { + promise.error(error); + }); + } + + return promise.future; + } + + /** + * Creates a promise which fulfills when all the input promises settle (whether success or failure). + * Returns an array of objects that describe the outcome of each promise. + * @param futures A list of Futures to resolve. + * @return A Future for a list of result values. + */ + public static function allSettled(futures:Array>):Future>> { + var promise:Promise>> = new Promise>>(); + var results:Array> = []; + + for (future in futures) { + future.onComplete(function(value) { + results.push(PromiseResult.fulfilled(value)); + if (results.length == futures.length) { + promise.complete(results); + } + }); + future.onError(function(error) { + results.push(PromiseResult.rejected(value)); + if (results.length == futures.length) { + promise.complete(results); + } + }); + } + + return promise.future; + } + + /** + * Creates a promise which fulfills when any of the input promises resolve successfully. + * Returns the first fulfilled promise. If all promises reject, the promise will be rejected with the list of rejection reasons. + * @param futures A list of Futures to resolve. + * @return A Future for a result value. + */ + public static function any(futures:Array>):Future { + var promise:Promise = new Promise(); + var errors:Array = []; + + for (future in futures) { + future.onComplete(function(value) { + promise.complete(value); + }); + future.onError(function(error) { + errors.push(error); + if (errors.length == futures.length) { + promise.error(errors); + } + }); + } + + return promise.future; + } + + /** + * Creates a promise which fulfills when any of the input promises settle. + * Returns an object that describes the outcome of the first settled promise (whether success or failure). + * @param futures A list of Futures to resolve. + * @return A Future for a result value. + */ + public static function race(futures:Array>):Future> { + var promise:Promise> = new Promise>(); + for (future in futures) { + future.onComplete(function(value) { + promise.complete(PromiseResult.fulfilled(value)); + }); + future.onError(function(error) { + promise.complete(PromiseResult.rejected(error)); + }); + } + return promise.future; + } +} + +class PromiseResult { + /** + * The current state of the promise. + */ + public var state:PromiseState; + /** + * The value of the promise, if it resolved as Fulfilled. + */ + public var value:Null; + /** + * The error of the promise, if it resolved as Rejected. + */ + public var error:Null; + + private function new(state:PromiseState, value:Null, error:Null):Void { + this.state = state; + this.value = value; + this.error = error; + } + + public static function pending():PromiseResult { + return new PromiseResult(PromiseState.Pending, null, null); + } + + public static function fulfilled(value:T):PromiseResult { + return new PromiseResult(PromiseState.Fulfilled, value, null); + } + + public static function rejected(error:Dynamic):PromiseResult { + return new PromiseResult(PromiseState.Rejected, null, error); + } +} + +enum PromiseState { + /** + * This promise has not yet resolved. + */ + Pending; + /** + * This promise has resolved with a value. + */ + Fulfilled; + /** + * This promise has resolved with an error. + */ + Rejected; +}