Skip to content

Commit

Permalink
Add standard convenience functions for creating Promises to resolve g…
Browse files Browse the repository at this point in the history
…roups of Futures.
  • Loading branch information
EliteMasterEric committed Sep 29, 2024
1 parent fe3368f commit da37417
Showing 1 changed file with 156 additions and 0 deletions.
156 changes: 156 additions & 0 deletions src/lime/app/Promises.hx
Original file line number Diff line number Diff line change
@@ -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<T>(futures:Array<Future<T>>):Future<Array<T>> {
var promise:Promise<Array<T>> = new Promise<Array<T>>();
var results:Array<T> = [];

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<T>(futures:Array<Future<T>>):Future<Array<PromiseResult<T>>> {
var promise:Promise<Array<PromiseResult<T>>> = new Promise<Array<PromiseResult<T>>>();
var results:Array<PromiseResult<T>> = [];

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<T>(futures:Array<Future<T>>):Future<T> {
var promise:Promise<T> = new Promise<T>();
var errors:Array<Dynamic> = [];

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<T>(futures:Array<Future<T>>):Future<PromiseResult<T>> {
var promise:Promise<PromiseResult<T>> = new Promise<PromiseResult<T>>();
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<T> {
/**
* The current state of the promise.
*/
public var state:PromiseState;
/**
* The value of the promise, if it resolved as Fulfilled.
*/
public var value:Null<T>;
/**
* The error of the promise, if it resolved as Rejected.
*/
public var error:Null<Dynamic>;

private function new(state:PromiseState, value:Null<T>, error:Null<Dynamic>):Void {
this.state = state;
this.value = value;
this.error = error;
}

public static function pending<T>():PromiseResult<T> {
return new PromiseResult<T>(PromiseState.Pending, null, null);
}

public static function fulfilled<T>(value:T):PromiseResult<T> {
return new PromiseResult<T>(PromiseState.Fulfilled, value, null);
}

public static function rejected<T>(error:Dynamic):PromiseResult<T> {
return new PromiseResult<T>(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;
}

0 comments on commit da37417

Please sign in to comment.