# HG changeset patch # User cin # Date 2014-11-11 01:14:21 # Node ID f5220e5472ef625fa0fcc3e9fbd0b5b8eff1f859 # Parent d4e38929ce36ce64cc0273cbc689fb35390bfbf8 minor fixes and optimizations diff --git a/Implab/Promise.cs b/Implab/Promise.cs --- a/Implab/Promise.cs +++ b/Implab/Promise.cs @@ -48,14 +48,14 @@ namespace Implab { public abstract void Cancel(); } - protected class HandlerDescriptor : AbstractHandler { + protected class RemapDescriptor : AbstractHandler { readonly Func m_resultHandler; readonly Func m_errorHandler; readonly Action m_cancellHandler; readonly Promise m_medium; - public HandlerDescriptor(Func resultHandler, Func errorHandler, Action cancelHandler, Promise medium) { + public RemapDescriptor(Func resultHandler, Func errorHandler, Action cancelHandler, Promise medium) { m_resultHandler = resultHandler; m_errorHandler = errorHandler; m_cancellHandler = cancelHandler; @@ -82,9 +82,61 @@ namespace Implab { var res = m_errorHandler(error); if (m_medium != null) m_medium.Resolve(res); - /*} catch (TransientPromiseException err2) { - if (medium != null) - medium.Reject(err2.InnerException);*/ + } catch (Exception err2) { + if (m_medium != null) + m_medium.Reject(err2); + } + } else if (m_medium != null) + m_medium.Reject(error); + } + + public override void Cancel() { + if (m_cancellHandler != null) { + try { + m_cancellHandler(); + } catch (Exception err) { + Reject(err); + return; + } + } + if (m_medium != null) + m_medium.Cancel(); + } + } + + protected class HandlerDescriptor : AbstractHandler { + + readonly Action m_resultHandler; + readonly Action m_errorHandler; + readonly Action m_cancellHandler; + readonly Promise m_medium; + + public HandlerDescriptor(Action resultHandler, Action errorHandler, Action cancelHandler, Promise medium) { + m_resultHandler = resultHandler; + m_errorHandler = errorHandler; + m_cancellHandler = cancelHandler; + m_medium = medium; + } + + public override void Resolve(T result) { + if (m_resultHandler != null) { + try { + m_resultHandler(result); + } catch (Exception e) { + Reject(e); + return; + } + } + if(m_medium != null) + m_medium.Resolve(result); + } + + public override void Reject(Exception error) { + if (m_errorHandler != null) { + try { + m_errorHandler(error); + if (m_medium != null) + m_medium.Resolve(default(T)); } catch (Exception err2) { if (m_medium != null) m_medium.Reject(err2); @@ -126,7 +178,7 @@ namespace Implab { public Promise(IPromise parent) { if (parent != null) - AddHandler( + AddMappers( null, null, () => { @@ -252,43 +304,28 @@ namespace Implab { if (success == null && error == null && cancel == null) return; - AddHandler( - success != null ? new Func(x => { - success(x); - return x; - }) : null, - error != null ? new Func(e => { - error(e); - return default(T); - }) : null, - cancel, - null, - false - ); + AddHandler(success, error, cancel, null, false); } public void On(Action success, Action error) { - On(success, error, null); + AddHandler(success, error, null, null, false); } public void On(Action success) { - On(success, null, null); + AddHandler(success, null, null, null, false); } public void On(Action handler, PromiseEventType events) { Safe.ArgumentNotNull(handler, "handler"); - Func success = events.HasFlag(PromiseEventType.Success) ? new Func(x => { - handler(); - return x; - }) : null; - Func error = events.HasFlag(PromiseEventType.Error) ? new Func(e => { - handler(); - return default(T); - }) : null; - Action cancel = events.HasFlag(PromiseEventType.Cancelled) ? handler : null; - AddHandler(success, error, cancel, null, false); + AddHandler( + events.HasFlag(PromiseEventType.Success) ? new Action(x => handler()) : null, + events.HasFlag(PromiseEventType.Error) ? new Action( x => handler()) : null, + events.HasFlag(PromiseEventType.Cancelled) ? handler : null, + null, + false + ); } public IPromise Error(Action error) { @@ -297,7 +334,7 @@ namespace Implab { var medium = new Promise(this); - AddHandler( + AddMappers( null, e => { error(e); @@ -325,7 +362,7 @@ namespace Implab { var medium = new Promise(this); - AddHandler(null, handler, null, medium, true); + AddMappers(null, handler, null, medium, true); return medium; } @@ -345,7 +382,7 @@ namespace Implab { // создаем прицепленное обещание var medium = new Promise(this); - AddHandler( + AddMappers( mapper, error, cancel, @@ -454,7 +491,7 @@ namespace Implab { else cancelHandler = medium.Cancel; - AddHandler( + AddMappers( resultHandler, errorHandler, cancelHandler, @@ -490,10 +527,7 @@ namespace Implab { var medium = new Promise(this); AddHandler( - x => { - handler(); - return x; - }, + x => handler(), e => { handler(); throw new TransientPromiseException(e); @@ -559,11 +593,37 @@ namespace Implab { return Join(Timeout.Infinite); } - void AddHandler(Func success, Func error, Action cancel, Promise medium, bool inc) { + void AddMappers(Func success, Func error, Action cancel, Promise medium, bool inc) { if (inc) Interlocked.Increment(ref m_childrenCount); - AbstractHandler handler = new HandlerDescriptor(success, error, cancel, medium); + AbstractHandler handler = new RemapDescriptor(success, error, cancel, medium); + + bool queued; + + if (!IsResolved) { + m_handlers.Enqueue(handler); + queued = true; + } else { + // the promise is in resolved state, just invoke the handled with minimum overhead + queued = false; + InvokeHandler(handler); + } + + if (queued && IsResolved && m_handlers.TryDequeue(out handler)) + // if the promise have been resolved while we was adding handler to the queue + // we can't guarantee that someone is still processing it + // therefore we will fetch a handler from the queue and execute it + // note that fetched handler may be not the one that we have added + // even we can fetch no handlers at all :) + InvokeHandler(handler); + } + + void AddHandler(Action success, Action error, Action cancel, Promise medium, bool inc) { + if (inc) + Interlocked.Increment(ref m_childrenCount); + + AbstractHandler handler = new HandlerDescriptor(success, error, cancel, medium); bool queued; @@ -834,7 +894,7 @@ namespace Implab { else cancelHandler = medium.Cancel; - AddHandler( + AddMappers( resultHandler, errorHandler, cancelHandler,