using System; using System.Collections; using System.Collections.Generic; #if (NET_4_6 && UNITY_2017_1_OR_NEWER) using System.Threading.Tasks; #endif namespace UniTask { public interface ISchedulable { /// 実行が終了したか?Coroutineの実行が一回で終わらない場合がある ExecutionStatus Execute(); Exception GetError(); IScheduler Schedulder { get; } ISchedulable Parent { get; set; } void AddChild(ISchedulable child); IEnumerable Traverse(); } public static class ISchedulableExtensions { public static ISchedulable GetRoot(this ISchedulable self) { var current = self; while (current.Parent != null) { current = current.Parent; } return current; } } public class Schedulable : ISchedulable { List m_children = new List(); public void AddChild(ISchedulable child) { child.Parent = this; m_children.Add(child); } public IEnumerable Traverse() { yield return this; foreach (var child in m_children) { foreach (var x in child.Traverse()) { yield return x; } } } public ISchedulable Parent { get; set; } public IScheduler Schedulder { get; private set; } public IFunctor Func { get; private set; } public Exception GetError() { return Func.GetError(); } public Schedulable() { } public Schedulable(IScheduler scheduler, IFunctor func) { Schedulder = scheduler; Func = func; } public ExecutionStatus Execute() { if (Func == null) { return ExecutionStatus.Done; } return Func.Execute(); } public Schedulable AddTask(IScheduler scheduler, Action pred) { return AddTask(scheduler, () => { pred(); return Unit.Default; }); } public Schedulable AddTask(IScheduler scheduler, Func pred) { var schedulable = new Schedulable(scheduler, Functor.Create(() => Unit.Default, _ => pred())); AddChild(schedulable); return schedulable; } public Schedulable AddCoroutine(IScheduler scheduler, Func starter) { var func = CoroutineFunctor.Create(() => default(T), _ => starter()); var schedulable = new Schedulable(scheduler, func); AddChild(schedulable); return schedulable; } public Schedulable ContinueWith(IScheduler scheduler, Action pred) { return ContinueWith(scheduler, t => { pred(t); return Unit.Default; }); } public Schedulable ContinueWith(IScheduler scheduler, Func pred) { Func getResult = null; if (Func != null) { getResult = Func.GetResult; } var func = Functor.Create(getResult, pred); var schedulable = new Schedulable(scheduler, func); Parent.AddChild(schedulable); return schedulable; } public Schedulable ContinueWithCoroutine(IScheduler scheduler, Func starter) { var func = CoroutineFunctor.Create(() => default(T), _ => starter()); var schedulable = new Schedulable(scheduler, func); Parent.AddChild(schedulable); return schedulable; } public Schedulable OnExecute(IScheduler scheduler, Action> pred) { Func getResult = null; if (Func != null) { getResult = Func.GetResult; } var schedulable = new Schedulable(); schedulable.Func = Functor.Create(getResult, _ => { pred(schedulable); return Unit.Default; }); Parent.AddChild(schedulable); return schedulable; } /* public ISchedulable ContinueWithNested(Func> starter, IScheduler scheduler) { var func = SchedulableFunctor.Create(() => starter(Func.GetResult())); return new Schedulable(scheduler, func, this); } */ } public static class Schedulable { public static Schedulable Create() { return new Schedulable(); } } public static class SchedulableExtensions { public static void Subscribe( this Schedulable schedulable, IScheduler scheduler, Action onCompleted, Action onError) { schedulable.ContinueWith(scheduler, onCompleted); TaskChain.Schedule(schedulable.GetRoot(), onError); } #if (NET_4_6 && UNITY_2017_1_OR_NEWER) public static Task ToTask(this Schedulable schedulable) { return ToTask(schedulable, Scheduler.MainThread); } public static Task ToTask(this Schedulable schedulable, IScheduler scheduler) { var tcs = new TaskCompletionSource(); schedulable.Subscribe(scheduler, r => tcs.TrySetResult(r), ex => tcs.TrySetException(ex)); return tcs.Task; } #endif /* public static ISchedulable Sequencial(IEnumerable> schedulables, Action mergePred) { var it = schedulables.GetEnumerator(); ISchedulable last = Schedulable.Start(null, () => Unit.Default); while (it.MoveNext()) { var current = it.Current; var merger = current.ContinueWith(result => { mergePred(result); return Unit.Default; }); if (last != null) { // 連結 current.EnumParents().Last().Parent = last; } last = merger; } return last; } */ /* public static ISchedulable MergeCollection(this ISchedulable schedulable, Func> extractor, Func pred, Action merger, IScheduler scheduler = null) { return schedulable.ContinueWithNested(x => { var schedulables = extractor(x).Select(y => Schedulable.Start(scheduler, () => pred(x, y))); return Sequencial(schedulables, z => merger(x, z)).ContinueWith(_ => x); }, scheduler); } */ } }