private static void SubscribeProgressToChain(Promise promise, InternalProtected.IProgressListener progressListener, ref ValueLinkedStack <InternalProtected.PromisePassThrough> passThroughs) { Promise next; // If the promise is not waiting on another promise (is the root), it sets next to null, does not add the listener, and returns false. // If the promise is waiting on another promise that is not its previous, it adds the listener, transforms progresslistener, sets next to the one it's waiting on, and returns true. // Otherwise, it sets next to its previous, adds the listener only if it is a WaitPromise, and returns true. while (promise.SubscribeProgressIfWaiterAndContinueLoop(ref progressListener, out next, ref passThroughs)) { promise = next; } // promise is the root of the promise tree. switch (promise._state) { case State.Pending: { progressListener.SetInitialProgress(promise.CurrentProgress()); break; } case State.Resolved: { progressListener.SetInitialProgress(promise._waitDepthAndProgress.GetIncrementedWholeTruncated()); break; } default: // Rejected or Canceled: { progressListener.Retain(); progressListener.CancelOrSetProgress(promise, promise._waitDepthAndProgress); break; } } }
protected void SubscribeProgress <TCapture>(TCapture capturedValue, Action <TCapture, float> onProgress, CancelationToken cancelationToken) { ValidateOperation(this, 2); ValidateArgument(onProgress, "onProgress", 2); if (_state == State.Pending) { InternalProtected.IProgressListener progressListener = InternalProtected.ProgressDelegateCapture <TCapture> .GetOrCreate(capturedValue, onProgress, this, cancelationToken); // Directly add to listeners for this promise. // Sets promise to the one this is waiting on. Returns false if not waiting on another promise. Promise promise; if (!SubscribeProgressAndContinueLoop(ref progressListener, out promise)) { // This is the root of the promise tree. progressListener.SetInitialProgress(_waitDepthAndProgress); return; } SubscribeProgressToBranchesAndRoots(promise, progressListener); } else if (_state == State.Resolved) { Internal.AddToHandleQueueBack(InternalProtected.ProgressDelegateCapture <TCapture> .GetOrCreate(capturedValue, onProgress, this)); } // Don't report progress if the promise is canceled or rejected. }
private static void SubscribeProgressToBranchesAndRoots(Promise promise, InternalProtected.IProgressListener progressListener) { // This allows us to subscribe progress to AllPromises and RacePromises iteratively instead of recursively ValueLinkedStack <InternalProtected.PromisePassThrough> passThroughs = new ValueLinkedStack <InternalProtected.PromisePassThrough>(); Repeat: SubscribeProgressToChain(promise, progressListener, ref passThroughs); if (passThroughs.IsNotEmpty) { // passThroughs are removed from their targets before adding to passThroughs. Add them back here. var passThrough = passThroughs.Pop(); promise = passThrough.Owner; progressListener = passThrough; passThrough.Target.ReAdd(passThrough); goto Repeat; } }
protected virtual bool SubscribeProgressIfWaiterAndContinueLoop(ref InternalProtected.IProgressListener progressListener, out Promise previous, ref ValueLinkedStack <InternalProtected.PromisePassThrough> passThroughs) { return((previous = _valueOrPrevious as Promise) != null); }
protected virtual bool SubscribeProgressAndContinueLoop(ref InternalProtected.IProgressListener progressListener, out Promise previous) { progressListener.Retain(); _progressListeners.Push(progressListener); return((previous = _valueOrPrevious as Promise) != null); }