Skip to content

Instantly share code, notes, and snippets.

@E-K
Last active April 23, 2021 19:50
Show Gist options
  • Save E-K/20ae876494b1dcf7d6c5e5e34a065474 to your computer and use it in GitHub Desktop.
Save E-K/20ae876494b1dcf7d6c5e5e34a065474 to your computer and use it in GitHub Desktop.
CoroutineRunner
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