Last active
April 23, 2021 19:50
-
-
Save E-K/20ae876494b1dcf7d6c5e5e34a065474 to your computer and use it in GitHub Desktop.
CoroutineRunner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Runtime.ExceptionServices; | |
using System.Threading.Tasks; | |
using UnityEngine; | |
namespace Core.Concurrent | |
{ | |
public class CoroutineRunner | |
{ | |
private readonly Stack<object> _stack; | |
private ExceptionDispatchInfo _exception; | |
public CoroutineRunner() | |
{ | |
_stack = new Stack<object>(); | |
} | |
public void Start(System.Collections.IEnumerator enumerator) | |
{ | |
if (enumerator is null) throw new ArgumentNullException(nameof(enumerator)); | |
if (_stack.Count > 0) throw new ArgumentException(nameof(_stack)); //完了まではこのRunner上ではStartできない | |
_exception = null; | |
_stack.Push(enumerator); | |
} | |
/// <summary> | |
/// コルーチンを1フレーム回します | |
/// 実行するものがない、または実行完了時にfalseを返します | |
/// </summary> | |
public bool Update() | |
{ | |
if (_stack.Count <= 0) return false; | |
var item = _stack.Peek(); | |
if (!UpdateItem(item)) | |
{ | |
_stack.Pop(); | |
} | |
if (_exception != null) | |
{ | |
var ex = _exception; | |
_exception = null; | |
_stack.Clear(); | |
ex.Throw(); | |
} | |
return _stack.Count > 0; | |
} | |
private bool UpdateItem(object item) | |
{ | |
if (item is System.Collections.IEnumerator enumerator) | |
{ | |
return UpdateEnumerator(enumerator); | |
} | |
else if (item is Task task) | |
{ | |
return CheckTaskComplete(task); | |
} | |
else if(item is AsyncOperation asyncOp) | |
{ | |
return CheckAsyncOperationComplete(asyncOp); | |
} | |
throw new InvalidOperationException("stackに積めない型"); | |
} | |
private bool UpdateEnumerator(System.Collections.IEnumerator enumerator) | |
{ | |
bool moveNext = false; | |
try | |
{ | |
moveNext = enumerator.MoveNext(); | |
} | |
catch (Exception ex) | |
{ | |
_exception = ExceptionDispatchInfo.Capture(ex); | |
} | |
if (!moveNext) | |
{ | |
//例外発生時もこちら | |
//enumerator.Reset(); | |
if (enumerator is IDisposable disposable) | |
disposable.Dispose(); | |
return false; | |
} | |
var current = enumerator.Current; | |
if (current is System.Collections.IEnumerator || current is Task || current is AsyncOperation) | |
_stack.Push(current); | |
return true; | |
} | |
private bool CheckTaskComplete(Task task) | |
{ | |
if (task.IsFaulted) | |
_exception = ExceptionDispatchInfo.Capture(task.Exception); | |
return !task.IsCompleted; | |
} | |
private bool CheckAsyncOperationComplete(AsyncOperation asyncOp) | |
{ | |
return !asyncOp.isDone; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment