< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
StartThrowingCoroutine(...)0%110100%
RunThrowingIterator()0%660100%
WaitForAllIEnumerators()0%30500%

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        {
 42129            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.
 42151            var stack = new Stack<IEnumerator>();
 42152            stack.Push(enumerator);
 53
 2413654            while (stack.Count > 0)
 55            {
 56                // any inner enumerator will be at the top of the stack
 57                // otherwise the original one
 2373058                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                {
 2373065                    if (currentEnumerator.MoveNext() == false)
 66                    {
 67                        // in this case, the enumerator has finished
 964368                        stack.Pop();
 69                        // if the stack is empty, then everything has finished,
 70                        // and the while (stack.Count &gt; 0) will pick it up
 964371                        continue;
 72                    }
 73
 1408574                    currentYieldedObject = currentEnumerator.Current;
 1408575                }
 276                catch (Exception ex)
 77                {
 78                    // this part is the whole point of this method!
 279                    done(ex);
 280                    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
 1408586                if (currentYieldedObject is IEnumerator)
 87                {
 930288                    stack.Push(currentYieldedObject as IEnumerator);
 930289                }
 90                else
 91                {
 478392                    yield return currentYieldedObject;
 93                }
 94            }
 40695        }
 96
 97        public static IEnumerator WaitForAllIEnumerators(params IEnumerator[] coroutines)
 98        {
 099            List<Coroutine> coroutineGroup = new List<Coroutine>();
 0100            for (int i = 0; i < coroutines.Length; i++)
 101            {
 0102                coroutineGroup.Add(CoroutineStarter.Start(coroutines[i]));
 103            }
 104
 0105            int coroutineGroupCount = coroutineGroup.Count;
 0106            for (int index = 0; index < coroutineGroupCount; index++)
 107            {
 0108                var coroutine = coroutineGroup[index];
 0109                yield return coroutine;
 110            }
 0111        }
 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
 121        public WaitUntil(Func<bool> predicate, float? timeoutInSeconds = null)
 122        {
 123            this.predicate = predicate;
 124
 125            if (timeoutInSeconds.HasValue)
 126            {
 127                waitEnabled = true;
 128                waitTime = Time.realtimeSinceStartup + timeoutInSeconds.Value;
 129            }
 130        }
 131
 132        public override bool keepWaiting
 133        {
 134            get
 135            {
 136                if (waitEnabled)
 137                    return !predicate() && Time.realtimeSinceStartup < waitTime;
 138                else
 139                    return !predicate();
 140            }
 141        }
 142    }
 143}