|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Threading;
|
|
|
|
|
|
namespace Implab {
|
|
|
class PromiseAll<T> : IResolvable {
|
|
|
|
|
|
int m_count;
|
|
|
|
|
|
readonly List<IPromise<T>> m_promises = new List<IPromise<T>>();
|
|
|
|
|
|
readonly Deferred<T[]> m_deferred;
|
|
|
|
|
|
IPromise<T[]> m_result;
|
|
|
|
|
|
readonly Func<T, IPromise> m_cleanup;
|
|
|
|
|
|
readonly Action m_cancel;
|
|
|
|
|
|
public bool Done {
|
|
|
get { return m_deferred.Promise.IsResolved && m_cleanup == null; }
|
|
|
}
|
|
|
|
|
|
public IPromise<T[]> ResultPromise {
|
|
|
get { return m_result; }
|
|
|
}
|
|
|
|
|
|
public void AddPromise(IPromise<T> promise) {
|
|
|
Interlocked.Increment(ref m_count);
|
|
|
promise.Then(this);
|
|
|
}
|
|
|
|
|
|
public PromiseAll(Deferred<T[]> deferred, Func<T, IPromise> cleanup, Action cancel) {
|
|
|
m_deferred = deferred;
|
|
|
m_cancel = cancel;
|
|
|
m_cleanup = cleanup;
|
|
|
}
|
|
|
|
|
|
public void Resolve() {
|
|
|
if (Interlocked.Decrement(ref m_count) == 0)
|
|
|
m_deferred.Resolve(GetResults());
|
|
|
}
|
|
|
|
|
|
public void Reject(Exception error) {
|
|
|
m_deferred.Reject(error);
|
|
|
}
|
|
|
|
|
|
public void Complete() {
|
|
|
if (m_cancel != null || m_cleanup != null)
|
|
|
m_result = m_deferred.Promise.Catch(CleanupResults);
|
|
|
else
|
|
|
m_result = m_deferred.Promise;
|
|
|
}
|
|
|
|
|
|
IPromise<T[]> CleanupResults(Exception reason) {
|
|
|
var errors = new List<Exception>();
|
|
|
errors.Add(reason);
|
|
|
|
|
|
if (m_cancel != null)
|
|
|
try {
|
|
|
m_cancel();
|
|
|
} catch (Exception e) {
|
|
|
errors.Add(e);
|
|
|
}
|
|
|
|
|
|
if (m_cleanup != null) {
|
|
|
return Promise.All(
|
|
|
m_promises.Select(p => p
|
|
|
.Then(m_cleanup, e => { })
|
|
|
.Catch(e => {
|
|
|
errors.Add(e);
|
|
|
})
|
|
|
)
|
|
|
).Then<T[]>(new Func<T[]>(() => {
|
|
|
throw new AggregateException(errors);
|
|
|
}), (Func<Exception, T[]>)null);
|
|
|
} else {
|
|
|
return Promise.Reject<T[]>(errors.Count > 1 ? new AggregateException(errors) : reason);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
T[] GetResults() {
|
|
|
var results = new T[m_promises.Count];
|
|
|
for (var i = 0; i < results.Length; i++)
|
|
|
results[i] = m_promises[i].Join();
|
|
|
return results;
|
|
|
}
|
|
|
}
|
|
|
}
|