< Summary

Class:DCL.WaitUntil
Assembly:CoroutineHelpers
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Helpers/CoroutineHelpers/CoroutineHelpers.cs
Covered lines:9
Uncovered lines:0
Coverable lines:9
Total lines:143
Line coverage:100% (9 of 9)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
WaitUntil(...)0%220100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Helpers/CoroutineHelpers/CoroutineHelpers.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using UnityEngine;
 5
 6namespace DCL
 7{
 8    /// <summary>
 9    /// Utility functions to handle exceptions thrown from coroutine and iterator functions
 10    /// http://JacksonDunstan.com/articles/3718
 11    /// </summary>
 12    public static class CoroutineHelpers
 13    {
 14        /// <summary>
 15        /// Start a coroutine that might throw an exception. Call the callback with the exception if it
 16        /// does or null if it finishes without throwing an exception.
 17        /// </summary>
 18        /// <param name="monoBehaviour">MonoBehaviour to start the coroutine on</param>
 19        /// <param name="enumerator">Iterator function to run as the coroutine</param>
 20        /// <param name="done">Callback to call when the coroutine has thrown an exception or finished.
 21        /// The thrown exception or null is passed as the parameter.</param>
 22        /// <returns>The started coroutine</returns>
 23        public static Coroutine StartThrowingCoroutine(
 24            this MonoBehaviour monoBehaviour,
 25            IEnumerator enumerator,
 26            Action<Exception> done
 27        )
 28        {
 29            return CoroutineStarter.Start(RunThrowingIterator(enumerator, done));
 30        }
 31
 32        /// <summary>
 33        /// Run an iterator function that might throw an exception. Call the callback with the exception
 34        /// if it does or null if it finishes without throwing an exception.
 35        /// </summary>
 36        /// <param name="enumerator">Iterator function to run</param>
 37        /// <param name="done">Callback to call when the iterator has thrown an exception or finished.
 38        /// The thrown exception or null is passed as the parameter.</param>
 39        /// <returns>An enumerator that runs the given enumerator</returns>
 40        public static IEnumerator RunThrowingIterator(
 41            IEnumerator enumerator,
 42            Action<Exception> done
 43        )
 44        {
 45            // The enumerator might yield return enumerators, in which case
 46            // we need to enumerate those here rather than yield-returning
 47            // them. Otherwise, any exceptions thrown by those "inner enumerators"
 48            // would actually escape to an outer level of iteration, outside this
 49            // code here, and not be passed to the done callback.
 50            // So, this stack holds any inner enumerators.
 51            var stack = new Stack<IEnumerator>();
 52            stack.Push(enumerator);
 53
 54            while (stack.Count > 0)
 55            {
 56                // any inner enumerator will be at the top of the stack
 57                // otherwise the original one
 58                var currentEnumerator = stack.Peek();
 59                // this is what get "yield returned" in the work enumerator
 60                object currentYieldedObject;
 61                // the contents of this try block run the work enumerator until
 62                // it gets to a yield return statement
 63                try
 64                {
 65                    if (currentEnumerator.MoveNext() == false)
 66                    {
 67                        // in this case, the enumerator has finished
 68                        stack.Pop();
 69                        // if the stack is empty, then everything has finished,
 70                        // and the while (stack.Count &gt; 0) will pick it up
 71                        continue;
 72                    }
 73
 74                    currentYieldedObject = currentEnumerator.Current;
 75                }
 76                catch (Exception ex)
 77                {
 78                    // this part is the whole point of this method!
 79                    done(ex);
 80                    yield break;
 81                }
 82
 83                // in unity you can yield return whatever the hell you want,
 84                // so this will pick up whether it's something to enumerate
 85                // here, or pass through by yield returning it
 86                if (currentYieldedObject is IEnumerator)
 87                {
 88                    stack.Push(currentYieldedObject as IEnumerator);
 89                }
 90                else
 91                {
 92                    yield return currentYieldedObject;
 93                }
 94            }
 95        }
 96
 97        public static IEnumerator WaitForAllIEnumerators(params IEnumerator[] coroutines)
 98        {
 99            List<Coroutine> coroutineGroup = new List<Coroutine>();
 100            for (int i = 0; i < coroutines.Length; i++)
 101            {
 102                coroutineGroup.Add(CoroutineStarter.Start(coroutines[i]));
 103            }
 104
 105            int coroutineGroupCount = coroutineGroup.Count;
 106            for (int index = 0; index < coroutineGroupCount; index++)
 107            {
 108                var coroutine = coroutineGroup[index];
 109                yield return coroutine;
 110            }
 111        }
 112    }
 113
 114    // Suspends the coroutine execution until the supplied delegate evaluates to true or the timeout is reached.
 115    public class WaitUntil : CustomYieldInstruction
 116    {
 117        Func<bool> predicate;
 118        float waitTime;
 119        bool waitEnabled = false;
 120
 559121        public WaitUntil(Func<bool> predicate, float? timeoutInSeconds = null)
 122        {
 559123            this.predicate = predicate;
 124
 559125            if (timeoutInSeconds.HasValue)
 126            {
 97127                waitEnabled = true;
 97128                waitTime = Time.realtimeSinceStartup + timeoutInSeconds.Value;
 129            }
 559130        }
 131
 132        public override bool keepWaiting
 133        {
 134            get
 135            {
 22178136                if (waitEnabled)
 1717137                    return !predicate() && Time.realtimeSinceStartup < waitTime;
 138                else
 20461139                    return !predicate();
 140            }
 141        }
 142    }
 143}