|
|
|
|
|
|
using RSG.Promises; |
|
|
|
using RSG.Promises; |
|
|
|
namespace RSG |
|
|
|
{ |
|
|
|
namespace RSG { |
|
|
|
public interface IPromise<PromisedT> |
|
|
|
{ |
|
|
|
public interface IPromise<PromisedT> { |
|
|
|
/// <summary>
|
|
|
|
/// Gets the id of the promise, useful for referencing the promise during runtime.
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
/// The resolved callback chains a value promise (optionally converting to a different value type).
|
|
|
|
/// </summary>
|
|
|
|
IPromise<ConvertedT> Then<ConvertedT>( |
|
|
|
Func<PromisedT, IPromise<ConvertedT>> onResolved, |
|
|
|
Func<PromisedT, IPromise<ConvertedT>> onResolved, |
|
|
|
Func<Exception, IPromise<ConvertedT>> onRejected |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Interface for a promise that can be rejected.
|
|
|
|
/// </summary>
|
|
|
|
public interface IRejectable |
|
|
|
{ |
|
|
|
public interface IRejectable { |
|
|
|
/// <summary>
|
|
|
|
/// Reject the promise with an exception.
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Interface for a promise that can be rejected or resolved.
|
|
|
|
/// </summary>
|
|
|
|
public interface IPendingPromise<PromisedT> : IRejectable |
|
|
|
{ |
|
|
|
public interface IPendingPromise<PromisedT> : IRejectable { |
|
|
|
/// <summary>
|
|
|
|
/// ID of the promise, useful for debugging.
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Specifies the state of a promise.
|
|
|
|
/// </summary>
|
|
|
|
public enum PromiseState |
|
|
|
{ |
|
|
|
Pending, // The promise is in-flight.
|
|
|
|
Rejected, // The promise has been rejected.
|
|
|
|
Resolved // The promise has been resolved.
|
|
|
|
public enum PromiseState { |
|
|
|
Pending, // The promise is in-flight.
|
|
|
|
Rejected, // The promise has been rejected.
|
|
|
|
Resolved // The promise has been resolved.
|
|
|
|
}; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
public class Promise<PromisedT> : IPromise<PromisedT>, IPendingPromise<PromisedT>, IPromiseInfo |
|
|
|
{ |
|
|
|
public class Promise<PromisedT> : IPromise<PromisedT>, IPendingPromise<PromisedT>, IPromiseInfo { |
|
|
|
private Exception rejectionException; |
|
|
|
Exception rejectionException; |
|
|
|
private PromisedT resolveValue; |
|
|
|
PromisedT resolveValue; |
|
|
|
private List<RejectHandler> rejectHandlers; |
|
|
|
List<RejectHandler> rejectHandlers; |
|
|
|
private List<ProgressHandler> progressHandlers; |
|
|
|
List<ProgressHandler> progressHandlers; |
|
|
|
private List<Action<PromisedT>> resolveCallbacks; |
|
|
|
private List<IRejectable> resolveRejectables; |
|
|
|
List<Action<PromisedT>> resolveCallbacks; |
|
|
|
|
|
|
|
List<IRejectable> resolveRejectables; |
|
|
|
public int Id { get { return id; } } |
|
|
|
public int Id { |
|
|
|
get { return this.id; } |
|
|
|
} |
|
|
|
private readonly int id; |
|
|
|
readonly int id; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Name of the promise, when set, useful for debugging.
|
|
|
|
|
|
|
/// Tracks the current state of the promise.
|
|
|
|
/// </summary>
|
|
|
|
public PromiseState CurState { get; private set; } |
|
|
|
|
|
|
|
|
|
|
|
public bool IsSync { get; } |
|
|
|
|
|
|
|
public Promise(bool isSync = false) { |
|
|
|
|
|
|
|
|
|
|
if (Promise.EnablePromiseTracking) |
|
|
|
{ |
|
|
|
if (Promise.EnablePromiseTracking) { |
|
|
|
Promise.PendingPromises.Add(this); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
this.CurState = PromiseState.Pending; |
|
|
|
this.id = Promise.NextId(); |
|
|
|
|
|
|
|
if (Promise.EnablePromiseTracking) |
|
|
|
{ |
|
|
|
if (Promise.EnablePromiseTracking) { |
|
|
|
try |
|
|
|
{ |
|
|
|
resolver(Resolve, Reject); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
Reject(ex); |
|
|
|
try { |
|
|
|
resolver(this.Resolve, this.Reject); |
|
|
|
} catch (Exception ex) { |
|
|
|
this.Reject(ex); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
private void AddRejectHandler(Action<Exception> onRejected, IRejectable rejectable) |
|
|
|
{ |
|
|
|
if (rejectHandlers == null) |
|
|
|
{ |
|
|
|
rejectHandlers = new List<RejectHandler>(); |
|
|
|
void AddRejectHandler(Action<Exception> onRejected, IRejectable rejectable) { |
|
|
|
if (this.rejectHandlers == null) { |
|
|
|
this.rejectHandlers = new List<RejectHandler>(); |
|
|
|
rejectHandlers.Add(new RejectHandler { callback = onRejected, rejectable = rejectable }); |
|
|
|
this.rejectHandlers.Add(new RejectHandler {callback = onRejected, rejectable = rejectable}); |
|
|
|
private void AddResolveHandler(Action<PromisedT> onResolved, IRejectable rejectable) |
|
|
|
{ |
|
|
|
if (resolveCallbacks == null) |
|
|
|
{ |
|
|
|
resolveCallbacks = new List<Action<PromisedT>>(); |
|
|
|
void AddResolveHandler(Action<PromisedT> onResolved, IRejectable rejectable) { |
|
|
|
if (this.resolveCallbacks == null) { |
|
|
|
this.resolveCallbacks = new List<Action<PromisedT>>(); |
|
|
|
if (resolveRejectables == null) |
|
|
|
{ |
|
|
|
resolveRejectables = new List<IRejectable>(); |
|
|
|
if (this.resolveRejectables == null) { |
|
|
|
this.resolveRejectables = new List<IRejectable>(); |
|
|
|
resolveCallbacks.Add(onResolved); |
|
|
|
resolveRejectables.Add(rejectable); |
|
|
|
this.resolveCallbacks.Add(onResolved); |
|
|
|
this.resolveRejectables.Add(rejectable); |
|
|
|
private void AddProgressHandler(Action<float> onProgress, IRejectable rejectable) |
|
|
|
{ |
|
|
|
if (progressHandlers == null) |
|
|
|
{ |
|
|
|
progressHandlers = new List<ProgressHandler>(); |
|
|
|
void AddProgressHandler(Action<float> onProgress, IRejectable rejectable) { |
|
|
|
if (this.progressHandlers == null) { |
|
|
|
this.progressHandlers = new List<ProgressHandler>(); |
|
|
|
progressHandlers.Add(new ProgressHandler { callback = onProgress, rejectable = rejectable }); |
|
|
|
this.progressHandlers.Add(new ProgressHandler {callback = onProgress, rejectable = rejectable}); |
|
|
|
private void InvokeHandler<T>(Action<T> callback, IRejectable rejectable, T value) |
|
|
|
{ |
|
|
|
void InvokeHandler<T>(Action<T> callback, IRejectable rejectable, T value) { |
|
|
|
try |
|
|
|
{ |
|
|
|
try { |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
} catch (Exception ex) { |
|
|
|
rejectable.Reject(ex); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
/// </summary>
|
|
|
|
private void ClearHandlers() |
|
|
|
{ |
|
|
|
rejectHandlers = null; |
|
|
|
resolveCallbacks = null; |
|
|
|
resolveRejectables = null; |
|
|
|
progressHandlers = null; |
|
|
|
void ClearHandlers() { |
|
|
|
this.rejectHandlers = null; |
|
|
|
this.resolveCallbacks = null; |
|
|
|
this.resolveRejectables = null; |
|
|
|
this.progressHandlers = null; |
|
|
|
private void InvokeRejectHandlers(Exception ex) |
|
|
|
{ |
|
|
|
void InvokeRejectHandlers(Exception ex) { |
|
|
|
if (rejectHandlers != null) |
|
|
|
{ |
|
|
|
rejectHandlers.Each(handler => InvokeHandler(handler.callback, handler.rejectable, ex)); |
|
|
|
if (this.rejectHandlers != null) { |
|
|
|
this.rejectHandlers.Each(handler => this.InvokeHandler(handler.callback, handler.rejectable, ex)); |
|
|
|
ClearHandlers(); |
|
|
|
this.ClearHandlers(); |
|
|
|
private void InvokeResolveHandlers(PromisedT value) |
|
|
|
{ |
|
|
|
if (resolveCallbacks != null) |
|
|
|
{ |
|
|
|
for (int i = 0, maxI = resolveCallbacks.Count; i < maxI; i++) { |
|
|
|
InvokeHandler(resolveCallbacks[i], resolveRejectables[i], value); |
|
|
|
void InvokeResolveHandlers(PromisedT value) { |
|
|
|
if (this.resolveCallbacks != null) { |
|
|
|
for (int i = 0, maxI = this.resolveCallbacks.Count; i < maxI; i++) { |
|
|
|
this.InvokeHandler(this.resolveCallbacks[i], this.resolveRejectables[i], value); |
|
|
|
ClearHandlers(); |
|
|
|
this.ClearHandlers(); |
|
|
|
private void InvokeProgressHandlers(float progress) |
|
|
|
{ |
|
|
|
if (progressHandlers != null) |
|
|
|
{ |
|
|
|
progressHandlers.Each(handler => InvokeHandler(handler.callback, handler.rejectable, progress)); |
|
|
|
void InvokeProgressHandlers(float progress) { |
|
|
|
if (this.progressHandlers != null) { |
|
|
|
this.progressHandlers.Each( |
|
|
|
handler => this.InvokeHandler(handler.callback, handler.rejectable, progress)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
public void Reject(Exception ex) { |
|
|
|
if (IsSync) { |
|
|
|
RejectSync(ex); |
|
|
|
if (this.IsSync) { |
|
|
|
this.RejectSync(ex); |
|
|
|
Window.instance.run(() => RejectSync(ex)); |
|
|
|
Window.instance.run(() => this.RejectSync(ex)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
if (CurState != PromiseState.Pending) { |
|
|
|
if (this.CurState != PromiseState.Pending) { |
|
|
|
+ CurState |
|
|
|
+ this.CurState |
|
|
|
rejectionException = ex; |
|
|
|
CurState = PromiseState.Rejected; |
|
|
|
this.rejectionException = ex; |
|
|
|
this.CurState = PromiseState.Rejected; |
|
|
|
InvokeRejectHandlers(ex); |
|
|
|
this.InvokeRejectHandlers(ex); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
if (IsSync) { |
|
|
|
ResolveSync(value); |
|
|
|
if (this.IsSync) { |
|
|
|
this.ResolveSync(value); |
|
|
|
Window.instance.run(() => ResolveSync(value)); |
|
|
|
Window.instance.run(() => this.ResolveSync(value)); |
|
|
|
if (CurState != PromiseState.Pending) { |
|
|
|
if (this.CurState != PromiseState.Pending) { |
|
|
|
+ CurState |
|
|
|
+ this.CurState |
|
|
|
resolveValue = value; |
|
|
|
CurState = PromiseState.Resolved; |
|
|
|
this.resolveValue = value; |
|
|
|
this.CurState = PromiseState.Resolved; |
|
|
|
InvokeResolveHandlers(value); |
|
|
|
this.InvokeResolveHandlers(value); |
|
|
|
public void ReportProgress(float progress) |
|
|
|
{ |
|
|
|
if (CurState != PromiseState.Pending) |
|
|
|
{ |
|
|
|
public void ReportProgress(float progress) { |
|
|
|
if (this.CurState != PromiseState.Pending) { |
|
|
|
"Attempt to report progress on a promise that is already in state: " |
|
|
|
+ CurState + ", a promise can only report progress when it is still in state: " |
|
|
|
"Attempt to report progress on a promise that is already in state: " |
|
|
|
+ this.CurState + ", a promise can only report progress when it is still in state: " |
|
|
|
InvokeProgressHandlers(progress); |
|
|
|
this.InvokeProgressHandlers(progress); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
public void Done(Action<PromisedT> onResolved, Action<Exception> onRejected) |
|
|
|
{ |
|
|
|
Then(onResolved, onRejected) |
|
|
|
public void Done(Action<PromisedT> onResolved, Action<Exception> onRejected) { |
|
|
|
this.Then(onResolved, onRejected) |
|
|
|
.Catch(ex => |
|
|
|
Promise.PropagateUnhandledException(this, ex) |
|
|
|
); |
|
|
|
|
|
|
/// onResolved is called on successful completion.
|
|
|
|
/// Adds a default error handler.
|
|
|
|
/// </summary>
|
|
|
|
public void Done(Action<PromisedT> onResolved) |
|
|
|
{ |
|
|
|
Then(onResolved) |
|
|
|
public void Done(Action<PromisedT> onResolved) { |
|
|
|
this.Then(onResolved) |
|
|
|
.Catch(ex => |
|
|
|
Promise.PropagateUnhandledException(this, ex) |
|
|
|
); |
|
|
|
|
|
|
/// Complete the promise. Adds a default error handler.
|
|
|
|
/// </summary>
|
|
|
|
public void Done() |
|
|
|
{ |
|
|
|
Catch(ex => |
|
|
|
public void Done() { |
|
|
|
this.Catch(ex => |
|
|
|
Promise.PropagateUnhandledException(this, ex) |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
/// </summary>
|
|
|
|
public IPromise<PromisedT> WithName(string name) |
|
|
|
{ |
|
|
|
public IPromise<PromisedT> WithName(string name) { |
|
|
|
this.Name = name; |
|
|
|
return this; |
|
|
|
} |
|
|
|
|
|
|
/// </summary>
|
|
|
|
public IPromise Catch(Action<Exception> onRejected) |
|
|
|
{ |
|
|
|
public IPromise Catch(Action<Exception> onRejected) { |
|
|
|
resultPromise.WithName(Name); |
|
|
|
resultPromise.WithName(this.Name); |
|
|
|
Action<Exception> rejectHandler = ex => |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
Action<Exception> rejectHandler = ex => { |
|
|
|
try { |
|
|
|
} |
|
|
|
catch(Exception cbEx) |
|
|
|
{ |
|
|
|
} catch (Exception cbEx) { |
|
|
|
ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
ProgressHandlers(resultPromise, v => resultPromise.ReportProgress(v)); |
|
|
|
this.ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
this.ProgressHandlers(resultPromise, v => resultPromise.ReportProgress(v)); |
|
|
|
|
|
|
|
return resultPromise; |
|
|
|
} |
|
|
|
|
|
|
/// </summary>
|
|
|
|
public IPromise<PromisedT> Catch(Func<Exception, PromisedT> onRejected) |
|
|
|
{ |
|
|
|
public IPromise<PromisedT> Catch(Func<Exception, PromisedT> onRejected) { |
|
|
|
resultPromise.WithName(Name); |
|
|
|
resultPromise.WithName(this.Name); |
|
|
|
Action<Exception> rejectHandler = ex => |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
Action<Exception> rejectHandler = ex => { |
|
|
|
try { |
|
|
|
} |
|
|
|
catch (Exception cbEx) |
|
|
|
{ |
|
|
|
} catch (Exception cbEx) { |
|
|
|
ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
ProgressHandlers(resultPromise, v => resultPromise.ReportProgress(v)); |
|
|
|
this.ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
this.ProgressHandlers(resultPromise, v => resultPromise.ReportProgress(v)); |
|
|
|
|
|
|
|
return resultPromise; |
|
|
|
} |
|
|
|
|
|
|
/// </summary>
|
|
|
|
public IPromise<ConvertedT> Then<ConvertedT>(Func<PromisedT, IPromise<ConvertedT>> onResolved) |
|
|
|
{ |
|
|
|
return Then(onResolved, null, null); |
|
|
|
public IPromise<ConvertedT> Then<ConvertedT>(Func<PromisedT, IPromise<ConvertedT>> onResolved) { |
|
|
|
return this.Then(onResolved, null, null); |
|
|
|
public IPromise Then(Func<PromisedT, IPromise> onResolved) |
|
|
|
{ |
|
|
|
return Then(onResolved, null, null); |
|
|
|
public IPromise Then(Func<PromisedT, IPromise> onResolved) { |
|
|
|
return this.Then(onResolved, null, null); |
|
|
|
public IPromise Then(Action<PromisedT> onResolved) |
|
|
|
{ |
|
|
|
return Then(onResolved, null, null); |
|
|
|
public IPromise Then(Action<PromisedT> onResolved) { |
|
|
|
return this.Then(onResolved, null, null); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
public IPromise<ConvertedT> Then<ConvertedT>( |
|
|
|
Func<PromisedT, IPromise<ConvertedT>> onResolved, |
|
|
|
Func<Exception, IPromise<ConvertedT>> onRejected |
|
|
|
) |
|
|
|
{ |
|
|
|
return Then(onResolved, onRejected, null); |
|
|
|
) { |
|
|
|
return this.Then(onResolved, onRejected, null); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
public IPromise Then(Func<PromisedT, IPromise> onResolved, Action<Exception> onRejected) |
|
|
|
{ |
|
|
|
return Then(onResolved, onRejected, null); |
|
|
|
public IPromise Then(Func<PromisedT, IPromise> onResolved, Action<Exception> onRejected) { |
|
|
|
return this.Then(onResolved, onRejected, null); |
|
|
|
public IPromise Then(Action<PromisedT> onResolved, Action<Exception> onRejected) |
|
|
|
{ |
|
|
|
return Then(onResolved, onRejected, null); |
|
|
|
public IPromise Then(Action<PromisedT> onResolved, Action<Exception> onRejected) { |
|
|
|
return this.Then(onResolved, onRejected, null); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
public IPromise<ConvertedT> Then<ConvertedT>( |
|
|
|
Func<PromisedT, IPromise<ConvertedT>> onResolved, |
|
|
|
Func<PromisedT, IPromise<ConvertedT>> onResolved, |
|
|
|
) |
|
|
|
{ |
|
|
|
) { |
|
|
|
resultPromise.WithName(Name); |
|
|
|
resultPromise.WithName(this.Name); |
|
|
|
Action<PromisedT> resolveHandler = v => |
|
|
|
{ |
|
|
|
Action<PromisedT> resolveHandler = v => { |
|
|
|
onResolved(v) |
|
|
|
.Progress(progress => resultPromise.ReportProgress(progress)) |
|
|
|
.Then( |
|
|
|
|
|
|
); |
|
|
|
}; |
|
|
|
|
|
|
|
Action<Exception> rejectHandler = ex => |
|
|
|
{ |
|
|
|
if (onRejected == null) |
|
|
|
{ |
|
|
|
Action<Exception> rejectHandler = ex => { |
|
|
|
if (onRejected == null) { |
|
|
|
try |
|
|
|
{ |
|
|
|
try { |
|
|
|
} |
|
|
|
catch (Exception callbackEx) |
|
|
|
{ |
|
|
|
} catch (Exception callbackEx) { |
|
|
|
ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
if (onProgress != null) |
|
|
|
{ |
|
|
|
ProgressHandlers(this, onProgress); |
|
|
|
this.ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
if (onProgress != null) { |
|
|
|
this.ProgressHandlers(this, onProgress); |
|
|
|
} |
|
|
|
|
|
|
|
return resultPromise; |
|
|
|
|
|
|
/// Add a resolved callback, a rejected callback and a progress callback.
|
|
|
|
/// The resolved callback chains a non-value promise.
|
|
|
|
/// </summary>
|
|
|
|
public IPromise Then(Func<PromisedT, IPromise> onResolved, Action<Exception> onRejected, Action<float> onProgress) |
|
|
|
{ |
|
|
|
public IPromise Then(Func<PromisedT, IPromise> onResolved, Action<Exception> onRejected, |
|
|
|
Action<float> onProgress) { |
|
|
|
resultPromise.WithName(Name); |
|
|
|
resultPromise.WithName(this.Name); |
|
|
|
Action<PromisedT> resolveHandler = v => |
|
|
|
{ |
|
|
|
if (onResolved != null) |
|
|
|
{ |
|
|
|
Action<PromisedT> resolveHandler = v => { |
|
|
|
if (onResolved != null) { |
|
|
|
onResolved(v) |
|
|
|
.Progress(progress => resultPromise.ReportProgress(progress)) |
|
|
|
.Then( |
|
|
|
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
} else { |
|
|
|
Action<Exception> rejectHandler = ex => |
|
|
|
{ |
|
|
|
if (onRejected != null) |
|
|
|
{ |
|
|
|
Action<Exception> rejectHandler = ex => { |
|
|
|
if (onRejected != null) { |
|
|
|
onRejected(ex); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
if (onProgress != null) |
|
|
|
{ |
|
|
|
ProgressHandlers(this, onProgress); |
|
|
|
this.ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
if (onProgress != null) { |
|
|
|
this.ProgressHandlers(this, onProgress); |
|
|
|
} |
|
|
|
|
|
|
|
return resultPromise; |
|
|
|
|
|
|
/// Add a resolved callback, a rejected callback and a progress callback.
|
|
|
|
/// </summary>
|
|
|
|
public IPromise Then(Action<PromisedT> onResolved, Action<Exception> onRejected, Action<float> onProgress) |
|
|
|
{ |
|
|
|
public IPromise Then(Action<PromisedT> onResolved, Action<Exception> onRejected, Action<float> onProgress) { |
|
|
|
resultPromise.WithName(Name); |
|
|
|
resultPromise.WithName(this.Name); |
|
|
|
Action<PromisedT> resolveHandler = v => |
|
|
|
{ |
|
|
|
if (onResolved != null) |
|
|
|
{ |
|
|
|
Action<PromisedT> resolveHandler = v => { |
|
|
|
if (onResolved != null) { |
|
|
|
onResolved(v); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
Action<Exception> rejectHandler = ex => |
|
|
|
{ |
|
|
|
if (onRejected != null) |
|
|
|
{ |
|
|
|
Action<Exception> rejectHandler = ex => { |
|
|
|
if (onRejected != null) { |
|
|
|
onRejected(ex); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
if (onProgress != null) |
|
|
|
{ |
|
|
|
ProgressHandlers(this, onProgress); |
|
|
|
this.ActionHandlers(resultPromise, resolveHandler, rejectHandler); |
|
|
|
if (onProgress != null) { |
|
|
|
this.ProgressHandlers(this, onProgress); |
|
|
|
} |
|
|
|
|
|
|
|
return resultPromise; |
|
|
|
|
|
|
/// Return a new promise with a different value.
|
|
|
|
/// May also change the type of the value.
|
|
|
|
/// </summary>
|
|
|
|
public IPromise<ConvertedT> Then<ConvertedT>(Func<PromisedT, ConvertedT> transform) |
|
|
|
{ |
|
|
|
public IPromise<ConvertedT> Then<ConvertedT>(Func<PromisedT, ConvertedT> transform) { |
|
|
|
return Then(value => Promise<ConvertedT>.Resolved(transform(value))); |
|
|
|
return this.Then(value => Promise<ConvertedT>.Resolved(transform(value))); |
|
|
|
private void ActionHandlers(IRejectable resultPromise, Action<PromisedT> resolveHandler, Action<Exception> rejectHandler) |
|
|
|
{ |
|
|
|
if (CurState == PromiseState.Resolved) { |
|
|
|
InvokeHandler(resolveHandler, resultPromise, resolveValue); |
|
|
|
} |
|
|
|
else if (CurState == PromiseState.Rejected) { |
|
|
|
InvokeHandler(rejectHandler, resultPromise, rejectionException); |
|
|
|
} |
|
|
|
else { |
|
|
|
AddResolveHandler(resolveHandler, resultPromise); |
|
|
|
AddRejectHandler(rejectHandler, resultPromise); |
|
|
|
void ActionHandlers(IRejectable resultPromise, Action<PromisedT> resolveHandler, |
|
|
|
Action<Exception> rejectHandler) { |
|
|
|
if (this.CurState == PromiseState.Resolved) { |
|
|
|
this.InvokeHandler(resolveHandler, resultPromise, this.resolveValue); |
|
|
|
} else if (this.CurState == PromiseState.Rejected) { |
|
|
|
this.InvokeHandler(rejectHandler, resultPromise, this.rejectionException); |
|
|
|
} else { |
|
|
|
this.AddResolveHandler(resolveHandler, resultPromise); |
|
|
|
this.AddRejectHandler(rejectHandler, resultPromise); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
private void ProgressHandlers(IRejectable resultPromise, Action<float> progressHandler) |
|
|
|
{ |
|
|
|
if (CurState == PromiseState.Pending) |
|
|
|
{ |
|
|
|
AddProgressHandler(progressHandler, resultPromise); |
|
|
|
void ProgressHandlers(IRejectable resultPromise, Action<float> progressHandler) { |
|
|
|
if (this.CurState == PromiseState.Pending) { |
|
|
|
this.AddProgressHandler(progressHandler, resultPromise); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
/// The resulting promise is resolved when all of the promises have resolved.
|
|
|
|
/// It is rejected as soon as any of the promises have been rejected.
|
|
|
|
/// </summary>
|
|
|
|
public IPromise<IEnumerable<ConvertedT>> ThenAll<ConvertedT>(Func<PromisedT, IEnumerable<IPromise<ConvertedT>>> chain) |
|
|
|
{ |
|
|
|
return Then(value => Promise<ConvertedT>.All(chain(value))); |
|
|
|
public IPromise<IEnumerable<ConvertedT>> ThenAll<ConvertedT>( |
|
|
|
Func<PromisedT, IEnumerable<IPromise<ConvertedT>>> chain) { |
|
|
|
return this.Then(value => Promise<ConvertedT>.All(chain(value))); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
/// It is rejected as soon as any of the promises have been rejected.
|
|
|
|
/// </summary>
|
|
|
|
public IPromise ThenAll(Func<PromisedT, IEnumerable<IPromise>> chain) |
|
|
|
{ |
|
|
|
return Then(value => Promise.All(chain(value))); |
|
|
|
public IPromise ThenAll(Func<PromisedT, IEnumerable<IPromise>> chain) { |
|
|
|
return this.Then(value => Promise.All(chain(value))); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
public static IPromise<IEnumerable<PromisedT>> All(params IPromise<PromisedT>[] promises) |
|
|
|
{ |
|
|
|
return All((IEnumerable<IPromise<PromisedT>>)promises); // Cast is required to force use of the other All function.
|
|
|
|
public static IPromise<IEnumerable<PromisedT>> All(params IPromise<PromisedT>[] promises) { |
|
|
|
return |
|
|
|
All( |
|
|
|
(IEnumerable<IPromise<PromisedT>>) |
|
|
|
promises); // Cast is required to force use of the other All function.
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
public static IPromise<IEnumerable<PromisedT>> All(IEnumerable<IPromise<PromisedT>> promises) |
|
|
|
{ |
|
|
|
public static IPromise<IEnumerable<PromisedT>> All(IEnumerable<IPromise<PromisedT>> promises) { |
|
|
|
if (promisesArray.Length == 0) |
|
|
|
{ |
|
|
|
if (promisesArray.Length == 0) { |
|
|
|
return Promise<IEnumerable<PromisedT>>.Resolved(Enumerable.Empty<PromisedT>()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
var resultPromise = new Promise<IEnumerable<PromisedT>>(); |
|
|
|
resultPromise.WithName("All"); |
|
|
|
|
|
|
|
promisesArray.Each((promise, index) => |
|
|
|
{ |
|
|
|
promisesArray.Each((promise, index) => { |
|
|
|
.Progress(v => |
|
|
|
{ |
|
|
|
.Progress(v => { |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) |
|
|
|
{ |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) { |
|
|
|
.Then(result => |
|
|
|
{ |
|
|
|
.Then(result => { |
|
|
|
if (remainingCount <= 0 && resultPromise.CurState == PromiseState.Pending) |
|
|
|
{ |
|
|
|
if (remainingCount <= 0 && resultPromise.CurState == PromiseState.Pending) { |
|
|
|
.Catch(ex => |
|
|
|
{ |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) |
|
|
|
{ |
|
|
|
.Catch(ex => { |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) { |
|
|
|
// If a promise errorred and the result promise is still pending, reject it.
|
|
|
|
resultPromise.Reject(ex); |
|
|
|
} |
|
|
|
|
|
|
/// Returns a promise that resolves when the first of the promises has resolved.
|
|
|
|
/// Yields the value from the first promise that has resolved.
|
|
|
|
/// </summary>
|
|
|
|
public IPromise<ConvertedT> ThenRace<ConvertedT>(Func<PromisedT, IEnumerable<IPromise<ConvertedT>>> chain) |
|
|
|
{ |
|
|
|
return Then(value => Promise<ConvertedT>.Race(chain(value))); |
|
|
|
public IPromise<ConvertedT> ThenRace<ConvertedT>(Func<PromisedT, IEnumerable<IPromise<ConvertedT>>> chain) { |
|
|
|
return this.Then(value => Promise<ConvertedT>.Race(chain(value))); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
/// Yields the value from the first promise that has resolved.
|
|
|
|
/// </summary>
|
|
|
|
public IPromise ThenRace(Func<PromisedT, IEnumerable<IPromise>> chain) |
|
|
|
{ |
|
|
|
return Then(value => Promise.Race(chain(value))); |
|
|
|
public IPromise ThenRace(Func<PromisedT, IEnumerable<IPromise>> chain) { |
|
|
|
return this.Then(value => Promise.Race(chain(value))); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
public static IPromise<PromisedT> Race(params IPromise<PromisedT>[] promises) |
|
|
|
{ |
|
|
|
return Race((IEnumerable<IPromise<PromisedT>>)promises); // Cast is required to force use of the other function.
|
|
|
|
public static IPromise<PromisedT> Race(params IPromise<PromisedT>[] promises) { |
|
|
|
return |
|
|
|
Race( |
|
|
|
(IEnumerable<IPromise<PromisedT>>) |
|
|
|
promises); // Cast is required to force use of the other function.
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
public static IPromise<PromisedT> Race(IEnumerable<IPromise<PromisedT>> promises) |
|
|
|
{ |
|
|
|
public static IPromise<PromisedT> Race(IEnumerable<IPromise<PromisedT>> promises) { |
|
|
|
if (promisesArray.Length == 0) |
|
|
|
{ |
|
|
|
if (promisesArray.Length == 0) { |
|
|
|
throw new InvalidOperationException( |
|
|
|
"At least 1 input promise must be provided for Race" |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
var progress = new float[promisesArray.Length]; |
|
|
|
|
|
|
|
promisesArray.Each((promise, index) => |
|
|
|
{ |
|
|
|
promisesArray.Each((promise, index) => { |
|
|
|
.Progress(v => |
|
|
|
{ |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) |
|
|
|
{ |
|
|
|
.Progress(v => { |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) { |
|
|
|
.Then(result => |
|
|
|
{ |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) |
|
|
|
{ |
|
|
|
.Then(result => { |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) { |
|
|
|
.Catch(ex => |
|
|
|
{ |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) |
|
|
|
{ |
|
|
|
.Catch(ex => { |
|
|
|
if (resultPromise.CurState == PromiseState.Pending) { |
|
|
|
// If a promise errorred and the result promise is still pending, reject it.
|
|
|
|
resultPromise.Reject(ex); |
|
|
|
} |
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Convert a simple value directly into a resolved promise.
|
|
|
|
/// </summary>
|
|
|
|
public static IPromise<PromisedT> Resolved(PromisedT promisedValue) |
|
|
|
{ |
|
|
|
public static IPromise<PromisedT> Resolved(PromisedT promisedValue) { |
|
|
|
var promise = new Promise<PromisedT>(isSync: true); |
|
|
|
promise.Resolve(promisedValue); |
|
|
|
return promise; |
|
|
|
|
|
|
/// Convert an exception directly into a rejected promise.
|
|
|
|
/// </summary>
|
|
|
|
public static IPromise<PromisedT> Rejected(Exception ex) |
|
|
|
{ |
|
|
|
public static IPromise<PromisedT> Rejected(Exception ex) { |
|
|
|
// Argument.NotNull(() => ex);
|
|
|
|
|
|
|
|
var promise = new Promise<PromisedT>(); |
|
|
|
|
|
|
|
|
|
|
public IPromise<PromisedT> Finally(Action onComplete) |
|
|
|
{ |
|
|
|
public IPromise<PromisedT> Finally(Action onComplete) { |
|
|
|
promise.WithName(Name); |
|
|
|
promise.WithName(this.Name); |
|
|
|
|
|
|
|
this.Then(x => promise.Resolve(x)); |
|
|
|
this.Catch(e => { |
|
|
|
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
return promise.Then(v => |
|
|
|
{ |
|
|
|
return promise.Then(v => { |
|
|
|
public IPromise ContinueWith(Func<IPromise> onComplete) |
|
|
|
{ |
|
|
|
public IPromise ContinueWith(Func<IPromise> onComplete) { |
|
|
|
promise.WithName(Name); |
|
|
|
promise.WithName(this.Name); |
|
|
|
|
|
|
|
this.Then(x => promise.Resolve()); |
|
|
|
this.Catch(e => promise.Resolve()); |
|
|
|
|
|
|
|
|
|
|
public IPromise<ConvertedT> ContinueWith<ConvertedT>(Func<IPromise<ConvertedT>> onComplete) |
|
|
|
{ |
|
|
|
public IPromise<ConvertedT> ContinueWith<ConvertedT>(Func<IPromise<ConvertedT>> onComplete) { |
|
|
|
promise.WithName(Name); |
|
|
|
promise.WithName(this.Name); |
|
|
|
|
|
|
|
this.Then(x => promise.Resolve()); |
|
|
|
this.Catch(e => promise.Resolve()); |
|
|
|
|
|
|
|
|
|
|
public IPromise<PromisedT> Progress(Action<float> onProgress) |
|
|
|
{ |
|
|
|
if (onProgress != null) |
|
|
|
{ |
|
|
|
ProgressHandlers(this, onProgress); |
|
|
|
public IPromise<PromisedT> Progress(Action<float> onProgress) { |
|
|
|
if (onProgress != null) { |
|
|
|
this.ProgressHandlers(this, onProgress); |
|
|
|
} |
|
|
|
} |