using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace Implab { class PromiseAll : IResolvable { int m_count; readonly List> m_promises = new List>(); readonly Deferred m_deferred; IPromise m_result; readonly Func m_cleanup; readonly Action m_cancel; public bool Done { get { return m_deferred.Promise.IsResolved && m_cleanup == null; } } public IPromise ResultPromise { get { return m_result; } } public void AddPromise(IPromise promise) { Interlocked.Increment(ref m_count); promise.Then(this); } public PromiseAll(Deferred deferred, Func 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 CleanupResults(Exception reason) { var errors = new List(); 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(new Func(() => { throw new AggregateException(errors); }), (Func)null); } else { return Promise.Reject(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; } } }