# HG changeset patch # User cin # Date 2013-11-01 20:55:47 # Node ID c82e0dfbb4ddf9ae375cf213d9370b9d5835f268 # Parent 849075f49d5c5403a2081ae4ad78016bc2ebcb07 sync diff --git a/Implab/IPromise.cs b/Implab/IPromise.cs --- a/Implab/IPromise.cs +++ b/Implab/IPromise.cs @@ -26,7 +26,7 @@ namespace Implab /// /// Tries to cancel the promise or the complete chain. /// - /// Try to cancel the parent promise is it has the only one child + /// Try to cancel the whole promise chain, the parent promise will be cancelled only if it has only one promise /// bool Cancel(bool dependencies); } diff --git a/Implab/Promise.cs b/Implab/Promise.cs --- a/Implab/Promise.cs +++ b/Implab/Promise.cs @@ -48,28 +48,32 @@ namespace Implab { /// только инициатор обещания иначе могут возникнуть противоречия. /// /// - public class Promise: IPromise { + public class Promise : IPromise { struct ResultHandlerInfo { public ResultHandler resultHandler; public ErrorHandler errorHandler; - public Action cancelHandler; } - LinkedList m_handlersChain = new LinkedList(); + IPromise m_parent; + + LinkedList m_resultHandlers = new LinkedList(); + LinkedList m_cancelHandlers = new LinkedList(); + + object m_lock = new Object(); + bool m_cancellable; + PromiseState m_state; - bool m_cancellable; T m_result; Exception m_error; - IPromise m_parent; + int m_childrenCount; public Promise() { m_cancellable = true; } - public Promise(IPromise parent, bool cancellable) - { + public Promise(IPromise parent, bool cancellable) { m_cancellable = cancellable; m_parent = parent; } @@ -97,9 +101,14 @@ namespace Implab { m_state = PromiseState.Resolved; } - ResultHandlerInfo handler; + // state has been changed to rejected new handlers can't be added + + foreach (var handler in m_resultHandlers) + InvokeHandler(handler); + + /* ResultHandlerInfo handler; while (FetchNextHandler(out handler)) - InvokeHandler(handler); + InvokeHandler(handler); */ } /// @@ -117,9 +126,14 @@ namespace Implab { m_state = PromiseState.Rejected; } - ResultHandlerInfo handler; + // state has been changed to rejected new handlers can't be added + + foreach (var handler in m_resultHandlers) + InvokeHandler(handler); + + /*ResultHandlerInfo handler; while (FetchNextHandler(out handler)) - InvokeHandler(handler); + InvokeHandler(handler);*/ } /// @@ -127,19 +141,7 @@ namespace Implab { /// /// true Операция была отменена, обработчики не будут вызваны.false отмена не возможна, поскольку обещание уже выполнено и обработчики отработали. public bool Cancel() { - lock (this) { - if (m_state == PromiseState.Unresolved && m_cancellable) - { - m_state = PromiseState.Cancelled; - EventHandler temp = Cancelled; - - if (temp != null) - temp(this, new EventArgs()); - - return true; - } else - return false; - } + return Cancel(true); } /// @@ -353,9 +355,9 @@ namespace Implab { lock (this) { Debug.Assert(m_state != PromiseState.Unresolved); - if (m_handlersChain.Count > 0) { - handler = m_handlersChain.First.Value; - m_handlersChain.RemoveFirst(); + if (m_resultHandlers.Count > 0) { + handler = m_resultHandlers.First.Value; + m_resultHandlers.RemoveFirst(); return true; } else { return false; @@ -368,7 +370,7 @@ namespace Implab { lock (this) { if (m_state == PromiseState.Unresolved) - m_handlersChain.AddLast(handler); + m_resultHandlers.AddLast(handler); else invokeRequired = true; } @@ -395,5 +397,47 @@ namespace Implab { } + + public bool IsExclusive { + get { + lock (m_lock) { + return m_childrenCount <= 1; + } + } + } + + public PromiseState State { + get { + lock (m_lock) { + return m_state; + } + } + } + + public bool Cancel(bool dependencies) { + bool result; + + lock (m_lock) { + if (m_state == PromiseState.Unresolved) { + m_state = PromiseState.Cancelled; + result = true; + } else { + result = false; + } + } + + if (dependencies && m_parent != null && m_parent.IsExclusive) { + // TODO syncronize IsExclusive, AddHandler, Cancel (maybe CancelExclusive) + m_parent.Cancel(true); + } + + if (result) { + // state has been changed to cancelled, new handlers can't be added + foreach (var handler in m_cancelHandlers) + handler(); + } + + return result; + } } }